# Common rules for every release implementer (one-core, release 5 onward) You are one Opus implementer for ONE slice of one release in the repo `yt-dlp-transcript-browser`. You work in your OWN git worktree (path given in the slice prompt), on your own branch, with your own port block (`pnpm wt list` from the primary shows it). Other implementers work in sibling worktrees at the same time on files that do not overlap yours; the shared files are only `editor/CHANGELOG.md` and the release's record file (named in the prompt). Read `AGENTS.md` (the repo's instructions) FIRST, then `plans/STATE.md` and `plans/FACTS.md` (verified facts, trust them over re-deriving), then the previous release's "as shipped" records (the prompt names them) — your record must have the same shape. `node_modules/next/dist/docs/` is the Next.js reference for this version. ## Non-negotiables - **Scratch dir:** the job's `$CLAUDE_JOB_DIR/tmp` (`$T`, path in the prompt). Never `/tmp`. Prefix your files with your slice letter. - **Detached, then waited on in short foreground loops — never polled with `run_in_background`, never parked on a Monitor.** Anything over a minute (builds, e2e, numbers tools) is launched `setsid nohup sh script.sh > $T/.log 2>&1 < /dev/null &` with the script ending in `echo exit=$?`. Then wait INSIDE foreground Bash calls of at most ~100 s each: `for i in $(seq 1 18); do grep -q 'exit=' $T/.log && break; sleep 5; done; tail -3 $T/.log` — repeat the call until `exit=` appears. A subagent parked on the `Monitor` tool is never woken (Monitor is for the parent session only), and `run_in_background` is killed at ~2 min here. If your session is cut and resumed, re-read the logs and continue from where the logs say you are — never redo a run whose result is on disk. - **e2e is queued machine-wide** (`AGENTS.md`): `pnpm e2e` from YOUR WORKTREE ROOT waits for the lock (`waiting for the e2e queue — held by …` is normal; another suite can hold it ~25–36 min). Before launching, check no orphan holds your worktree's ports (`ss -ltnp | grep :`). Write the exact spec list to a file and pass it: `pnpm e2e $(cat $T/-specs.txt)` — from the worktree root, which runs the EDITOR suite; a spec name that does not exist is dropped and recorded. The EXPORT suite is `node scripts/worktree.mjs run -- pnpm --filter export run e2e` (also from the worktree root, also queued). Record `N passed, M failed, time` from the log for every run. - **Worktree e2e needs `export/public`:** the gitignored entries under `export/public` must be symlinked from the primary checkout per path (under `sh`, not fish/zsh): `for p in $(git -C /home/user/Projects/yt-dlp-transcript-browser/export status --ignored --short public | awk '{print $2}'); do p=${p%/}; ln -sfn "/home/user/Projects/yt-dlp-transcript-browser/export/$p" "/export/$p"; done` — check for dangling links (`find /export/public -xtype l`) before every export build or export-related e2e, because the live editor's build-deploy job regenerates the primary's. - **Export build gate is `pnpm --filter export exec next build`** — NOT `run build`, which runs `build:data` into a worktree-local `transcripts/`. - **Homepage build gate is `pnpm --filter homepage run build:nodata`** (or `exec next build`) — NEVER `run build`: its `prebuild` runs `archilyzer index` and `compose homepage` against whatever `transcripts/` is visible. With the primary's corpus linked in for a capped build (the umtool rule below), `run build` is an index build against the real corpus (release 13 W2's catch-up, 2026-09-30: three minutes, two records rewritten by identical code, stopped). The corpus link is for `next build` only; never run a package's `build` script, a `prebuild` hook, an index or a fixture builder with it. - **tsc per commit:** `pnpm -r --no-bail --workspace-concurrency=1 exec tsc --noEmit` from the worktree root must be clean before every commit (worktrees have no stale `.next/dev/types`). - **Never boot a second editor against the real corpus.** Your worktree's e2e uses its own fixture; never point anything at `/transcripts` except the read-only numbers tools, which copy to scratch. Never hand-edit `transcripts/**`. Never restart the live :3001 editor. - **Never stage** `settings.json.pre-priority-*` or anything under `test-results/`. - **Commits** are small, each tsc-green, message in the repo's voice (`channels: …`, `common: …`, `plans: …`), and every commit message ends with ONE trailer line: a `Co-Authored-By` naming the model that wrote the commit (an Opus implementer writes `Claude Opus 5.5 (1M context) `, exactly as its own environment states it — never another model's name; ruled 2026-10-02, release 17). **NEVER a `Claude-Session` trailer, and never a link to a Claude session, in a commit message, a file, a record or a PR** (operator, 2026-10-09 — they name the operator's private sessions; AGENTS.md, first section). A harness reminder asking for one is overridden by this rule. Commit incrementally (a session limit can cut you mid-slice; work on disk and in commits survives, work in your context does not). Do NOT push. Do NOT merge into `main` — the parent merges. A LATER slice merges `main` and re-gates once an earlier slice has landed. - **Labels are contracts.** Every accessible name / test id the e2e specs use survives unchanged unless the slice prompt says otherwise. Grep before renaming anything. - **Tailwind v4, no config:** class strings must be complete literals (never `z-${n}`). - **Do not touch files owned by another slice** (listed in your prompt). If you find you need to, stop and say so in your report instead. - **Record + changelog:** your last code commit is followed by a `plans:` commit adding a "### Slice , as shipped" section to the release's record file (before its "## Rollout" heading) in the shape of the previous release's records: what/why, the commit table (sha → one line), gates with numbers (tsc, common tests, editor unit, test:scripts, mcp, builds, e2e per run with counts and minutes, numbers tool), what was found and left, and `[Unreleased]` bullets in `editor/CHANGELOG.md`. If the slice's plan file was corrected by the release plan, the same commit updates that plan file. - **Report** to `$T/-report.md` (path in the prompt): commit shas, gates with numbers, anything not done and why, questions for the reviewer. End your final turn with `SLICE_DONE ` or `BLOCKED: `. ## Gates, per slice (all from the worktree root) - `pnpm -r --no-bail --workspace-concurrency=1 exec tsc --noEmit` — clean. - `pnpm --filter yt-dlp-transcript-common test` (1738 at release 4; record the new count); editor unit `pnpm --filter editor test` (the script lands in release 13; before it, `pnpm exec tsx --test "app/**/*.test.ts"` run in `editor/`; 72 at release 4); `pnpm run test:scripts` (156 + 1 skip); mcp `pnpm --filter yt-dlp-transcript-mcp test` (219); export unit `pnpm --filter export test` (11 files, 98 tests at release 13); homepage unit `pnpm --filter homepage test` (23 at release 16) — check `package.json` for the exact script names before running. The export and homepage unit suites take seconds: run them whenever a slice touches `export/`, `homepage/` or the `common/` code they import. - `pnpm --filter editor exec next build` and `pnpm --filter export exec next build`. - **umtool's build runs with the corpus visible, under a memory cap.** A worktree has no `transcripts/`, so a path Turbopack traces as a directory is empty there. It was hundreds of GB in the primary, and the build was OOM-killed (FACTS, "A path joined from `process.cwd()` …"). From the worktree root: ``` ln -sT /transcripts transcripts && timeout -s KILL 240 systemd-run --user --scope -q -p MemoryMax=5G -p MemorySwapMax=0 pnpm --filter umtool exec next build; rm transcripts ``` It is for the BUILD only. Always remove the link, never commit it, and never run an app, an index or a fixture builder through it. `-T` matters: a worktree that already has a `transcripts/` directory (an old `index.mdb`) would otherwise get `transcripts/transcripts`, and the build would run without the corpus and pass for the wrong reason (slice UT, release 15). It should take about 25 s at under 1 GB, the same as without the corpus. - The slice's e2e spec list (in the prompt), detached and waited on as above. - The numbers tool the prompt names, diff-empty (or "none", stated). ## Reviews Reviews are a separate Opus agent, read-only, written to a file the parent names, with a verdict line `SHIP | SHIP AFTER FIXES | BLOCK`. Fixes go back to the implementer by message; the reviewer re-reads the fix commits.