[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CAVJ413PEMDHS90D1F4BSM":3,"skill-same:01M6CAVJ413PEMDHS90D1F4BSM":86},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":22,"publishedAt":52,"linkOnly":53,"markdownContent":54,"markdownBody":55,"frontMatter":56,"refName":65,"commitSha":66,"skillDirectory":67,"forksCount":68,"repositoryHtmlUrl":69,"repositoryHomepageUrl":6,"ownerHtmlUrl":70,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":71,"install":72,"resources":85},"01M6CAVJ413PEMDHS90D1F4BSM","always-pr-never-local-edit",null,"Never just make local edits and stop. Always create a GH issue + bead, dispatch via ao spawn for a PR, and skillify the pattern. Local exploration is fine; local edits without a PR are a process violation.","jleechanorg\u002Fjleechan-skills","jleechanorg","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F221404966?v=4","01M6C1VJ99XG950X1DWPEBCBGX","01M6C1VJDK5YVDNT3362RT5WSB",6,"MIT","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002Fhermes\u002Fskills\u002Fworkflow\u002Falways-pr-never-local-edit\u002FSKILL.md",[17],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51],"pr","local","edit","always pr never local edit","never","URL","MCP","remote","move","worker","project","lesson","exploration","clean","bq","files","patch","repro","fix","fetch","short","branch","gh pr","access","analysis","SET","authentication","code","auth","2026-11-10 10:12:30",false,"---\nname: always-pr-never-local-edit\nversion: 1.6.0\ndescription: Never just make local edits and stop. Always create a GH issue + bead, dispatch via ao spawn for a PR, and skillify the pattern. Local exploration is fine; local edits without a PR are a process violation.\nchangelog:\n  - \"1.6.0 (2026-07-28): New section 'Dirty-checkout pre-flight — refuse to dispatch onto a dirty or conflicted worktree'. Before any claudem \u002F ao \u002F opencode \u002F Codex dispatch, scan every candidate worktree + the main checkout for clean state. Dispatching onto a dirty worktree silently mixes your PR's commits with someone else's WIP; dispatching onto a conflicted worktree (`UU`\u002F`AA`\u002F`DD` rows in `git status --short`) makes the worker's first patch land on top of an unresolved merge. Verified 2026-07-28 on $GITHUB_REPOSITORY: the available main checkout had 3 modified `analysis\u002F*` files + 2 modified `$PROJECT_ROOT\u002F*.py` + multiple untracked files (dirty); the alternate checkout had unresolved `UU .claude\u002Fcommands\u002Fcode-standards.md` (conflicted). Both are no-go; correct move is `git worktree add -B \u003Ctopic> \u003Cpath> origin\u002Fmain` for a fresh clean branch.\"\n  - \"1.5.0 (2026-07-18): New section 'Worktree-silent-edit trap — when the worktree has no .\u002Fvenv\u002F' covering the dual-CWD silent failure where `patch` or `cp` from the wrong CWD lands edits in the main checkout instead of the worktree, with NO error message. Verified on $GITHUB_REPOSITORY PR #8446 (2026-07-18, SHA 4524525569692db3e5a5b36a818a7248b65fae09): the prompt edits + test file landed in the main checkout (on branch `docs\u002Fbq-cost-spike-2026-07-08-findings`) instead of the worktree's `fix\u002Faegon-rejoin-co-presence-8444` because the worktree had no `.\u002Fvenv\u002F` and I `cd`'d to the main checkout to run `pytest`. Detection heuristic: after every `patch` on a worktree, run `git status --short` on BOTH the worktree AND the main checkout — the main checkout MUST be empty. Recovery recipe: `cp` the file to the worktree, `git checkout -- \u003Cfile>` in the main checkout to revert, then verify with the dual-status check. Cross-references skill `repro` §'Git worktree pitfall → Worktree-silent-edit trap' and `references\u002Fprompt-fix-deliverable-shape-2026-07-18.md` §Pitfall 1.\"\n  - \"1.4.0 (2026-07-15): Two new sections. (a) 'Worktree test-import via Path.home() quirk' — when a test file imports the source via `Path.home() \u002F '.hermes' \u002F 'scripts' \u002F '\u003Cwatcher>.py'` instead of a worktree-relative path, pytest runs against the deployed prod copy and all new-wording tests fail with confusing substring errors. The 4-step temp-copy\u002Frestore work-around plus a detection heuristic. Verified on jleechanorg\u002Fjleechanclaw#781 (first test run had 4\u002F11 failures, all false alarms). (b) 'Local git fetch auth-block work-around for jleechanclaw' — `git fetch origin main` fails with `Authentication failed` because the `origin` URL contains a truncated placeholder token (`x-access-token:ghp_yg....git`). `gh auth setup-git` alone doesn't fix it. The two-step fix: `git remote set-url origin https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002F\u003Crepo>.git` + explicit `'$HOME\u002F.local\u002Fbin\u002Fgh.real auth git-credential'` helper.\"\n  - \"1.3.0 (2026-07-14): New section 'Bidirectional command pointer pattern — user-scope vs repo-local' with the 5-rule user-scope contract, repo-local contract, recipe for authoring a new bidirectional command, and the verified case (jleechanorg\u002Fclaude-commands PR #328 + $GITHUB_REPOSITORY PR #8402). Covers the cross-repo discipline when a slash command exists in BOTH ~\u002F.claude\u002Fcommands\u002F\u003Cname>.md (user-scope, mounted from jleechanorg\u002Fclaude-commands) AND \u003Cproduct-repo>\u002F.claude\u002Fcommands\u002F\u003Cname>.md (repo-local).\"\n  - \"1.2.0 (2026-07-13): Added 'Cross-repo pre-flight — find the right repo before opening the PR'. Recurring-alert pattern lesson from MCP Agent Mail `is_test IS NULL` watcher (jleechanclaw #774): the watcher script lives in jleechanorg\u002Fjleechanclaw, the BQ data lives in your-project.com — opening the PR in the wrong repo wastes a worktree. Recipe: trace the alert source to its origin repo before opening the PR.\"\n  - \"1.1.0 (2026-07-12): Added two new sections. (a) 'PR-topology pre-flight — iterate, don't proliferate': when handed a bug-fix task, check `gh pr list` for an existing PR covering the same issue BEFORE opening a new one; push improvements to the existing branch instead. Verified on merge_train #42 where PR #41 already covered the same fix. (b) 'Wind-down checkpoint — the WIP-pushed end-state': when the user signals immediate pause\u002Frestart, the right end-state is WIP commit + push to working branch + reply with branch\u002FSHA\u002Fempty `git status --porcelain`. Do NOT merge, do NOT push to `main`, do NOT touch deploy surfaces.\"\n---\n\n# always-pr-never-local-edit\n\n## Trigger\nAny time you find yourself editing files locally (outside an ao worktree) without a PR in progress.\n\n## Rule\n\n**NEVER make local edits and stop.** Every change that modifies source must end with a PR. The workflow is:\n\n1. **Investigate locally** — read files, search code, understand the problem. This is fine.\n2. **Create GH issue + bead** — `gh issue create` + `br create`. Mandatory before any edits.\n3. **Dispatch via `ao spawn`** — let the worker do the edits in its own worktree and create a PR.\n4. **Skillify the pattern** — if you learned something reusable, create\u002Fupdate a skill.\n\n### What counts as \"local edits and stop\"\n- Editing files in the main checkout without pushing or creating a PR\n- Making code changes in a session that ends without a PR URL\n- Investigating, finding the fix, applying it locally, then telling the user \"done\" with no PR\n\n### What's allowed locally\n- Read-only exploration: `search_files`, `read_file`, `grep`, `git log`, `gh` queries\n- Writing temporary files (scripts, tests) that you run and discard\n- Creating issues, beads, cron jobs, memory entries\n\n## Why\n\nLocal edits in the main checkout:\n- Create drift between main and production\n- Can't be reviewed or rolled back\n- Get lost when the next checkout overwrites them\n- Bypass CI and evidence standards\n\nA PR is the minimum unit of done-ness. No PR = not done.\n\n## Skillifying the pattern\n\nWhen `\u002Fskillify` is requested, create a **general** skill — not one specific to the current project or file. Ask: \"Would this pattern apply the same way in any repo?\" If yes, make it general.\n\nExamples:\n- ✅ `always-pr-never-local-edit` — general workflow pattern\n- ❌ `campaign-field-editability` — too specific to one project's one feature\n\nIf the pattern has reusable project-specific details (file paths, class names), put those in the GH issue or memory, not in the skill.\n\n## Recovery\nIf you catch yourself making local edits:\n1. Stop immediately\n2. `git stash` or `git checkout -- .` to undo\n3. Create the GH issue + bead\n4. Dispatch via `ao spawn` with the full task description\n5. Don't resume local edits\n\n## PR-topology pre-flight — iterate, don't proliferate (added 2026-07-12)\n\nBefore opening a new PR for a known bug or issue, check whether an existing PR already covers it. If yes, **push your improvements to that branch instead of opening a parallel PR**. This is the \"pr-quantity-control: iterate, don't proliferate\" rule from `finish-the-job` v1.11.0 extended to the local-edit workflow.\n\n**The trap:** when handed a bug-report-style task (e.g. \"fix issue #42\"), the natural Phase 2 instinct is \"open a new PR against `origin\u002Fmain`\". If `gh pr list` reveals an already-open PR covering the same issue, pushing a parallel branch creates reviewer work, evidence-bundle conflicts, and merge-order race conditions.\n\n**Recipe (run BEFORE `git worktree add -b \u003Cnew>` or `gh pr create`):**\n\n```bash\n# 1. List open PRs matching the topic\ngh pr list --repo \u003COWNER>\u002F\u003CREPO> --state open \\\n  --json number,title,headRefName,additions,changedFiles \\\n  --jq '.[] | \"\\(.number) [\\(.state)] \\(.headRefName) +\\(.additions)\u002F-\\(.deletions) files=\\(.changedFiles)\"'\n\n# 2. Verify the existing PR covers the issue\ngh pr view \u003CN> --repo \u003COWNER>\u002F\u003CREPO> --json body \\\n  --jq '.body' | grep -E \"\u003Cissue-number|keywords>\"\n```\n\n**Decision matrix:**\n\n| Existing PR state | Action |\n|---|---|\n| 0 matches | Normal flow — open new PR from a fresh branch off `origin\u002Fmain` |\n| 1 match, covers the issue | Iterate on its branch: `git worktree add -b \u003Ctopic>-improvements \u003Cpath> origin\u002F\u003Cexisting-branch>`, push commits there, comment on the PR instead of opening a new one |\n| 1 match, but unrelated (false positive) | Normal flow — open new PR |\n| ≥2 matches | Load `dispatch-task` skill to triage which is canonical |\n\n**Verified case 2026-07-12, jleechanorg\u002Fmerge_train issue #42:** PR #41 (`fix\u002Fpretooluse-approve-decision`) was already open with the same bug fix — Codex-driven, CI green, CodeRabbit APPROVED, 5 days unmerged. The natural Phase 2 reflex was \"open a new PR\". The user pushed back: *\"iterate on PR #41 — do NOT open a duplicate PR (pr-quantity-control: iterate, don't proliferate)\"*. I created `work\u002Fpr41-improvements` branched off `origin\u002Ffix\u002Fpretooluse-approve-decision`, pushed improvements there. No duplicate PR; the existing PR gets the better fix on its existing branch.\n\n## Push onto existing PR's headRefName from a separate worktree (added 2026-07-14)\n\nWhen you don't own the existing PR (someone else authored it, or an automated worker has been pushing commits) and your task is \"add these changes to that PR\", the recipe is:\n\n1. **Resolve the PR head branch** — `gh pr view \u003CN> --repo \u003COWNER>\u002F\u003CREPO> --json headRefName,headRepository` (NEVER guess; the user might rename it).\n2. **Create a worktree tracking that exact branch** — `git -C \u003CREPO> worktree add -B \u003Cmy-topic-branch> \u003CWORKTREE_PATH> origin\u002F\u003CheadRefName>`. Use `-B` (force-create) rather than `-b` (fail if exists) since the worktree is fresh.\n3. **Commit on your topic branch** — `git -C \u003CWT> add \u003Cpaths>` (path-scoped, NEVER `git add -A` if there's any chance of foreign staged work) → `git -C \u003CWT> commit -m \"...\"`.\n4. **Push onto the PR head ref** — `git -C \u003CWT> push origin HEAD:refs\u002Fheads\u002F\u003CheadRefName>`. This adds your commit ON TOP of the existing PR's head, so the PR's UI shows it as a new commit and reviewers see it as part of the same PR — no parallel PR, no merge queue contention.\n5. **Verify** — `git -C \u003CWT> rev-parse origin\u002F\u003CheadRefName>` returns your new SHA. Note: `gh pr view \u003CN> --json head_sha` may show a stale SHA (the PR cache lags the push by ~30s); the local `git rev-parse origin\u002F\u003CheadRefName>` is authoritative.\n\n**The trap:** the natural instinct when you don't own a branch is `git worktree add -b \u003Cnew> origin\u002Fmain`, then `git push origin \u003Cnew>`, then open a new PR. That creates the duplicate PR `finish-the-job` v1.11.0 + `always-pr-never-local-edit` v1.1.0 \u002F v1.2.0 all warn against. The \"push onto existing headRefName\" pattern avoids the duplication entirely.\n\n**Verified case 2026-07-14, jleechanorg\u002Fclaude-commands PR #321:** PR #321 (`fix: launch real Sonnet Claude teams via tmux`, head `fix\u002Freal-claude-team-tmux`, owned by another actor with 670k LOC \u002F 3001 files changed) already had the canonical surface for sidekick + swarm + test_real_claude_team_contract. A 5-minute checkpoint cadence contract was needed on the same files. The recipe: created `~\u002F.worktrees\u002Fcc-pr321-checkpoint` tracking `origin\u002Ffix\u002Freal-claude-team-tmux` (NOT `origin\u002Fmain`), committed the contract on `fix\u002Fsidekick-5min-checkpoint-pr321`, pushed with `git push origin HEAD:refs\u002Fheads\u002Ffix\u002Freal-claude-team-tmux`. The push landed: `286311a97..7c5031623` on `fix\u002Freal-claude-team-tmux`. Two commits (`7c5031623` initial + `1a43307a0` \u002Fadvice Round 2 tightening) now sit on top of the existing PR's head. No parallel PR; reviewers see the contract changes as additional commits on PR #321.\n\n**Anti-pattern:** `git worktree add -b docs\u002Fsidekick-5min-checkpoint origin\u002Fmain` + opening a new PR. This creates the duplicate PR problem `always-pr-never-local-edit` v1.1.0 was designed to prevent.\n\n## Worktree-silent-edit trap — when the worktree has no .\u002Fvenv\u002F (added 2026-07-18)\n\nWhen you create a fresh `git worktree add -b \u003Cbranch> origin\u002Fmain` for a PR, the worktree has the source files but **does NOT have `.\u002Fvenv\u002F`** (the Python venv lives only in the main checkout). When you `cd` to the worktree to `patch` prompt files \u002F write tests, you can't run `pytest` (no venv). The reflex: `cd $HOME\u002Fprojects\u002F\u003Cmain>` to use the venv, then keep editing — except now your `patch` and `cp` commands write to the **main checkout**, not the worktree.\n\nThe trap: **there is NO error message.** `patch` succeeds (file exists in main checkout too), `pytest` runs (venv is in main checkout), tests pass (because the file is correct). The edits look correct in the test run, but they were applied on a different branch than the PR branch. The PR commits land on whatever branch the main checkout is on, not on the worktree's `fix\u002F\u003Ctopic>` branch.\n\n**Detection heuristic (mandatory after every patch on a worktree):**\n\n```bash\n# After EVERY patch, run BOTH status commands:\ncd $HOME\u002Fprojects\u002Fwt-\u003Ctopic>\ngit status --short          # MUST show the patched files\ngit rev-parse --abbrev-ref HEAD   # confirm branch is what you think\n\ncd $HOME\u002Fprojects\u002F\u003Cmain-checkout>\ngit status --short          # MUST be empty after a worktree-local edit\n```\n\nIf the main checkout shows the file as modified, the patch landed in the wrong place.\n\n**Recipe for staying in the worktree (when you need the venv):**\n\nThe worktree's tests can run with the main checkout's venv via absolute path:\n\n```bash\ncd $HOME\u002Fprojects\u002Fwt-\u003Ctopic>\n# Use the main checkout's venv explicitly — patches still write to the worktree\n\u002Fpath\u002Fto\u002F\u003Cmain-checkout>\u002Fvenv\u002Fbin\u002Fpython -m pytest $PROJECT_ROOT\u002Ftests\u002F\u003Ctest>.py -v\n\n# OR copy test file to the main checkout's tests dir, run, then revert\ncp $PROJECT_ROOT\u002Ftests\u002F\u003Ctest>.py $HOME\u002Fprojects\u002F\u003Cmain>\u002F$PROJECT_ROOT\u002Ftests\u002F\u003Ctest>.py\nTESTING_AUTH_BYPASS=true $HOME\u002Fprojects\u002F\u003Cmain>\u002Fvenv\u002Fbin\u002Fpython -m pytest $PROJECT_ROOT\u002Ftests\u002F\u003Ctest>.py -v\n# Verify, then revert the main checkout's tests dir (NOT the worktree's)\ncd $HOME\u002Fprojects\u002F\u003Cmain>\ngit checkout -- $PROJECT_ROOT\u002Ftests\u002F\u003Ctest>.py\n```\n\nThe second pattern is safer because it leaves the test file under your natural test-discovery rootdir (the main checkout's `$PROJECT_ROOT\u002Ftests\u002F`).\n\n**Recovery if you've already shipped the edit to the wrong branch:**\n\n```bash\n# 1. Confirm the wrong-branch symptom\ncd $HOME\u002Fprojects\u002F\u003Cmain>\ngit status --short                # shows the file as modified here\n\n# 2. Revert the main checkout (so it stays clean)\ncd $HOME\u002Fprojects\u002F\u003Cmain>\ngit checkout -- \u003Cfile-path>\n\n# 3. Copy the file to the worktree\ncp \u003Cfile-path> $HOME\u002Fprojects\u002Fwt-\u003Ctopic>\u002F\u003Cfile-path>\n\n# 4. Verify the worktree now has it\ncd $HOME\u002Fprojects\u002Fwt-\u003Ctopic>\ngit status --short                # MUST show \u003Cfile> as modified\n\n# 5. Verify the main checkout is clean\ncd $HOME\u002Fprojects\u002F\u003Cmain>\ngit status --short                # MUST be empty\n```\n\n**Verified case 2026-07-18, $GITHUB_REPOSITORY PR #8446:** the prompt edits (`$PROJECT_ROOT\u002Fprompts\u002Fplanning_protocol.md` + `$PROJECT_ROOT\u002Fprompts\u002Fnarrative_system_instruction.md`) and the new test file (`$PROJECT_ROOT\u002Ftests\u002Ftest_planning_block_canonical_state_anchor_8444.py`) all landed in the main checkout first (no error). The main checkout was on branch `docs\u002Fbq-cost-spike-2026-07-08-findings`; the worktree was on `fix\u002Faegon-rejoin-co-presence-8444`. Caught via `git status --short` on both directories. ~3 tool calls wasted. Without the dual-status check, the PR would have shipped on `docs\u002Fbq-cost-spike-2026-07-08-findings`, NOT on the intended `fix\u002Faegon-rejoin-co-presence-8444` branch — and the PR number would have referenced a docs branch instead of the fix branch.\n\n**Cross-reference:** skill `repro` §\"Git worktree pitfall → Worktree-silent-edit trap\" and `references\u002Fprompt-fix-deliverable-shape-2026-07-18.md` §\"Pitfall 1 — Edits landed in the wrong checkout (silent failure)\" for the full recipe and a parallel example.\n\n## Bidirectional command pointer pattern — user-scope vs repo-local (added 2026-07-14)\n\nWhen a slash command exists in BOTH `~\u002F.claude\u002Fcommands\u002F\u003Cname>.md` (user-scope, mounted from `jleechanorg\u002Fclaude-commands`) AND `\u003Cproduct-repo>\u002F.claude\u002Fcommands\u002F\u003Cname>.md` (repo-local), the two files MUST form a **bidirectional pointer contract**:\n\n**User-scope contract (lives in `~\u002F.claude\u002Fcommands\u002F\u003Cname>.md`):**\n1. Stays **project-agnostic** — no hardcoded paths to a specific product repo.\n2. Documents that any repo-local `.claude\u002Fcommands\u002F\u003Cname>.md` MAY override specific lanes (e.g. add `\u002Fthermo` lane) but MUST inherit the 4 user-scope lanes (ponytail, ZFC, ZFC leveling, root-cause-first).\n3. **Reciprocal pointer** — explicit \"If a repo-local file exists at `\u003Crepo>\u002F.claude\u002Fcommands\u002F\u003Cname>.md`, that file MUST also be loaded; load both.\"\n\n**Repo-local contract (lives in `\u003Cproduct-repo>\u002F.claude\u002Fcommands\u002F\u003Cname>.md`):**\n1. **Top-of-file rule**: \"MUST be loaded along with `~\u002F.claude\u002Fcommands\u002F\u003Cname>.md`\" as the first line after the YAML frontmatter.\n2. Defines repo-specific behavior (e.g. `\u002Fthermo` lane, `\u002Fes` evidence rule) without forking the 4 user-scope lanes.\n3. **Reciprocal pointer** back to `~\u002F.claude\u002Fcommands\u002F\u003Cname>.md` documenting which lanes are added vs. inherited.\n\n**Verified case 2026-07-14 (jleechanorg\u002Fclaude-commands PR #328 + $GITHUB_REPOSITORY PR #8402):** the `\u002Fcode-standards` command existed in both locations but the user-scope copy was worldarchitect-flavored (referenced the worldai repo as the canonical) and the worldai copy didn't have the reciprocal \"load user-scope\" rule. Both rewrites land in their respective repos via PR #328 and PR #8402.\n\n**The trap:** writing one copy of the command and assuming it'll be loaded consistently across repos. Repo-local Claude agents load the user-scope command by default but DO NOT auto-load a sibling file at `\u003Crepo>\u002F.claude\u002Fcommands\u002F\u003Cname>.md` unless the user-scope file (or the agent's harness) explicitly says \"also load the repo-local counterpart.\"\n\n**Recipe for authoring a new bidirectional command:**\n\n1. **User-scope side first** (in `jleechanorg\u002Fclaude-commands` worktree, branch off `origin\u002Fmain`):\n   - Write the project-agnostic command at `.claude\u002Fcommands\u002F\u003Cname>.md`.\n   - Add a `## Bidirectional pointer contract` section that lists the 5 rules above.\n   - Open PR against `jleechanorg\u002Fclaude-commands`.\n2. **Repo-local side** (in `\u003Cproduct-repo>` worktree, branch off `origin\u002Fmain`):\n   - Write the repo-specific overlay at `.claude\u002Fcommands\u002F\u003Cname>.md`.\n   - Add the \"MUST be loaded along with `~\u002F.claude\u002Fcommands\u002F\u003Cname>.md`\" rule at the top.\n   - Add a `## Bidirectional contract` section that documents which lanes are added vs. inherited.\n   - Open PR against `\u003Cproduct-repo>`.\n3. **Both PRs MUST reference each other** in the PR description (one sentence: \"Paired with PR #N in \u003Cother-repo>\").\n4. **For commands that exist in `~\u002F.claude\u002Fcommands\u002F` but are wholly repo-specific** (e.g. `end2end-testing.md`, `benchg-ts.md`, `worldai-usage-email.md`), add a `> Worldai-only command. \u003Cdescription>.` banner block at the top, then a `## Repo-local counterpart` section pointing at `\u003Cproduct-repo>\u002F.claude\u002Fcommands\u002F\u003Cname>.md`. Do NOT remove the user-scope file — leave the banner so anyone running the command from outside the product repo sees the scope warning.\n5. **Create the repo-local pointer file** in `\u003Cproduct-repo>\u002F.claude\u002Fcommands\u002F` (thin YAML frontmatter + 2-3 line pointer back to the user-scope command) so the product repo has a complete command surface.\n\n**Why two repos, not one:** the user-scope `~\u002F.claude\u002Fcommands\u002F` is shared across ALL `jleechanorg\u002F*` repos via the `jleechanorg\u002Fclaude-commands` worktree. The repo-local `\u003Cproduct-repo>\u002F.claude\u002Fcommands\u002F` is loaded only when the agent is invoked from inside that product repo. Splitting them lets the same command have different lane sets per repo without forking the user-scope copy.\n\n## Cross-repo pre-flight — find the right repo before opening the PR (added 2026-07-13)\n\nBefore opening a new PR, confirm the change belongs in the repo you're targeting. Recurring alerts and cross-cutting tools often live in a different repo than the product code they monitor. Opening the PR in the wrong repo means the worktree, CI, reviewers, and reviewer-bot signals all run against the wrong context.\n\n**The trap:** when handling an alert like \"X is broken in production,\" the natural instinct is to find the repo named in the alert and open a PR there. But if the alert is fired by a *watcher* script, the fix often belongs in the watcher's repo, not the watched repo. Watcher scripts, AO infra, and Hermes tooling live in `jleechanorg\u002Fjleechanclaw`. Product code lives in `$GITHUB_REPOSITORY`. Hermes skills live in `~\u002F.hermes\u002Fskills\u002F`. Mixing these up means the PR's diff doesn't match the target repo's CI matrix.\n\n**Recipe (run BEFORE `git worktree add -b \u003Cnew>`):**\n\n```bash\n# 1. Identify the source of the alert\n#    - bot\u002Fcron watcher alert? Check ~\u002F.hermes\u002Fscripts\u002F for the script name\n#    - GitHub Action failure? Check the workflow file's repo + path\n#    - Slack message about a service? Trace the alert source to its origin\n\n# 2. List candidate repos for the fix\ngh api 'orgs\u002Fjleechanorg\u002Frepos?per_page=100&sort=updated' \\\n  --jq '.[] | \"\\(.name) \\(.description \u002F\u002F \"\")\"' | head -30\n\n# 3. For each candidate repo, run a quick `git grep` from the terminal to find\n#    the file the fix belongs in. The repo where the file lives = the PR target.\ngh -C ~\u002Frepos\u002F\u003Ccandidate> ls-files | grep -E \"\u003Crelevant-keyword>\"\n\n# 4. Verify the fix's natural reviewer set matches the target repo\ngh api repos\u002F\u003Cowner>\u002F\u003Crepo>\u002Fcontents\u002F.github\u002FCODEOWNERS --jq '.content' | base64 -d\n```\n\n**Verified case 2026-07-13, jleechanclaw #774 (recurring `is_test IS NULL` alert):** The MCP Agent Mail alert fired in `C0BCVG4F560` about Gemini rows with `is_test IS NULL`. Natural reflex: open PR in `your-project.com` where the BQ data lives. Correct target: `jleechanorg\u002Fjleechanclaw` — the watcher script `scripts\u002Fbq_coverage_watcher.py` lives there, and the watcher alert logic is what needs fixing (the underlying bug was already fixed in `your-project.com` #8351). PR-topology pre-flight found:\n- `your-project.com` #8070 — open, wrong shape (the original 1264-line \"add backfill + lock\" attempt, superseded by #8351)\n- `your-project.com` #8351 — merged, the actual root-cause fix\n- The right target for the new work was `jleechanorg\u002Fjleechanclaw` because the watcher alerting logic (which is what needs updating to stop firing false positives) lives there.\n\n**Anti-pattern:** Opening the PR in the \"alarmed repo\" by default. Always trace the alert source to its origin repo before opening the PR.\n\n## Wind-down checkpoint — the WIP-pushed end-state (added 2026-07-12)When the user explicitly says they are pausing \u002F restarting \u002F the session must end NOW (e.g. \"WIND-DOWN: Jeff is restarting\", \"checkpoint NOW\", \"stop and report state\"), the right end-state is **WIP-pushed to a working branch, NOT merged**. This is a fifth valid end-state alongside the four in `finish-the-job`'s Contract.\n\n**The recipe:**\n\n1. **Commit all work** (WIP is fine — even partial code + tests is OK if the commit message is honest about state). Include any untracked files via `git add -A` so the diff matches what was in flight.\n2. **Push to the working branch** — never to `main` and never to a \"canonical\" branch the user didn't designate. Use the worktree's tracking branch: `git push -u origin \u003Cbranch>`.\n3. **Reply in the thread with three lines, in this exact order:**\n   - Branch name (full `origin\u002F\u003Cbranch>`)\n   - Pushed SHA (`git rev-parse HEAD`)\n   - `git status --porcelain` output (must be empty)\n4. **Do NOT merge anything during wind-down.** Even if the PR is technically green, `gh pr merge` requires the user's deliberate go-ahead — not a session-end reflex.\n5. **State what is unfinished** in the same reply so the next session can resume without re-deriving context: known-failing tests, unmerged PRs, unclosed beads, unverified repro commands, etc.\n\n**Verified case 2026-07-12, jleechanorg\u002Fmerge_train PR #41 follow-up:** the user sent \"WIND-DOWN: Jeff is restarting the computer shortly. Please checkpoint NOW\" mid-task. I had partial code + 3 failing tests + a WIP commit ready but not pushed. The right move was `git add -A && git commit -m \"WIP(hooks): issue #42 — ...\" && git push -u origin work\u002Fpr41-improvements`, then reply with branch + SHA + empty `git status --porcelain`, then pause. Did NOT touch `main`, did NOT merge PR #41, did NOT touch `~\u002F.local\u002Fbin\u002Fconflict-warn-pre-tool.sh` (left byte-identical for the next session to deploy after the merge).\n\n**Anti-patterns:**\n\n- ❌ \"I'll keep working until the end\" — the user's wind-down is a hard stop. Keep working past it is an autonomy violation.\n- ❌ Pushing a partial commit to `main` to \"save it\" — the user will merge to `main` deliberately, and seeing unverified code on `main` is worse than losing the WIP.\n- ❌ A reply that says \"still working, will continue after restart\" without the branch\u002FSHA\u002Fporcelain — the next session can't resume without that information.\n- ❌ Merging a green-looking PR during wind-down without `MERGE APPROVED` — the merge gate is the user's, not the agent's.\n\n## Worktree test-import via `Path.home()` quirk (added 2026-07-15)\n\nSome test files import the source via an absolute path under `Path.home()` rather than a path relative to the test file. Concretely, `scripts\u002Ftests\u002Ftest_bq_coverage_watcher.py` does:\n\n```python\nWATCHER_PATH = Path.home() \u002F \".hermes\" \u002F \"scripts\" \u002F \"bq_coverage_watcher.py\"\nspec = importlib.util.spec_from_file_location(\"bq_coverage_watcher\", WATCHER_PATH)\n```\n\nWhen you `git worktree add` and patch the watcher in the worktree, `pytest` does NOT pick up the worktree copy — it runs against `~\u002F.hermes\u002Fscripts\u002Fbq_coverage_watcher.py` (the deployed prod copy). All \"new wording\" tests fail with confusing messages like `assert \"Remediation:\" in msg` against a deployed file that doesn't contain `Remediation:`.\n\n**The trap:** you edit in the worktree, see green tests in your head, run `pytest`, get 4 failures, and assume your patch is wrong. The patch is fine — the test is loading the wrong module.\n\n**The work-around (run once per test run, then restore before commit):**\n\n```bash\n# 1. Save the deployed copy for restore\ncp ~\u002F.hermes\u002Fscripts\u002F\u003Cwatcher>.py ~\u002F.hermes\u002Fscripts\u002F\u003Cwatcher>.py.bak-$(date +%s)\n\n# 2. Copy the patched worktree version into the import-target path\ncp \u002Ftmp\u002F\u003Crepo>-\u003Ctopic>\u002Fscripts\u002F\u003Cwatcher>.py ~\u002F.hermes\u002Fscripts\u002F\u003Cwatcher>.py\n\n# 3. Run pytest from anywhere — tests pick up the patched file\npython3 -m pytest \u002Ftmp\u002F\u003Crepo>-\u003Ctopic>\u002Fscripts\u002Ftests\u002Ftest_\u003Cwatcher>.py -v\n\n# 4. ALWAYS restore before commit, otherwise the local deploy drifts from main\nmv ~\u002F.hermes\u002Fscripts\u002F\u003Cwatcher>.py.bak-$(date +%s) ~\u002F.hermes\u002Fscripts\u002F\u003Cwatcher>.py\n```\n\n**Detection heuristic:** if a test fails on a substring your patch obviously adds (e.g. fails on `assert \"Remediation:\" in msg` when your patch literally added the string `Remediation:`), run `grep -n \"\u003Csubstring>\" ~\u002F.hermes\u002Fscripts\u002F\u003Cwatcher>.py` BEFORE the patch and AFTER the patch. If neither matches, the test is loading a different file. Use the work-around above.\n\n**Verified case 2026-07-15, jleechanorg\u002Fjleechanclaw#781:** first test run had 4\u002F11 failures with `assert \"$PROJECT_ROOT\u002Fbq_logging.py\" in msg` style errors. The patched file did contain the string; the test was loading the deployed 511-line copy that didn't have the new text. Work-around applied; 11\u002F11 green; deployed file restored before commit. Without this trap-recognition, ~3 tool calls wasted re-reading the patch.\n\n**Cross-reference:** skill `verify-telemetry-alert` Step 3a.1 (the same work-around appears in Step 5 of that recipe).\n\n## Local `git fetch` auth-block work-around for jleechanclaw (added 2026-07-15)\n\n`git fetch origin main` in `jleechanorg\u002Fjleechanclaw` (and most `jleechanorg\u002F*` repos) fails with `Authentication failed for 'https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechanclaw.git\u002F'` even when `gh auth status` shows a working `jleechan2015` account. Root cause: the `origin` remote URL contains a truncated\u002Fplaceholder token (`x-access-token:ghp_yg....git`) that no longer authenticates.\n\n**Symptoms:**\n```\n$ git fetch origin main\nremote: Invalid username or token. Password authentication is not supported for Git operations.\nfatal: Authentication failed\n```\n\n**Work-around recipe:**\n\n```bash\n# 1. Reset origin to the clean public URL (no embedded placeholder token)\ncd \u003Cworktree>\ngit remote set-url origin https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002F\u003Crepo>.git\n\n# 2. Force the gh-credential helper explicitly (the global gitconfig helper may be empty in worktrees)\ngit -c credential.helper='$HOME\u002F.local\u002Fbin\u002Fgh.real auth git-credential' \\\n    fetch origin main\n\n# 3. Confirm fetch succeeded\ngit rev-parse origin\u002Fmain  # should now show the post-#774 SHA, not the stale one\n```\n\n**Why `gh auth setup-git` alone doesn't fix it:** it sets up the credential helper, but `git fetch` still uses the URL configured in `.git\u002Fconfig` for that specific remote. If that URL is broken, no helper resolves it. The two-step fix is mandatory.\n\n**Verified case 2026-07-15, jleechanorg\u002Fjleechanclaw#781:** first fetch failed with `Authentication failed`. `gh auth setup-git` returned silently. After `git remote set-url origin https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechanclaw.git` + explicit `gh.real auth git-credential`, fetch succeeded; `git rev-parse origin\u002Fmain` jumped from stale `1a8c5aef` to post-#774 `99cb779`.\n\n## Dirty-checkout pre-flight — refuse to dispatch onto a dirty or conflicted worktree (added 2026-07-28)\n\nBefore dispatching a worker (ao spawn \u002F claudem \u002F opencode) onto an existing checkout, **scan every candidate worktree + the main checkout for clean state**. A \"clean\" worktree is one where `git status --short` returns empty AND there are no merge\u002Frebase conflicts. Dispatching onto a dirty worktree silently mixes your PR's commits with someone else's WIP, and dispatching onto a conflicted worktree (state `UU` \u002F `AA` \u002F `DD` rows in `git status --short`) makes the worker's first patch land on top of an unresolved merge — a guarantee the next rebase or merge will produce conflicts the agent never saw.\n\n**Recipe (run BEFORE `git worktree add` OR before reusing an existing worktree):**\n\n```bash\n# 1. List ALL candidate worktrees for the repo (main + every entry under ~\u002F.worktrees\u002F, ~\u002Fprojects\u002F, ~\u002Frepos\u002F)\ngh repo list jleechanorg --json nameWithOwner --jq '.[].nameWithOwner' \\\n  | xargs -I{} sh -c 'printf \"%s\\n\" \"{}\"' 2>\u002Fdev\u002Fnull | head\n\n# For each candidate, get status\nfor wt in ~\u002Fprojects\u002F\u003Crepo> ~\u002Frepos\u002Fjleechanorg\u002F\u003Crepo> ~\u002F.worktrees\u002F*\u002F\u003Crepo> 2>\u002Fdev\u002Fnull; do\n  if [ -d \"$wt\" ]; then\n    echo \"=== $wt ===\"\n    git -C \"$wt\" rev-parse --abbrev-ref HEAD 2>\u002Fdev\u002Fnull\n    git -C \"$wt\" rev-parse --abbrev-ref --symbolic-full-name @{u} 2>\u002Fdev\u002Fnull\n    git -C \"$wt\" status --short --branch 2>\u002Fdev\u002Fnull | head -30\n  fi\ndone\n```\n\n**Decision matrix:**\n\n| Worktree state | Action |\n|---|---|\n| `git status --short` returns empty | Safe to dispatch — worktree is clean. |\n| `git status --short` shows only `M` \u002F `A` \u002F `??` on the planned-PR's intended files | Safe to dispatch — the dirt is the worker's intended changes. Confirm with the user. |\n| `git status --short` shows `UU` \u002F `AA` \u002F `DD` (merge conflicts) | **DO NOT dispatch.** Resolve the conflicts first (`git status --short` to identify files, `git checkout --theirs\u002F--ours \u003Cfile>` or manual edit, then `git add` + `git commit` if needed). |\n| `git status --short` shows unrelated modified files (e.g. `.beads\u002Fissues.jsonl`, unrelated `.py` files, `wt-\u003Cother-topic>\u002F`) | **DO NOT dispatch.** The agent's first `git add` + commit will accumulate that dirt onto the new PR's branch. Either `git checkout -- \u003Cunrelated-file>` to drop, or pick a different worktree, or `git worktree add -B \u003Cnew-topic> \u003Cwt-path> origin\u002Fmain` for a fresh-clean branch. |\n| No worktree exists OR all candidate worktrees are dirty | **Create a fresh worktree from `origin\u002Fmain`:** `git worktree add -B \u003Ctopic>-\u003Cshort-hash> \u003Cpath> origin\u002Fmain`. Do NOT edit in the main checkout. |\n\n**Why this matters even when the worker runs in its own sandboxed worktree:** many coding agents (claudem \u002F opencode \u002F Codex) accept a `--workdir` flag but still inherit the user's `.gitconfig`, GitHub auth tokens, and IDE state. If the agent's first action is `git status` and the working tree is dirty, the agent may either (a) silently commit on top of unrelated changes, or (b) refuse to commit and ask the user to clean up — neither outcome is acceptable for a one-shot dispatch.\n\n**Anti-pattern:** picking the most-recently-touched worktree under `~\u002F.worktrees\u002F` because \"it was used recently, must be safe.\" Recent activity is not the same as clean state. Always run `git status --short` first; never trust `mtime` or branch-name familiarity.\n\n**Verified case 2026-07-28, $GITHUB_REPOSITORY:** the available worktrees were:\n- `~\u002Fprojects\u002Fyour-project.com` — on branch `pr8399-w2verify`, 3 modified files (`.beads\u002Fissues.jsonl`, `analysis\u002Fcampaign_analysis_sariel_v2.json`, `analysis\u002Fcampaign_snapshot_sariel_v2.json`), 2 modified `$PROJECT_ROOT\u002F*.py`, multiple untracked files (`repro-ta[REDACTED_OPENAI_KEY]`, `specs\u002Fskeptic-report.json`, etc.) → **dirty, do NOT dispatch**\n- `~\u002Frepos\u002F$GITHUB_REPOSITORY` — on branch `fix\u002Fcron-exit-semantics-and-oom-watchdog`, **unresolved merge conflicts** (`UU .claude\u002Fcommands\u002Fcode-standards.md`), 1 modified file → **conflicted, do NOT dispatch**\n- No clean worktree available → the right move was to create a fresh worktree from `origin\u002Fmain` before dispatching the claudem worker.\n\nThe lesson: scanning for clean state is the worktree equivalent of `git fetch origin` before push — a 5-second check that prevents a 30-minute cleanup. Add it to every dispatch workflow.","# always-pr-never-local-edit\n\n## Trigger\nAny time you find yourself editing files locally (outside an ao worktree) without a PR in progress.\n\n## Rule\n\n**NEVER make local edits and stop.** Every change that modifies source must end with a PR. The workflow is:\n\n1. **Investigate locally** — read files, search code, understand the problem. This is fine.\n2. **Create GH issue + bead** — `gh issue create` + `br create`. Mandatory before any edits.\n3. **Dispatch via `ao spawn`** — let the worker do the edits in its own worktree and create a PR.\n4. **Skillify the pattern** — if you learned something reusable, create\u002Fupdate a skill.\n\n### What counts as \"local edits and stop\"\n- Editing files in the main checkout without pushing or creating a PR\n- Making code changes in a session that ends without a PR URL\n- Investigating, finding the fix, applying it locally, then telling the user \"done\" with no PR\n\n### What's allowed locally\n- Read-only exploration: `search_files`, `read_file`, `grep`, `git log`, `gh` queries\n- Writing temporary files (scripts, tests) that you run and discard\n- Creating issues, beads, cron jobs, memory entries\n\n## Why\n\nLocal edits in the main checkout:\n- Create drift between main and production\n- Can't be reviewed or rolled back\n- Get lost when the next checkout overwrites them\n- Bypass CI and evidence standards\n\nA PR is the minimum unit of done-ness. No PR = not done.\n\n## Skillifying the pattern\n\nWhen `\u002Fskillify` is requested, create a **general** skill — not one specific to the current project or file. Ask: \"Would this pattern apply the same way in any repo?\" If yes, make it general.\n\nExamples:\n- ✅ `always-pr-never-local-edit` — general workflow pattern\n- ❌ `campaign-field-editability` — too specific to one project's one feature\n\nIf the pattern has reusable project-specific details (file paths, class names), put those in the GH issue or memory, not in the skill.\n\n## Recovery\nIf you catch yourself making local edits:\n1. Stop immediately\n2. `git stash` or `git checkout -- .` to undo\n3. Create the GH issue + bead\n4. Dispatch via `ao spawn` with the full task description\n5. Don't resume local edits\n\n## PR-topology pre-flight — iterate, don't proliferate (added 2026-07-12)\n\nBefore opening a new PR for a known bug or issue, check whether an existing PR already covers it. If yes, **push your improvements to that branch instead of opening a parallel PR**. This is the \"pr-quantity-control: iterate, don't proliferate\" rule from `finish-the-job` v1.11.0 extended to the local-edit workflow.\n\n**The trap:** when handed a bug-report-style task (e.g. \"fix issue #42\"), the natural Phase 2 instinct is \"open a new PR against `origin\u002Fmain`\". If `gh pr list` reveals an already-open PR covering the same issue, pushing a parallel branch creates reviewer work, evidence-bundle conflicts, and merge-order race conditions.\n\n**Recipe (run BEFORE `git worktree add -b \u003Cnew>` or `gh pr create`):**\n\n```bash\n# 1. List open PRs matching the topic\ngh pr list --repo \u003COWNER>\u002F\u003CREPO> --state open \\\n  --json number,title,headRefName,additions,changedFiles \\\n  --jq '.[] | \"\\(.number) [\\(.state)] \\(.headRefName) +\\(.additions)\u002F-\\(.deletions) files=\\(.changedFiles)\"'\n\n# 2. Verify the existing PR covers the issue\ngh pr view \u003CN> --repo \u003COWNER>\u002F\u003CREPO> --json body \\\n  --jq '.body' | grep -E \"\u003Cissue-number|keywords>\"\n```\n\n**Decision matrix:**\n\n| Existing PR state | Action |\n|---|---|\n| 0 matches | Normal flow — open new PR from a fresh branch off `origin\u002Fmain` |\n| 1 match, covers the issue | Iterate on its branch: `git worktree add -b \u003Ctopic>-improvements \u003Cpath> origin\u002F\u003Cexisting-branch>`, push commits there, comment on the PR instead of opening a new one |\n| 1 match, but unrelated (false positive) | Normal flow — open new PR |\n| ≥2 matches | Load `dispatch-task` skill to triage which is canonical |\n\n**Verified case 2026-07-12, jleechanorg\u002Fmerge_train issue #42:** PR #41 (`fix\u002Fpretooluse-approve-decision`) was already open with the same bug fix — Codex-driven, CI green, CodeRabbit APPROVED, 5 days unmerged. The natural Phase 2 reflex was \"open a new PR\". The user pushed back: *\"iterate on PR #41 — do NOT open a duplicate PR (pr-quantity-control: iterate, don't proliferate)\"*. I created `work\u002Fpr41-improvements` branched off `origin\u002Ffix\u002Fpretooluse-approve-decision`, pushed improvements there. No duplicate PR; the existing PR gets the better fix on its existing branch.\n\n## Push onto existing PR's headRefName from a separate worktree (added 2026-07-14)\n\nWhen you don't own the existing PR (someone else authored it, or an automated worker has been pushing commits) and your task is \"add these changes to that PR\", the recipe is:\n\n1. **Resolve the PR head branch** — `gh pr view \u003CN> --repo \u003COWNER>\u002F\u003CREPO> --json headRefName,headRepository` (NEVER guess; the user might rename it).\n2. **Create a worktree tracking that exact branch** — `git -C \u003CREPO> worktree add -B \u003Cmy-topic-branch> \u003CWORKTREE_PATH> origin\u002F\u003CheadRefName>`. Use `-B` (force-create) rather than `-b` (fail if exists) since the worktree is fresh.\n3. **Commit on your topic branch** — `git -C \u003CWT> add \u003Cpaths>` (path-scoped, NEVER `git add -A` if there's any chance of foreign staged work) → `git -C \u003CWT> commit -m \"...\"`.\n4. **Push onto the PR head ref** — `git -C \u003CWT> push origin HEAD:refs\u002Fheads\u002F\u003CheadRefName>`. This adds your commit ON TOP of the existing PR's head, so the PR's UI shows it as a new commit and reviewers see it as part of the same PR — no parallel PR, no merge queue contention.\n5. **Verify** — `git -C \u003CWT> rev-parse origin\u002F\u003CheadRefName>` returns your new SHA. Note: `gh pr view \u003CN> --json head_sha` may show a stale SHA (the PR cache lags the push by ~30s); the local `git rev-parse origin\u002F\u003CheadRefName>` is authoritative.\n\n**The trap:** the natural instinct when you don't own a branch is `git worktree add -b \u003Cnew> origin\u002Fmain`, then `git push origin \u003Cnew>`, then open a new PR. That creates the duplicate PR `finish-the-job` v1.11.0 + `always-pr-never-local-edit` v1.1.0 \u002F v1.2.0 all warn against. The \"push onto existing headRefName\" pattern avoids the duplication entirely.\n\n**Verified case 2026-07-14, jleechanorg\u002Fclaude-commands PR #321:** PR #321 (`fix: launch real Sonnet Claude teams via tmux`, head `fix\u002Freal-claude-team-tmux`, owned by another actor with 670k LOC \u002F 3001 files changed) already had the canonical surface for sidekick + swarm + test_real_claude_team_contract. A 5-minute checkpoint cadence contract was needed on the same files. The recipe: created `~\u002F.worktrees\u002Fcc-pr321-checkpoint` tracking `origin\u002Ffix\u002Freal-claude-team-tmux` (NOT `origin\u002Fmain`), committed the contract on `fix\u002Fsidekick-5min-checkpoint-pr321`, pushed with `git push origin HEAD:refs\u002Fheads\u002Ffix\u002Freal-claude-team-tmux`. The push landed: `286311a97..7c5031623` on `fix\u002Freal-claude-team-tmux`. Two commits (`7c5031623` initial + `1a43307a0` \u002Fadvice Round 2 tightening) now sit on top of the existing PR's head. No parallel PR; reviewers see the contract changes as additional commits on PR #321.\n\n**Anti-pattern:** `git worktree add -b docs\u002Fsidekick-5min-checkpoint origin\u002Fmain` + opening a new PR. This creates the duplicate PR problem `always-pr-never-local-edit` v1.1.0 was designed to prevent.\n\n## Worktree-silent-edit trap — when the worktree has no .\u002Fvenv\u002F (added 2026-07-18)\n\nWhen you create a fresh `git worktree add -b \u003Cbranch> origin\u002Fmain` for a PR, the worktree has the source files but **does NOT have `.\u002Fvenv\u002F`** (the Python venv lives only in the main checkout). When you `cd` to the worktree to `patch` prompt files \u002F write tests, you can't run `pytest` (no venv). The reflex: `cd $HOME\u002Fprojects\u002F\u003Cmain>` to use the venv, then keep editing — except now your `patch` and `cp` commands write to the **main checkout**, not the worktree.\n\nThe trap: **there is NO error message.** `patch` succeeds (file exists in main checkout too), `pytest` runs (venv is in main checkout), tests pass (because the file is correct). The edits look correct in the test run, but they were applied on a different branch than the PR branch. The PR commits land on whatever branch the main checkout is on, not on the worktree's `fix\u002F\u003Ctopic>` branch.\n\n**Detection heuristic (mandatory after every patch on a worktree):**\n\n```bash\n# After EVERY patch, run BOTH status commands:\ncd $HOME\u002Fprojects\u002Fwt-\u003Ctopic>\ngit status --short          # MUST show the patched files\ngit rev-parse --abbrev-ref HEAD   # confirm branch is what you think\n\ncd $HOME\u002Fprojects\u002F\u003Cmain-checkout>\ngit status --short          # MUST be empty after a worktree-local edit\n```\n\nIf the main checkout shows the file as modified, the patch landed in the wrong place.\n\n**Recipe for staying in the worktree (when you need the venv):**\n\nThe worktree's tests can run with the main checkout's venv via absolute path:\n\n```bash\ncd $HOME\u002Fprojects\u002Fwt-\u003Ctopic>\n# Use the main checkout's venv explicitly — patches still write to the worktree\n\u002Fpath\u002Fto\u002F\u003Cmain-checkout>\u002Fvenv\u002Fbin\u002Fpython -m pytest $PROJECT_ROOT\u002Ftests\u002F\u003Ctest>.py -v\n\n# OR copy test file to the main checkout's tests dir, run, then revert\ncp $PROJECT_ROOT\u002Ftests\u002F\u003Ctest>.py $HOME\u002Fprojects\u002F\u003Cmain>\u002F$PROJECT_ROOT\u002Ftests\u002F\u003Ctest>.py\nTESTING_AUTH_BYPASS=true $HOME\u002Fprojects\u002F\u003Cmain>\u002Fvenv\u002Fbin\u002Fpython -m pytest $PROJECT_ROOT\u002Ftests\u002F\u003Ctest>.py -v\n# Verify, then revert the main checkout's tests dir (NOT the worktree's)\ncd $HOME\u002Fprojects\u002F\u003Cmain>\ngit checkout -- $PROJECT_ROOT\u002Ftests\u002F\u003Ctest>.py\n```\n\nThe second pattern is safer because it leaves the test file under your natural test-discovery rootdir (the main checkout's `$PROJECT_ROOT\u002Ftests\u002F`).\n\n**Recovery if you've already shipped the edit to the wrong branch:**\n\n```bash\n# 1. Confirm the wrong-branch symptom\ncd $HOME\u002Fprojects\u002F\u003Cmain>\ngit status --short                # shows the file as modified here\n\n# 2. Revert the main checkout (so it stays clean)\ncd $HOME\u002Fprojects\u002F\u003Cmain>\ngit checkout -- \u003Cfile-path>\n\n# 3. Copy the file to the worktree\ncp \u003Cfile-path> $HOME\u002Fprojects\u002Fwt-\u003Ctopic>\u002F\u003Cfile-path>\n\n# 4. Verify the worktree now has it\ncd $HOME\u002Fprojects\u002Fwt-\u003Ctopic>\ngit status --short                # MUST show \u003Cfile> as modified\n\n# 5. Verify the main checkout is clean\ncd $HOME\u002Fprojects\u002F\u003Cmain>\ngit status --short                # MUST be empty\n```\n\n**Verified case 2026-07-18, $GITHUB_REPOSITORY PR #8446:** the prompt edits (`$PROJECT_ROOT\u002Fprompts\u002Fplanning_protocol.md` + `$PROJECT_ROOT\u002Fprompts\u002Fnarrative_system_instruction.md`) and the new test file (`$PROJECT_ROOT\u002Ftests\u002Ftest_planning_block_canonical_state_anchor_8444.py`) all landed in the main checkout first (no error). The main checkout was on branch `docs\u002Fbq-cost-spike-2026-07-08-findings`; the worktree was on `fix\u002Faegon-rejoin-co-presence-8444`. Caught via `git status --short` on both directories. ~3 tool calls wasted. Without the dual-status check, the PR would have shipped on `docs\u002Fbq-cost-spike-2026-07-08-findings`, NOT on the intended `fix\u002Faegon-rejoin-co-presence-8444` branch — and the PR number would have referenced a docs branch instead of the fix branch.\n\n**Cross-reference:** skill `repro` §\"Git worktree pitfall → Worktree-silent-edit trap\" and `references\u002Fprompt-fix-deliverable-shape-2026-07-18.md` §\"Pitfall 1 — Edits landed in the wrong checkout (silent failure)\" for the full recipe and a parallel example.\n\n## Bidirectional command pointer pattern — user-scope vs repo-local (added 2026-07-14)\n\nWhen a slash command exists in BOTH `~\u002F.claude\u002Fcommands\u002F\u003Cname>.md` (user-scope, mounted from `jleechanorg\u002Fclaude-commands`) AND `\u003Cproduct-repo>\u002F.claude\u002Fcommands\u002F\u003Cname>.md` (repo-local), the two files MUST form a **bidirectional pointer contract**:\n\n**User-scope contract (lives in `~\u002F.claude\u002Fcommands\u002F\u003Cname>.md`):**\n1. Stays **project-agnostic** — no hardcoded paths to a specific product repo.\n2. Documents that any repo-local `.claude\u002Fcommands\u002F\u003Cname>.md` MAY override specific lanes (e.g. add `\u002Fthermo` lane) but MUST inherit the 4 user-scope lanes (ponytail, ZFC, ZFC leveling, root-cause-first).\n3. **Reciprocal pointer** — explicit \"If a repo-local file exists at `\u003Crepo>\u002F.claude\u002Fcommands\u002F\u003Cname>.md`, that file MUST also be loaded; load both.\"\n\n**Repo-local contract (lives in `\u003Cproduct-repo>\u002F.claude\u002Fcommands\u002F\u003Cname>.md`):**\n1. **Top-of-file rule**: \"MUST be loaded along with `~\u002F.claude\u002Fcommands\u002F\u003Cname>.md`\" as the first line after the YAML frontmatter.\n2. Defines repo-specific behavior (e.g. `\u002Fthermo` lane, `\u002Fes` evidence rule) without forking the 4 user-scope lanes.\n3. **Reciprocal pointer** back to `~\u002F.claude\u002Fcommands\u002F\u003Cname>.md` documenting which lanes are added vs. inherited.\n\n**Verified case 2026-07-14 (jleechanorg\u002Fclaude-commands PR #328 + $GITHUB_REPOSITORY PR #8402):** the `\u002Fcode-standards` command existed in both locations but the user-scope copy was worldarchitect-flavored (referenced the worldai repo as the canonical) and the worldai copy didn't have the reciprocal \"load user-scope\" rule. Both rewrites land in their respective repos via PR #328 and PR #8402.\n\n**The trap:** writing one copy of the command and assuming it'll be loaded consistently across repos. Repo-local Claude agents load the user-scope command by default but DO NOT auto-load a sibling file at `\u003Crepo>\u002F.claude\u002Fcommands\u002F\u003Cname>.md` unless the user-scope file (or the agent's harness) explicitly says \"also load the repo-local counterpart.\"\n\n**Recipe for authoring a new bidirectional command:**\n\n1. **User-scope side first** (in `jleechanorg\u002Fclaude-commands` worktree, branch off `origin\u002Fmain`):\n   - Write the project-agnostic command at `.claude\u002Fcommands\u002F\u003Cname>.md`.\n   - Add a `## Bidirectional pointer contract` section that lists the 5 rules above.\n   - Open PR against `jleechanorg\u002Fclaude-commands`.\n2. **Repo-local side** (in `\u003Cproduct-repo>` worktree, branch off `origin\u002Fmain`):\n   - Write the repo-specific overlay at `.claude\u002Fcommands\u002F\u003Cname>.md`.\n   - Add the \"MUST be loaded along with `~\u002F.claude\u002Fcommands\u002F\u003Cname>.md`\" rule at the top.\n   - Add a `## Bidirectional contract` section that documents which lanes are added vs. inherited.\n   - Open PR against `\u003Cproduct-repo>`.\n3. **Both PRs MUST reference each other** in the PR description (one sentence: \"Paired with PR #N in \u003Cother-repo>\").\n4. **For commands that exist in `~\u002F.claude\u002Fcommands\u002F` but are wholly repo-specific** (e.g. `end2end-testing.md`, `benchg-ts.md`, `worldai-usage-email.md`), add a `> Worldai-only command. \u003Cdescription>.` banner block at the top, then a `## Repo-local counterpart` section pointing at `\u003Cproduct-repo>\u002F.claude\u002Fcommands\u002F\u003Cname>.md`. Do NOT remove the user-scope file — leave the banner so anyone running the command from outside the product repo sees the scope warning.\n5. **Create the repo-local pointer file** in `\u003Cproduct-repo>\u002F.claude\u002Fcommands\u002F` (thin YAML frontmatter + 2-3 line pointer back to the user-scope command) so the product repo has a complete command surface.\n\n**Why two repos, not one:** the user-scope `~\u002F.claude\u002Fcommands\u002F` is shared across ALL `jleechanorg\u002F*` repos via the `jleechanorg\u002Fclaude-commands` worktree. The repo-local `\u003Cproduct-repo>\u002F.claude\u002Fcommands\u002F` is loaded only when the agent is invoked from inside that product repo. Splitting them lets the same command have different lane sets per repo without forking the user-scope copy.\n\n## Cross-repo pre-flight — find the right repo before opening the PR (added 2026-07-13)\n\nBefore opening a new PR, confirm the change belongs in the repo you're targeting. Recurring alerts and cross-cutting tools often live in a different repo than the product code they monitor. Opening the PR in the wrong repo means the worktree, CI, reviewers, and reviewer-bot signals all run against the wrong context.\n\n**The trap:** when handling an alert like \"X is broken in production,\" the natural instinct is to find the repo named in the alert and open a PR there. But if the alert is fired by a *watcher* script, the fix often belongs in the watcher's repo, not the watched repo. Watcher scripts, AO infra, and Hermes tooling live in `jleechanorg\u002Fjleechanclaw`. Product code lives in `$GITHUB_REPOSITORY`. Hermes skills live in `~\u002F.hermes\u002Fskills\u002F`. Mixing these up means the PR's diff doesn't match the target repo's CI matrix.\n\n**Recipe (run BEFORE `git worktree add -b \u003Cnew>`):**\n\n```bash\n# 1. Identify the source of the alert\n#    - bot\u002Fcron watcher alert? Check ~\u002F.hermes\u002Fscripts\u002F for the script name\n#    - GitHub Action failure? Check the workflow file's repo + path\n#    - Slack message about a service? Trace the alert source to its origin\n\n# 2. List candidate repos for the fix\ngh api 'orgs\u002Fjleechanorg\u002Frepos?per_page=100&sort=updated' \\\n  --jq '.[] | \"\\(.name) \\(.description \u002F\u002F \"\")\"' | head -30\n\n# 3. For each candidate repo, run a quick `git grep` from the terminal to find\n#    the file the fix belongs in. The repo where the file lives = the PR target.\ngh -C ~\u002Frepos\u002F\u003Ccandidate> ls-files | grep -E \"\u003Crelevant-keyword>\"\n\n# 4. Verify the fix's natural reviewer set matches the target repo\ngh api repos\u002F\u003Cowner>\u002F\u003Crepo>\u002Fcontents\u002F.github\u002FCODEOWNERS --jq '.content' | base64 -d\n```\n\n**Verified case 2026-07-13, jleechanclaw #774 (recurring `is_test IS NULL` alert):** The MCP Agent Mail alert fired in `C0BCVG4F560` about Gemini rows with `is_test IS NULL`. Natural reflex: open PR in `your-project.com` where the BQ data lives. Correct target: `jleechanorg\u002Fjleechanclaw` — the watcher script `scripts\u002Fbq_coverage_watcher.py` lives there, and the watcher alert logic is what needs fixing (the underlying bug was already fixed in `your-project.com` #8351). PR-topology pre-flight found:\n- `your-project.com` #8070 — open, wrong shape (the original 1264-line \"add backfill + lock\" attempt, superseded by #8351)\n- `your-project.com` #8351 — merged, the actual root-cause fix\n- The right target for the new work was `jleechanorg\u002Fjleechanclaw` because the watcher alerting logic (which is what needs updating to stop firing false positives) lives there.\n\n**Anti-pattern:** Opening the PR in the \"alarmed repo\" by default. Always trace the alert source to its origin repo before opening the PR.\n\n## Wind-down checkpoint — the WIP-pushed end-state (added 2026-07-12)When the user explicitly says they are pausing \u002F restarting \u002F the session must end NOW (e.g. \"WIND-DOWN: Jeff is restarting\", \"checkpoint NOW\", \"stop and report state\"), the right end-state is **WIP-pushed to a working branch, NOT merged**. This is a fifth valid end-state alongside the four in `finish-the-job`'s Contract.\n\n**The recipe:**\n\n1. **Commit all work** (WIP is fine — even partial code + tests is OK if the commit message is honest about state). Include any untracked files via `git add -A` so the diff matches what was in flight.\n2. **Push to the working branch** — never to `main` and never to a \"canonical\" branch the user didn't designate. Use the worktree's tracking branch: `git push -u origin \u003Cbranch>`.\n3. **Reply in the thread with three lines, in this exact order:**\n   - Branch name (full `origin\u002F\u003Cbranch>`)\n   - Pushed SHA (`git rev-parse HEAD`)\n   - `git status --porcelain` output (must be empty)\n4. **Do NOT merge anything during wind-down.** Even if the PR is technically green, `gh pr merge` requires the user's deliberate go-ahead — not a session-end reflex.\n5. **State what is unfinished** in the same reply so the next session can resume without re-deriving context: known-failing tests, unmerged PRs, unclosed beads, unverified repro commands, etc.\n\n**Verified case 2026-07-12, jleechanorg\u002Fmerge_train PR #41 follow-up:** the user sent \"WIND-DOWN: Jeff is restarting the computer shortly. Please checkpoint NOW\" mid-task. I had partial code + 3 failing tests + a WIP commit ready but not pushed. The right move was `git add -A && git commit -m \"WIP(hooks): issue #42 — ...\" && git push -u origin work\u002Fpr41-improvements`, then reply with branch + SHA + empty `git status --porcelain`, then pause. Did NOT touch `main`, did NOT merge PR #41, did NOT touch `~\u002F.local\u002Fbin\u002Fconflict-warn-pre-tool.sh` (left byte-identical for the next session to deploy after the merge).\n\n**Anti-patterns:**\n\n- ❌ \"I'll keep working until the end\" — the user's wind-down is a hard stop. Keep working past it is an autonomy violation.\n- ❌ Pushing a partial commit to `main` to \"save it\" — the user will merge to `main` deliberately, and seeing unverified code on `main` is worse than losing the WIP.\n- ❌ A reply that says \"still working, will continue after restart\" without the branch\u002FSHA\u002Fporcelain — the next session can't resume without that information.\n- ❌ Merging a green-looking PR during wind-down without `MERGE APPROVED` — the merge gate is the user's, not the agent's.\n\n## Worktree test-import via `Path.home()` quirk (added 2026-07-15)\n\nSome test files import the source via an absolute path under `Path.home()` rather than a path relative to the test file. Concretely, `scripts\u002Ftests\u002Ftest_bq_coverage_watcher.py` does:\n\n```python\nWATCHER_PATH = Path.home() \u002F \".hermes\" \u002F \"scripts\" \u002F \"bq_coverage_watcher.py\"\nspec = importlib.util.spec_from_file_location(\"bq_coverage_watcher\", WATCHER_PATH)\n```\n\nWhen you `git worktree add` and patch the watcher in the worktree, `pytest` does NOT pick up the worktree copy — it runs against `~\u002F.hermes\u002Fscripts\u002Fbq_coverage_watcher.py` (the deployed prod copy). All \"new wording\" tests fail with confusing messages like `assert \"Remediation:\" in msg` against a deployed file that doesn't contain `Remediation:`.\n\n**The trap:** you edit in the worktree, see green tests in your head, run `pytest`, get 4 failures, and assume your patch is wrong. The patch is fine — the test is loading the wrong module.\n\n**The work-around (run once per test run, then restore before commit):**\n\n```bash\n# 1. Save the deployed copy for restore\ncp ~\u002F.hermes\u002Fscripts\u002F\u003Cwatcher>.py ~\u002F.hermes\u002Fscripts\u002F\u003Cwatcher>.py.bak-$(date +%s)\n\n# 2. Copy the patched worktree version into the import-target path\ncp \u002Ftmp\u002F\u003Crepo>-\u003Ctopic>\u002Fscripts\u002F\u003Cwatcher>.py ~\u002F.hermes\u002Fscripts\u002F\u003Cwatcher>.py\n\n# 3. Run pytest from anywhere — tests pick up the patched file\npython3 -m pytest \u002Ftmp\u002F\u003Crepo>-\u003Ctopic>\u002Fscripts\u002Ftests\u002Ftest_\u003Cwatcher>.py -v\n\n# 4. ALWAYS restore before commit, otherwise the local deploy drifts from main\nmv ~\u002F.hermes\u002Fscripts\u002F\u003Cwatcher>.py.bak-$(date +%s) ~\u002F.hermes\u002Fscripts\u002F\u003Cwatcher>.py\n```\n\n**Detection heuristic:** if a test fails on a substring your patch obviously adds (e.g. fails on `assert \"Remediation:\" in msg` when your patch literally added the string `Remediation:`), run `grep -n \"\u003Csubstring>\" ~\u002F.hermes\u002Fscripts\u002F\u003Cwatcher>.py` BEFORE the patch and AFTER the patch. If neither matches, the test is loading a different file. Use the work-around above.\n\n**Verified case 2026-07-15, jleechanorg\u002Fjleechanclaw#781:** first test run had 4\u002F11 failures with `assert \"$PROJECT_ROOT\u002Fbq_logging.py\" in msg` style errors. The patched file did contain the string; the test was loading the deployed 511-line copy that didn't have the new text. Work-around applied; 11\u002F11 green; deployed file restored before commit. Without this trap-recognition, ~3 tool calls wasted re-reading the patch.\n\n**Cross-reference:** skill `verify-telemetry-alert` Step 3a.1 (the same work-around appears in Step 5 of that recipe).\n\n## Local `git fetch` auth-block work-around for jleechanclaw (added 2026-07-15)\n\n`git fetch origin main` in `jleechanorg\u002Fjleechanclaw` (and most `jleechanorg\u002F*` repos) fails with `Authentication failed for 'https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechanclaw.git\u002F'` even when `gh auth status` shows a working `jleechan2015` account. Root cause: the `origin` remote URL contains a truncated\u002Fplaceholder token (`x-access-token:ghp_yg....git`) that no longer authenticates.\n\n**Symptoms:**\n```\n$ git fetch origin main\nremote: Invalid username or token. Password authentication is not supported for Git operations.\nfatal: Authentication failed\n```\n\n**Work-around recipe:**\n\n```bash\n# 1. Reset origin to the clean public URL (no embedded placeholder token)\ncd \u003Cworktree>\ngit remote set-url origin https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002F\u003Crepo>.git\n\n# 2. Force the gh-credential helper explicitly (the global gitconfig helper may be empty in worktrees)\ngit -c credential.helper='$HOME\u002F.local\u002Fbin\u002Fgh.real auth git-credential' \\\n    fetch origin main\n\n# 3. Confirm fetch succeeded\ngit rev-parse origin\u002Fmain  # should now show the post-#774 SHA, not the stale one\n```\n\n**Why `gh auth setup-git` alone doesn't fix it:** it sets up the credential helper, but `git fetch` still uses the URL configured in `.git\u002Fconfig` for that specific remote. If that URL is broken, no helper resolves it. The two-step fix is mandatory.\n\n**Verified case 2026-07-15, jleechanorg\u002Fjleechanclaw#781:** first fetch failed with `Authentication failed`. `gh auth setup-git` returned silently. After `git remote set-url origin https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechanclaw.git` + explicit `gh.real auth git-credential`, fetch succeeded; `git rev-parse origin\u002Fmain` jumped from stale `1a8c5aef` to post-#774 `99cb779`.\n\n## Dirty-checkout pre-flight — refuse to dispatch onto a dirty or conflicted worktree (added 2026-07-28)\n\nBefore dispatching a worker (ao spawn \u002F claudem \u002F opencode) onto an existing checkout, **scan every candidate worktree + the main checkout for clean state**. A \"clean\" worktree is one where `git status --short` returns empty AND there are no merge\u002Frebase conflicts. Dispatching onto a dirty worktree silently mixes your PR's commits with someone else's WIP, and dispatching onto a conflicted worktree (state `UU` \u002F `AA` \u002F `DD` rows in `git status --short`) makes the worker's first patch land on top of an unresolved merge — a guarantee the next rebase or merge will produce conflicts the agent never saw.\n\n**Recipe (run BEFORE `git worktree add` OR before reusing an existing worktree):**\n\n```bash\n# 1. List ALL candidate worktrees for the repo (main + every entry under ~\u002F.worktrees\u002F, ~\u002Fprojects\u002F, ~\u002Frepos\u002F)\ngh repo list jleechanorg --json nameWithOwner --jq '.[].nameWithOwner' \\\n  | xargs -I{} sh -c 'printf \"%s\\n\" \"{}\"' 2>\u002Fdev\u002Fnull | head\n\n# For each candidate, get status\nfor wt in ~\u002Fprojects\u002F\u003Crepo> ~\u002Frepos\u002Fjleechanorg\u002F\u003Crepo> ~\u002F.worktrees\u002F*\u002F\u003Crepo> 2>\u002Fdev\u002Fnull; do\n  if [ -d \"$wt\" ]; then\n    echo \"=== $wt ===\"\n    git -C \"$wt\" rev-parse --abbrev-ref HEAD 2>\u002Fdev\u002Fnull\n    git -C \"$wt\" rev-parse --abbrev-ref --symbolic-full-name @{u} 2>\u002Fdev\u002Fnull\n    git -C \"$wt\" status --short --branch 2>\u002Fdev\u002Fnull | head -30\n  fi\ndone\n```\n\n**Decision matrix:**\n\n| Worktree state | Action |\n|---|---|\n| `git status --short` returns empty | Safe to dispatch — worktree is clean. |\n| `git status --short` shows only `M` \u002F `A` \u002F `??` on the planned-PR's intended files | Safe to dispatch — the dirt is the worker's intended changes. Confirm with the user. |\n| `git status --short` shows `UU` \u002F `AA` \u002F `DD` (merge conflicts) | **DO NOT dispatch.** Resolve the conflicts first (`git status --short` to identify files, `git checkout --theirs\u002F--ours \u003Cfile>` or manual edit, then `git add` + `git commit` if needed). |\n| `git status --short` shows unrelated modified files (e.g. `.beads\u002Fissues.jsonl`, unrelated `.py` files, `wt-\u003Cother-topic>\u002F`) | **DO NOT dispatch.** The agent's first `git add` + commit will accumulate that dirt onto the new PR's branch. Either `git checkout -- \u003Cunrelated-file>` to drop, or pick a different worktree, or `git worktree add -B \u003Cnew-topic> \u003Cwt-path> origin\u002Fmain` for a fresh-clean branch. |\n| No worktree exists OR all candidate worktrees are dirty | **Create a fresh worktree from `origin\u002Fmain`:** `git worktree add -B \u003Ctopic>-\u003Cshort-hash> \u003Cpath> origin\u002Fmain`. Do NOT edit in the main checkout. |\n\n**Why this matters even when the worker runs in its own sandboxed worktree:** many coding agents (claudem \u002F opencode \u002F Codex) accept a `--workdir` flag but still inherit the user's `.gitconfig`, GitHub auth tokens, and IDE state. If the agent's first action is `git status` and the working tree is dirty, the agent may either (a) silently commit on top of unrelated changes, or (b) refuse to commit and ask the user to clean up — neither outcome is acceptable for a one-shot dispatch.\n\n**Anti-pattern:** picking the most-recently-touched worktree under `~\u002F.worktrees\u002F` because \"it was used recently, must be safe.\" Recent activity is not the same as clean state. Always run `git status --short` first; never trust `mtime` or branch-name familiarity.\n\n**Verified case 2026-07-28, $GITHUB_REPOSITORY:** the available worktrees were:\n- `~\u002Fprojects\u002Fyour-project.com` — on branch `pr8399-w2verify`, 3 modified files (`.beads\u002Fissues.jsonl`, `analysis\u002Fcampaign_analysis_sariel_v2.json`, `analysis\u002Fcampaign_snapshot_sariel_v2.json`), 2 modified `$PROJECT_ROOT\u002F*.py`, multiple untracked files (`repro-ta[REDACTED_OPENAI_KEY]`, `specs\u002Fskeptic-report.json`, etc.) → **dirty, do NOT dispatch**\n- `~\u002Frepos\u002F$GITHUB_REPOSITORY` — on branch `fix\u002Fcron-exit-semantics-and-oom-watchdog`, **unresolved merge conflicts** (`UU .claude\u002Fcommands\u002Fcode-standards.md`), 1 modified file → **conflicted, do NOT dispatch**\n- No clean worktree available → the right move was to create a fresh worktree from `origin\u002Fmain` before dispatching the claudem worker.\n\nThe lesson: scanning for clean state is the worktree equivalent of `git fetch origin` before push — a 5-second check that prevents a 30-minute cleanup. Add it to every dispatch workflow.",{"name":5,"version":57,"changelog":58,"description":7},"1.6.0",[59,60,61,62,63,64],"1.6.0 (2026-07-28): New section 'Dirty-checkout pre-flight — refuse to dispatch onto a dirty or conflicted worktree'. Before any claudem \u002F ao \u002F opencode \u002F Codex dispatch, scan every candidate worktree + the main checkout for clean state. Dispatching onto a dirty worktree silently mixes your PR's commits with someone else's WIP; dispatching onto a conflicted worktree (`UU`\u002F`AA`\u002F`DD` rows in `git status --short`) makes the worker's first patch land on top of an unresolved merge. Verified 2026-07-28 on $GITHUB_REPOSITORY: the available main checkout had 3 modified `analysis\u002F*` files + 2 modified `$PROJECT_ROOT\u002F*.py` + multiple untracked files (dirty); the alternate checkout had unresolved `UU .claude\u002Fcommands\u002Fcode-standards.md` (conflicted). Both are no-go; correct move is `git worktree add -B \u003Ctopic> \u003Cpath> origin\u002Fmain` for a fresh clean branch.","1.5.0 (2026-07-18): New section 'Worktree-silent-edit trap — when the worktree has no .\u002Fvenv\u002F' covering the dual-CWD silent failure where `patch` or `cp` from the wrong CWD lands edits in the main checkout instead of the worktree, with NO error message. Verified on $GITHUB_REPOSITORY PR #8446 (2026-07-18, SHA 4524525569692db3e5a5b36a818a7248b65fae09): the prompt edits + test file landed in the main checkout (on branch `docs\u002Fbq-cost-spike-2026-07-08-findings`) instead of the worktree's `fix\u002Faegon-rejoin-co-presence-8444` because the worktree had no `.\u002Fvenv\u002F` and I `cd`'d to the main checkout to run `pytest`. Detection heuristic: after every `patch` on a worktree, run `git status --short` on BOTH the worktree AND the main checkout — the main checkout MUST be empty. Recovery recipe: `cp` the file to the worktree, `git checkout -- \u003Cfile>` in the main checkout to revert, then verify with the dual-status check. Cross-references skill `repro` §'Git worktree pitfall → Worktree-silent-edit trap' and `references\u002Fprompt-fix-deliverable-shape-2026-07-18.md` §Pitfall 1.","1.4.0 (2026-07-15): Two new sections. (a) 'Worktree test-import via Path.home() quirk' — when a test file imports the source via `Path.home() \u002F '.hermes' \u002F 'scripts' \u002F '\u003Cwatcher>.py'` instead of a worktree-relative path, pytest runs against the deployed prod copy and all new-wording tests fail with confusing substring errors. The 4-step temp-copy\u002Frestore work-around plus a detection heuristic. Verified on jleechanorg\u002Fjleechanclaw#781 (first test run had 4\u002F11 failures, all false alarms). (b) 'Local git fetch auth-block work-around for jleechanclaw' — `git fetch origin main` fails with `Authentication failed` because the `origin` URL contains a truncated placeholder token (`x-access-token:ghp_yg....git`). `gh auth setup-git` alone doesn't fix it. The two-step fix: `git remote set-url origin https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002F\u003Crepo>.git` + explicit `'$HOME\u002F.local\u002Fbin\u002Fgh.real auth git-credential'` helper.","1.3.0 (2026-07-14): New section 'Bidirectional command pointer pattern — user-scope vs repo-local' with the 5-rule user-scope contract, repo-local contract, recipe for authoring a new bidirectional command, and the verified case (jleechanorg\u002Fclaude-commands PR #328 + $GITHUB_REPOSITORY PR #8402). Covers the cross-repo discipline when a slash command exists in BOTH ~\u002F.claude\u002Fcommands\u002F\u003Cname>.md (user-scope, mounted from jleechanorg\u002Fclaude-commands) AND \u003Cproduct-repo>\u002F.claude\u002Fcommands\u002F\u003Cname>.md (repo-local).","1.2.0 (2026-07-13): Added 'Cross-repo pre-flight — find the right repo before opening the PR'. Recurring-alert pattern lesson from MCP Agent Mail `is_test IS NULL` watcher (jleechanclaw #774): the watcher script lives in jleechanorg\u002Fjleechanclaw, the BQ data lives in your-project.com — opening the PR in the wrong repo wastes a worktree. Recipe: trace the alert source to its origin repo before opening the PR.","1.1.0 (2026-07-12): Added two new sections. (a) 'PR-topology pre-flight — iterate, don't proliferate': when handed a bug-fix task, check `gh pr list` for an existing PR covering the same issue BEFORE opening a new one; push improvements to the existing branch instead. Verified on merge_train #42 where PR #41 already covered the same fix. (b) 'Wind-down checkpoint — the WIP-pushed end-state': when the user signals immediate pause\u002Frestart, the right end-state is WIP commit + push to working branch + reply with branch\u002FSHA\u002Fempty `git status --porcelain`. Do NOT merge, do NOT push to `main`, do NOT touch deploy surfaces.","main","05df7380981a2c4af868ce0fa57962ae0eea62a9","hermes\u002Fskills\u002Fworkflow\u002Falways-pr-never-local-edit",0,"https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills","https:\u002F\u002Fgithub.com\u002Fjleechanorg","2026-11-14 14:55:35",{"source":8,"skillName":5,"commands":73,"prompt":83,"zipAvailable":84},[74,77,80],{"tool":75,"command":76},"npx","npx skills add jleechanorg\u002Fjleechan-skills --skill always-pr-never-local-edit",{"tool":78,"command":79},"bunx","bunx skills add jleechanorg\u002Fjleechan-skills --skill always-pr-never-local-edit",{"tool":81,"command":82},"pnpm","pnpm dlx skills add jleechanorg\u002Fjleechan-skills --skill always-pr-never-local-edit","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002Fhermes\u002Fskills\u002Fworkflow\u002Falways-pr-never-local-edit\u002FSKILL.md",true,[],[87,105,127,139,153,169],{"skillNo":88,"name":89,"nameZh":6,"description":90,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":91,"categories":92,"keywords":93,"publishedAt":52},"01M716Y5MTJ6GYJZ2ATXCJK8G4","instinct","Use when the user invokes \u002Finstinct or \u002Fin, or asks to \"message Instinct\", \"ask Instinct\", \"tell Instinct\", \"check Instinct\", or read replies from the configured peer assistant. iMessage first, WhatsApp Web as fallback.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Finstinct\u002FSKILL.md",[],[89,94,95,96,97,98,99,100,101,102,103,104],"user","when","replies","check","use","identity","whatsapp","gmail","read","message","ask",{"skillNo":106,"name":107,"nameZh":6,"description":108,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":109,"categories":110,"keywords":116,"publishedAt":52},"01M716Y4HF7FVVMJSA2CCVN5VF","hr","Compatibility alias for history-resume; produce the same fresh-state, provenance-aware resume briefing.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fhr\u002FSKILL.md",[111],{"categoryNo":112,"categoryName":113,"taxonomyType":114,"taxonomyTypeDesc":115},"01JBSEEDCAT000000000000038","人力资源","PROFESSION","适用职业",[107,117,118,119,120,121,122,123,124,125,126],"resume","compatibility","provenance","for","history","produce","alias","briefing","state","fresh",{"skillNo":128,"name":129,"nameZh":6,"description":130,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":131,"categories":132,"keywords":134,"publishedAt":52},"01M716Y1FFNFKFJYYKF8HQA6T8","history-resume","Resume briefing for the current repository branch or worktree using fresh state and admitted history sources.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fhistory-resume\u002FSKILL.md",[133],{"categoryNo":112,"categoryName":113,"taxonomyType":114,"taxonomyTypeDesc":115},[121,117,135,44,94,47,124,136,120,137,138,125,126],"history resume","repository","worktree","sources",{"skillNo":140,"name":141,"nameZh":6,"description":142,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":143,"categories":144,"keywords":145,"publishedAt":52},"01M716XWXJ8EPHK4RH9T14TR85","grok","Alias for the canonical grokbot browser conversation workflow; \u002Fgrok talks to the Grok bot the same way \u002Fdot talks to Dot.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fgrok\u002FSKILL.md",[],[141,146,147,148,120,149,123,150,151,152],"dot","bot","workflow","canonical","conversation","browser","grokbot",{"skillNo":154,"name":155,"nameZh":6,"description":156,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":157,"categories":158,"keywords":159,"publishedAt":52},"01M70N9Q07DTE0EW5KFXMMMSJ0","codexa-bench","Compare `codexa` and normal `codex` on a fair split of comparable work by default; use `--strict` for duplicate runs of the exact same task.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fcodexa-bench\u002FSKILL.md",[],[160,161,162,98,163,120,164,165,166,167,168],"codexa bench","work","split","default","duplicate","task","compare","normal","codex",{"skillNo":170,"name":171,"nameZh":6,"description":172,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":173,"licenseFileUrl":174,"sourceHtmlUrl":175,"categories":176,"keywords":186,"publishedAt":52},"01M6C24S2X60SP8BBFGAEKPEGW","frontend-design","Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML\u002FCSS layouts, or when styling\u002Fbeautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Ffrontend-design\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Ffrontend-design\u002FSKILL.md",[177,180,183],{"categoryNo":178,"categoryName":179,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":181,"categoryName":182,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":184,"categoryName":185,"taxonomyType":114,"taxonomyTypeDesc":115},"01JBSEEDCAT000000000000032","设计师",[187,188,189,98,190,191,192,94,193,194,50,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,95,210],"frontend","design","frontend design","generic","ui design","react","html","components","artifacts","ui","aesthetics","Production","web components","landing","applications","quality","web","css","create","examples","with","react components","web ui","pages"]