enhancedchannelmanager
CLAUDE.md89 starsChanged 4 months agoCC0-1.0View on GitHub
Before reading code, editing files, or exploring the codebase for ANY code task: The first positional arg is the title, not the repo. Repo is auto-routed from .beads/. Don't pass enhancedchannelmanager as the title — that's the most common foot-gun. No exceptions. No "I'll do it later." The bead comes before the first Read, Grep, or Edit. After the work is deployed and verified, close it: bd close <bead-id> When work ships, it doesn't just close the bead it was…
- Deletes or force-pushes
- Installs packages
- Commits and pushes
In this repository3 other files it gives its agents.
- AGENTS.mdAGENTS.md
- backend/CLAUDE.mdCLAUDE.md
- frontend/CLAUDE.mdCLAUDE.md
The file
We split this CLAUDE.md into the rules it gives an agent
11 rules. About 0 are common, 4 are distinctive, and 7 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
7
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Distinctive: line 5
Before reading code, editing files, or exploring the codebase for ANY code task:
- Very specific: line 18
No exceptions. No "I'll do it later." The bead comes before the first Read, Grep, or Edit.
- Very specific: line 19
After the work is deployed and verified, close it: bd close <bead-id>
- Very specific: line 134
Rebuild the graph: only if (1) and (2) don't cover it: /graphify backend frontend docs.
- Very specific: line 166
Always clean /app/static/assets/ before copying — docker cp only adds files, never removes stale bundles.
- Distinctive: line 175
Coupled backend/frontend changes: When a frontend build depends on a new or changed backend route, deploy the backend first and wait for …
- Very specific: line 207
Python packages: use uv (not pip): docker exec ecm-ecm-1 uv pip install <package>
- Very specific: line 211
Follow docs/shipping.md. The full PR-driven flow (branch from origin/dev, push, open PR via gh pr create --base dev, wait for the 5 …
- Very specific: line 213
Run gh pr create from the checkout being shipped.
- Distinctive: line 217
NEVER stop before the PR is merged — an open PR is not a shipped change
- Distinctive: line 218
NEVER say "ready to merge when you are" — YOU must drive the merge once the required checks are green
≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Agent Instructions
STOP — Read Beads, Then Create a Bead
Before reading code, editing files, or exploring the codebase for ANY code task:
- Read existing beads for context on past work:
bd list --status closed bd ready - Create a bead for the current task:
The first positional arg is the title, not the repo. Repo is auto-routed frombd create "Brief title" --description "Why this exists and what needs to be done".beads/. Don't passenhancedchannelmanageras the title — that's the most common foot-gun.
No exceptions. No "I'll do it later." The bead comes before the first Read, Grep, or Edit.
After the work is deployed and verified, close it: bd close <bead-id>
Beads Quick Reference
bd ready # Find available work
bd show <id> # View issue details
bd update <id> --status in_progress # Claim work
bd close <id> # Complete work
bd list --status closed # View closed beads for context
bd sync # Sync beads data only (NOT for code commits)- Beads auto-route to this repo via
.beads/. If you ever need to override (e.g., creating a bead targeting a different rig), use--repo enhancedchannelmanager. - NEVER chain
bd createandbd close— run them as separate commands - The
.git/beads-worktrees/devworktree is only for beads issue tracking (sparse checkout of.beads/only — no code files). Do NOT edit code there.
Close Every Bead Your Work Fulfills
When work ships, it doesn't just close the bead it was filed under. Check whether it also fulfills other beads, and close those too, naming them and the evidence in the close reason. Watch for three patterns especially: children of an epic when the epic's work ships, sibling beads absorbed by a broader fix, and beads whose premise a refactor removes.
A 2026-08-12 validity audit of all 194 open beads closed 44 of them, almost all already-shipped work that had simply never been closed. All 14 children of epic gsnw0 sat open for weeks after one commit fulfilled them against the parent only. t4d5w's own CHANGELOG entry says it absorbs bead pb2s4; pb2s4 stayed open. dfkbn, a P1, was declared closed in CHANGELOG prose but never closed in beads. Three siblings (2896r.16, 2896r.17, 70u0r) were all described by one CHANGELOG entry and all stayed open. Net effect: the backlog overstated remaining work by roughly 17 percent, and it produced a real planning error, sequencing a batch around a docs-CI chain that had already shipped.
Verification Discipline: Check the Thing, Not a Proxy
Four rules from a 2026-08-13 error retro (~/retros/2026-08-13-19_(project-d-proxy-not-referent).md). Twelve errors that session, and every judgment error among them was one substitution: checking something adjacent to the claim, then reporting the claim.
1. Smoke-test every instrument before you trust it. Run any monitor, watch loop, or external-tool invocation against a known-good AND a known-bad input before arming it. Silence from a broken instrument is indistinguishable from silence from a healthy system, so this class of failure conceals itself. Four monitors failed this way in one session: a gh pr checks --json flag that does not exist (30 minutes of confident silence while the checks had already finished); a || echo '[]' fallback that turned every error into "no results"; a [0] index on a branch-filtered API listing assumed to be newest-first, which reported on a six-week-old commit; and a 5-minute timeout on a ~15-minute publish. A codex exec call passed the prompt as an argument and piped stdin, so it blocked, did nothing, and exited 0. That exit status was very nearly read as "reviewed, no findings."
2. Report the check you ran, not the conclusion you drew. Say "grepped seven across docs/", not "verified". If the reporting sentence is broader than the command, the command was too narrow, and that gap is invisible to the PO, who calibrates trust on the phrasing. A docs sweep for a stale required-check count grepped the word "seven", reported "none remain", and missed three files using the numeral 7. scripts/check_publish.py:573 already encodes this rule for the publish gate ("Claim only what actually ran"); it generalizes.
3. Never assert a handoff without opening the target. Closing bead A because bead B covers it requires reading B. rnzu0 was closed on the claim its fix "rides with hmr0e"; hmr0e is about removing an M3U Manager link and covered none of it. Four stale e2e assertions stayed live and the bead had to be reopened. The same rule covers "already fixed": mechanism absent from current code is not defect fixed, and the difference decides whether it can return.
4. Your own verification is not exempt from verification. The rules above about agent-reported gates and shared-resource control apply to your own greps and closures too. The asymmetry is invisible from the inside: you cannot feel the difference between "I checked" and "I checked something adjacent". Two demonstrations from the retro session itself, both caught only by looking at the thing: an audit-closure count quoted from a same-day close total (46) when the real figure was 44, and a "TLS route with no auth dependency" that was an artifact of a 4-line awk window with the dependency on line 5. Prefer external adversarial review (Codex, a persona-reviewer agent) on your own judgment (closures, "verified" claims, recommendations), not only on the code. Hand the reviewer the repository, not a curated file list: curating backend routers only once produced a confident, wrong conclusion that the MCP tools did not exist. A mitigation phrased as an intention ("avoid biasing by omission") is not a mitigation.
Invoking Personas (project-engineer, qa-engineer, sre, etc.)
Personas are skills at ~/.claude/skills/<persona>/SKILL.md, NOT subagent types. To spawn them — especially in parallel — use the Agent tool with subagent_type: "general-purpose" and load the persona identity in the prompt:
Read ~/.claude/skills/<persona>/SKILL.md for your domain scope.
Read ~/.claude/skills/<persona>/identity.md (if present).
Read ~/.claude/skills/_shared/engineering-discipline.md.
You are the <Persona>. <question/task>The canonical pattern is documented in ~/.claude/skills/spike/SKILL.md (Step 3). Do NOT try subagent_type: "project-engineer" — the registered subagent types are only general-purpose, Explore, Plan, claude-code-guide, statusline-setup.
For multi-persona workflows (team-plan, team-review, spike, grooming, standup, retro, onboard), invoke the orchestrating skill via the Skill tool — it handles the fan-out itself.
Worktree & Agent Isolation (this environment)
The Claude Code worktree mechanism is unreliable here. Three harness-level bugs, NOT fixable in-repo (see bd-j8osn; the third is enhancedchannelmanager-2lwz3):
- cwd-trap: a worktree-spawned agent's Bash cwd resets to the MAIN checkout between calls, while Read/Edit act on the literal absolute path given. An agent that doesn't make EVERY path worktree-absolute ends up editing
devdirectly — silently polluting the main checkout. - Lock accumulation: a finished agent's worktree stays locked and is never auto-cleaned;
git worktree removethen needs-f -f. Stale-base: a worktree is branched from
origin/main, notdev, unless a start point is given explicitly.origin/mainis the repo's default branch, so this is the silent default, not an edge case. Measured 2026-08-12: a worktree agent's branch reflog readCreated from origin/mainatae25ad70(PR #748, 2026-07-26), whiledevwas 858 files and roughly 141k lines ahead ateecd257a. The agent's brief named a symbol added ondevby a later PR; that symbol did not exist on the worktree's base, and the agent only caught it mid-task. Nothing about this looks wrong from the outside:git statusis clean, gates pass, and the diff against the worktree's own (stale) base looks small and correct. An agent that doesn't notice ships a branch written against an old API surface: the code it targeted has moved, so part of its fix can be missing or wrong, its gates passed against a tree that is not the one it will land in, and its conflicts are likelier and easy to mis-resolve toward the stale side.The merge itself does NOT revert
dev. An earlier version of this bullet said it "reverts everythingdevgained since the stale base"; that is wrong. A three-way merge takes the stale commit as its merge base and keeps dev-only work on dev's side. That was verified empirically in a throwaway repo: branch from an old commit, advance the target four commits, then merge, and all target-side work and files survive. The damage is a quietly incomplete fix plus meaningless gate results, not mass reversion, and the distinction matters because it changes the remediation. Standing rule 4 below is unaffected: verify the merge-base regardless. Full evidence in enhancedchannelmanager-2lwz3.
Standing defaults (these OVERRIDE the global "worktree-isolate every write agent" rule, which assumes a working mechanism):
- Default: non-worktree, sequential engineers. For typical small / single-domain changes, spawn the engineer WITHOUT
isolation: "worktree"and brief it to work on a branch in the main checkout (do NOT create a worktree). No second tree ⇒ no cwd-trap, nothing left locked. - Worktrees only for genuinely parallel, independent write agents. When used: brief the cwd-trap hard (every Read/Edit/Bash path worktree-absolute; verify
git -C <wt> branch --show-currentbefore any commit), and on return verify each agent's gates AND that the main checkout is clean (git statusshows none of the agent's files). - Clean up on merge, every time.
git worktree remove -f -f <path>is part of the PR-merge step — never defer to a later sweep. Skip and flag any worktree with uncommitted tracked changes instead of force-removing it. - First action in every worktree agent: verify the base, then rebase onto
origin/dev. Before any other work, comparegit -C <worktree> merge-base HEAD origin/devagainstgit rev-parse origin/dev. These agreeing is the pass condition; if they disagree, the worktree is stale and must be rebased ontoorigin/devbefore the brief's actual task starts. - Trust nothing unverified. Independently re-run the agent's claimed gates before merging, AND independently re-verify the branch's merge-base against
origin/devbefore merging: gates passing on a stale base proves nothing about the merge.
Frontend tooling in a worktree (writable .vite-temp) is fixed in scripts/worktree-bootstrap.sh; full caveats in docs/shipping.md → "Worktree quirks".
Sizing Vocabulary — No Calendar Estimates
Size work as Small / Medium / Large / Epic — needs decomposition (per ~/.claude/skills/grooming/SKILL.md). Do NOT give the PO calendar estimates in hours/days/weeks/months. Calendar estimates invite commitment theater and are almost always wrong.
Exception — governance cadence rules from ADRs (e.g., ADR-005's monthly-then-quarterly audit cadence) are project-defined constraints and can be quoted verbatim. Do not multiply them out into wall-time estimates. Quote the rule; let the PO do the arithmetic if they want it.
Reference Guides
| Guide | Location |
| Architecture Diagram | docs/architecture.md |
| Auth Middleware | docs/auth_middleware.md |
| Backend Architecture | docs/backend_architecture.md |
| Database Migrations | docs/database_migrations.md |
| Pytest Conventions | docs/pytest_conventions.md |
| Project Architecture | docs/project_architecture.md |
| Runbooks | docs/runbooks/ |
| Style Guide (canonical) | docs/style_guide.md |
| CSS Guidelines | docs/css_guidelines.md |
| Beads (Issue Tracking) | ~/.claude/projects/<project-slug>/memory/beads.md |
| Dispatcharr API | docs/dispatcharr_api.md |
| Discord Release Notes | docs/discord_release_notes.md |
| Frontend Lint Policy | docs/frontend_lint.md |
| Testing Details | docs/testing.md |
| Shipping Workflow | docs/shipping.md |
| Dummy EPG Template Engine | docs/template_engine.md |
| DBAS Import Threat Model | docs/security/threat_model_dbas_import.md |
| CodeQL Configuration | docs/security/codeql-config.md |
| Normalization (user + dev guide) | docs/normalization.md |
| Channel Pipeline Rule Analyzer | docs/channel_pipeline_rule_analyzer.md |
| Event Sync (user + dev guide) | docs/event_sync.md |
| Versioning Scheme | docs/versioning.md |
| API Reference | docs/api.md |
| SLOs | docs/sre/slos.md |
| User Guide (operator-facing) | docs/user_guide/ |
| Graphify findings (past traces) | graphify-out/memory/*.md |
| Graph audit report | graphify-out/GRAPH_REPORT.md |
Architecture Questions
For codebase-architecture questions (how X connects to Y, what a component's role is, where the hot path runs), the order of precedence is:
docs/architecture.md— the hand-curated system overview + Channel Pipeline internals + MCP + external API contract.graphify-out/memory/*.md— saved Q&A from past graph traces. Each file is one question + answer. Greppable. Cheap to read.- Rebuild the graph only if (1) and (2) don't cover it:
/graphify backend frontend docs. Then query viagraphify query "..."/graphify explain "NodeName"/graphify path "A" "B".
The raw graph.json and cross-repo-graph.json files are gitignored (large, machine-local paths). Rebuild on demand.
For coding conventions (naming, module organization, comments, error
handling, regex, CSS, lint, tests), docs/style_guide.md is the canonical
reference. Other guides in this table cover their own subject (CSS shared
classes, lint per-rule patterns, etc.) and are cited from the style guide
where they remain authoritative.
Development Workflow
Always work from the dev branch. Container name: ecm-ecm-1
Container-First Development
Edit code locally, deploy to container, iterate. Do NOT commit until told to "ship the fix."
docker cp <local-file> ecm-ecm-1:/app/<destination-path>Frontend deploy:
scripts/deploy-frontend.sh # build + clean stale assets + copy, in one stepThe script bakes in the stale-asset cleanup below so it can't be skipped. Equivalent manual sequence (use --no-build to skip the rebuild):
cd frontend && npm run build
docker exec ecm-ecm-1 sh -c 'rm -rf /app/static/assets/*'
docker cp dist/. ecm-ecm-1:/app/static/Always clean /app/static/assets/ before copying — docker cp only adds files, never removes stale bundles. Set ECM_CONTAINER to target a container other than ecm-ecm-1.
Backend deploy (to /app/, NOT /app/backend/):
docker cp backend/main.py ecm-ecm-1:/app/main.py
docker cp backend/routers/. ecm-ecm-1:/app/routers/
docker restart ecm-ecm-1Coupled backend/frontend changes: When a frontend build depends on a new or changed backend route, deploy the backend first and wait for its restart to complete before deploying the frontend:
docker cp backend/main.py ecm-ecm-1:/app/main.py
docker cp backend/routers/. ecm-ecm-1:/app/routers/
docker restart ecm-ecm-1
ready=0
for attempt in $(seq 1 30); do
if docker exec ecm-ecm-1 python -c "import os, urllib.request; port = os.environ.get('ECM_PORT', '6100'); urllib.request.urlopen(f'http://localhost:{port}/api/health/ready', timeout=2)" >/dev/null 2>&1; then
ready=1
break
fi
sleep 1
done
if [ "$ready" -ne 1 ]; then
echo "ECM backend did not become ready; frontend was not deployed" >&2
docker logs --tail 100 ecm-ecm-1 >&2
exit 1
fi
scripts/deploy-frontend.shThis order prevents the new frontend from calling an API contract that the
running backend does not yet provide. The readiness loop is bounded to 30
attempts with a two-second request timeout; /api/health/ready is public, so
the in-container probe needs no credentials. Roll back in reverse dependency order:
restore and deploy the previous frontend build first, then restore the previous
backend files and restart ecm-ecm-1. Do not roll back the backend while the
dependent frontend is still live.
Python packages use uv (not pip): docker exec ecm-ecm-1 uv pip install <package>
Shipping (When User Says "Ship the Fix")
Follow docs/shipping.md. The full PR-driven flow (branch from origin/dev, push, open PR via gh pr create --base dev, wait for the 5 required checks, then gh pr merge --merge --delete-branch) lives in docs/shipping.md §6 — do not duplicate it here.
Run gh pr create from the checkout being shipped. The local preflight hook resolves the session cwd before Bash runs and cannot follow an inline cd <other-checkout> && gh pr create ...; that form is unsupported. Remove the branch worktree and check the branch out in the main checkout before opening its PR.
Non-negotiable rules:
- Work is NOT complete until the PR merges into
dev - NEVER stop before the PR is merged — an open PR is not a shipped change
- NEVER say "ready to merge when you are" — YOU must drive the merge once the required checks are green
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

