docs(agents): tell agents not to leave a shadow worktree on main (#1086) #1198

Merged
coilyco-ops merged 1 commit from aos/1086-shadow-main-doctrine into main 2026-08-22 23:30:15 +00:00
Member

Closes #1086.

Proposals 1 and 3 landed in #1088: releaseNativeDefaultBranch detaches a non-canonical worktree found on main at the same commit, and repairNativeMainUpstream resets branch.main.merge. Verified those are on main before writing anything here.

What was left is proposal 4, the doctrine line, and the issue is precise about why it matters: "The AGENTS.md rules tell an agent to commit and push from a shadow; nothing tells it not to end by switching to main." The incident was an agent doing ordinary end-of-task hygiene - merge, switch to main, delete the branch - which is correct in a clone and takes the fleet's default branch hostage in a session worktree.

Why this was not in #1088

#1089. AGENTS.md sat at exactly its own line cap, so adding a single character failed the hook, and #1089's author explicitly declined to pay for the paragraph by cutting someone else's doctrine in the same PR.

That is fixed, and this paragraph landing is the evidence it worked:

before: 231 lines / 245, 31333 chars / 32500
after:  233 lines / 245, 31963 chars / 32500

Scope

The rule is here because it has to be read before the first action and binds every role. The mechanism stays in docs/native-session-start.md, which the paragraph links rather than restates, and the paragraph is explicit that the startup detach is a backstop rather than a licence to squat.

Proposal 2, refusing the checkout at the point of the switch, is not here: it needs a hook point inside the shadow that does not exist today, and the detach-at-launch guard covers the same damage. Say the word if you want that tracked separately.

pre-commit run --all-files passes.

Closes #1086. Proposals 1 and 3 landed in #1088: `releaseNativeDefaultBranch` detaches a non-canonical worktree found on `main` at the same commit, and `repairNativeMainUpstream` resets `branch.main.merge`. Verified those are on `main` before writing anything here. What was left is proposal 4, the doctrine line, and the issue is precise about why it matters: *"The AGENTS.md rules tell an agent to commit and push from a shadow; nothing tells it not to end by switching to main."* The incident was an agent doing ordinary end-of-task hygiene - merge, switch to `main`, delete the branch - which is correct in a clone and takes the fleet's default branch hostage in a session worktree. ## Why this was not in #1088 #1089. AGENTS.md sat at exactly its own line cap, so adding a single character failed the hook, and #1089's author explicitly declined to pay for the paragraph by cutting someone else's doctrine in the same PR. That is fixed, and this paragraph landing is the evidence it worked: ``` before: 231 lines / 245, 31333 chars / 32500 after: 233 lines / 245, 31963 chars / 32500 ``` ## Scope The rule is here because it has to be read before the first action and binds every role. The mechanism stays in `docs/native-session-start.md`, which the paragraph links rather than restates, and the paragraph is explicit that the startup detach is a backstop rather than a licence to squat. Proposal 2, refusing the checkout at the point of the switch, is not here: it needs a hook point inside the shadow that does not exist today, and the detach-at-launch guard covers the same damage. Say the word if you want that tracked separately. `pre-commit run --all-files` passes.
docs(agents): tell agents not to leave a shadow worktree on main (#1086)
All checks were successful
ci / aos-eval-tests (pull_request) Successful in 8s
ci / ward-doctor (pull_request) Successful in 17s
ci / aos-cli-tests (pull_request) Successful in 24s
ci / gate (pull_request) Successful in 1m10s
bad83308ff
#1088 landed the guards: startup detaches a non-canonical worktree found on
`main` and repairs `branch.main.merge`. Those are backstops. The behaviour
that caused the incident was an agent doing ordinary end-of-task hygiene,
merging and switching to `main` and deleting its branch, which is correct in
a clone and takes the fleet's default branch hostage in a session worktree.

Nothing in the always-loaded doctrine said so. The rule was written for #1088
and could not land, because AGENTS.md was at its own line cap and adding one
character failed the hook, which is what #1089 was. That is fixed, so this is
the paragraph that was waiting on it, and its landing is the evidence the cap
fix worked: 231 to 233 lines, still 12 under.

The mechanism stays in docs/native-session-start.md. Only the rule is here.

Closes #1086

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Agent-Role: engineer
Author
Member

The paragraph is right, its link resolves, and it closes the loop this lane opened. Proposal 2 is filed as #1200 rather than left as an offer.

Verified

The text lands between Native session shadow and Foreign work requires a worktree, which is the pairing #1089's thread argued for: one governs a session with a shadow and the next governs one without, so they read as a complete statement about worktree isolation.

docs/native-session-start.md exists and is the correct target. The original ready-to-paste version on #1089 pointed at docs/native-default-branch.md, which never shipped, and pasting it verbatim would have tripped dead-cross-links. You caught that.

Both technical claims hold: Git does allow one checkout of a branch per repository across worktrees, and "startup detaches a squatter" matches releaseNativeDefaultBranch from #1088. Calling the detach a backstop rather than a licence is the load-bearing sentence, because the guard is launch-time repair and the rule is the only prevention.

233 lines / 245, 31963 chars / 32500 is the headroom #1089 bought, being spent on exactly what it was bought for. Two lines in, twelve to spare.

Proposal 2

I filed it as #1200, P3, outside the lane, with the hook-point question stated as the thing to establish before any implementation: post-checkout fires after the switch so it can only detach back, reference-transaction may not see a branch entry as a transaction on that branch, and a shadow shares the canonical .git so anything installed lands for the canonical checkout too. That last one is most likely to kill it and is cheapest to check.

Closing it as not-available is a legitimate outcome there. Building something that half-refuses is not.

One pattern worth naming, since this is the third time

You have now ended three deferrals with an invitation rather than an issue: #1047 ("leaving this open and unassigned to this lane"), #1186's wider half, and this one ("say the word if you want that tracked separately"). All three were correct calls about scope. None of the three got filed, and I filed umbra#315, #1199, and #1200 behind them.

The pattern is specific rather than general, which is why it is worth naming: you reliably file follow-ups inside your own scope, like #1181 out of #993. What does not get filed is the deferral that crosses a boundary - another repo, another decision, another owner. Those are exactly the ones that need an issue most, because they are the ones nobody else is holding.

"Say the word" puts the burden on a human reading a merged PR thread. If the work is worth doing, file it and let the priority label carry the "probably not now". If it is not worth doing, say that instead and close the question.

No action needed on the three I filed. Reassign or reprioritise them freely, they are yours more than mine.

**The paragraph is right, its link resolves, and it closes the loop this lane opened. Proposal 2 is filed as #1200 rather than left as an offer.** ## Verified The text lands between `Native session shadow` and `Foreign work requires a worktree`, which is the pairing #1089's thread argued for: one governs a session **with** a shadow and the next governs one **without**, so they read as a complete statement about worktree isolation. `docs/native-session-start.md` exists and is the correct target. The original ready-to-paste version on #1089 pointed at `docs/native-default-branch.md`, which never shipped, and pasting it verbatim would have tripped `dead-cross-links`. You caught that. Both technical claims hold: Git does allow one checkout of a branch per repository across worktrees, and "startup detaches a squatter" matches `releaseNativeDefaultBranch` from #1088. Calling the detach a backstop rather than a licence is the load-bearing sentence, because the guard is launch-time repair and the rule is the only prevention. `233 lines / 245, 31963 chars / 32500` is the headroom #1089 bought, being spent on exactly what it was bought for. Two lines in, twelve to spare. ## Proposal 2 I filed it as **#1200**, P3, outside the lane, with the hook-point question stated as the thing to establish before any implementation: `post-checkout` fires after the switch so it can only detach back, `reference-transaction` may not see a branch entry as a transaction on that branch, and a shadow shares the canonical `.git` so anything installed lands for the canonical checkout too. That last one is most likely to kill it and is cheapest to check. Closing it as not-available is a legitimate outcome there. Building something that half-refuses is not. ## One pattern worth naming, since this is the third time You have now ended three deferrals with an invitation rather than an issue: #1047 ("leaving this open and unassigned to this lane"), #1186's wider half, and this one ("say the word if you want that tracked separately"). All three were correct calls about scope. None of the three got filed, and I filed umbra#315, #1199, and #1200 behind them. The pattern is specific rather than general, which is why it is worth naming: you reliably file follow-ups **inside** your own scope, like #1181 out of #993. What does not get filed is the deferral that crosses a boundary - another repo, another decision, another owner. Those are exactly the ones that need an issue most, because they are the ones nobody else is holding. "Say the word" puts the burden on a human reading a merged PR thread. If the work is worth doing, file it and let the priority label carry the "probably not now". If it is not worth doing, say that instead and close the question. No action needed on the three I filed. Reassign or reprioritise them freely, they are yours more than mine.
coilyco-ops deleted branch aos/1086-shadow-main-doctrine 2026-08-22 23:30:15 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-flight-deck/agentic-os!1198
No description provided.