Refuse agent-branch commits from a main checkout #119

Open
opened 2026-07-27 15:52:57 +01:00 by vnprc-agent · 1 comment
Contributor

Worktree isolation only holds if agents actually use it, and today nothing stops an agent from running bare git switch -c in a shared checkout — which is how the collision in allod/tools#115 happened, since neither agent invoked allod change at all. Move the rule down to the hook layer so working on an agent branch in a shared checkout is refused rather than merely discouraged.

Part of allod/tools#115. Depends on allod/tools#112.

Primary goals:

  • Refuse agent-branch work in a main checkout — a commit or push on an agent/* branch from a registry checkout is blocked, with a message naming the allod change begin invocation that produces a correct worktree.
  • Leave humans and default branches alone — commits to a repo's default branch in a shared checkout are untouched, so the memory and planning-doc flow and ordinary human work are unaffected.
  • Keep the override a human act — bypassing is standard git commit --no-verify, never a flag the tooling offers, per architecture.md principle 4.
  • Close the enforcement gap, not just the tool gap — the rule has to hold for agents that never call allod change, which is the failure mode actually observed.

Why this depends on allod/tools#112

The hook cannot currently tell where it is. git-hooks/protected-refs-policy:4 resolves the repo as git rev-parse --show-toplevel and :21 derives the lookup key as ${repo#"$HOME"/}, so inside a linked worktree the key is an absolute path that matches nothing. Both path-keyed policy files therefore go silent in a worktree: protected-branches (:21) and signing-required-branches (:35). Signing enforcement disappearing inside a worktree is the more serious half, since a repo whose default branch requires signed pushes loses that guard entirely there.

Worth noting that the same hook already keys two other policies off remote identity — active-pr-branches (:48, used at :174 and :186) and allowed-external-remotes (:62-68) — so allod/tools#112's remote-identity lookup is the established pattern in this file and the path-keyed pair is the outlier. Until that lands, adding a rule that pushes more work into worktrees widens the gap rather than closing it.

Current state

Nothing distinguishes a registry checkout from a linked worktree in the hook, and nothing keys on the agent/ branch prefix. A linked worktree can be identified by git rev-parse --git-common-dir differing from --git-dir, which is also how allod change already resolves repo identity from a worktree.

Scope

In: git-hooks/protected-refs-policy and its tests, covering the refusal, the default-branch pass-through, and the human override. Out: the identity-resolution change itself (allod/tools#112) and worktree creation policy (allod/tools#116).

Worktree isolation only holds if agents actually use it, and today nothing stops an agent from running bare `git switch -c` in a shared checkout — which is how the collision in allod/tools#115 happened, since neither agent invoked `allod change` at all. Move the rule down to the hook layer so working on an agent branch in a shared checkout is refused rather than merely discouraged. Part of allod/tools#115. Depends on allod/tools#112. Primary goals: - **Refuse agent-branch work in a main checkout** — a commit or push on an `agent/*` branch from a registry checkout is blocked, with a message naming the `allod change begin` invocation that produces a correct worktree. - **Leave humans and default branches alone** — commits to a repo's default branch in a shared checkout are untouched, so the memory and planning-doc flow and ordinary human work are unaffected. - **Keep the override a human act** — bypassing is standard `git commit --no-verify`, never a flag the tooling offers, per `architecture.md` principle 4. - **Close the enforcement gap, not just the tool gap** — the rule has to hold for agents that never call `allod change`, which is the failure mode actually observed. ### Why this depends on allod/tools#112 The hook cannot currently tell where it is. `git-hooks/protected-refs-policy:4` resolves the repo as `git rev-parse --show-toplevel` and `:21` derives the lookup key as `${repo#"$HOME"/}`, so inside a linked worktree the key is an absolute path that matches nothing. Both path-keyed policy files therefore go silent in a worktree: `protected-branches` (`:21`) and `signing-required-branches` (`:35`). Signing enforcement disappearing inside a worktree is the more serious half, since a repo whose default branch requires signed pushes loses that guard entirely there. Worth noting that the same hook already keys two other policies off remote identity — `active-pr-branches` (`:48`, used at `:174` and `:186`) and `allowed-external-remotes` (`:62-68`) — so allod/tools#112's remote-identity lookup is the established pattern in this file and the path-keyed pair is the outlier. Until that lands, adding a rule that pushes more work into worktrees widens the gap rather than closing it. ### Current state Nothing distinguishes a registry checkout from a linked worktree in the hook, and nothing keys on the `agent/` branch prefix. A linked worktree can be identified by `git rev-parse --git-common-dir` differing from `--git-dir`, which is also how `allod change` already resolves repo identity from a worktree. ### Scope In: `git-hooks/protected-refs-policy` and its tests, covering the refusal, the default-branch pass-through, and the human override. Out: the identity-resolution change itself (allod/tools#112) and worktree creation policy (allod/tools#116).
Member

The arc's plan, allod/strategy dev-plans/concurrent-agent-workspace.md, is archived; this issue continues on its own. It still depends on allod/tools#112 for the hook's worktree-aware identity lookup. Since the plan was written, allod/tools#118 landed: allod change record now refuses a checkout switched off the branch begin handed out and refuses an unnamed sweep in a main checkout, but a bare git switch -c agent/x plus git commit in a shared checkout still goes through, which is the gap this issue closes at the hook layer. Acceptance from the plan: the refusal, the default-branch pass-through, and a human --no-verify still passing.

The arc's plan, `allod/strategy` `dev-plans/concurrent-agent-workspace.md`, is archived; this issue continues on its own. It still depends on allod/tools#112 for the hook's worktree-aware identity lookup. Since the plan was written, allod/tools#118 landed: `allod change record` now refuses a checkout switched off the branch `begin` handed out and refuses an unnamed sweep in a main checkout, but a bare `git switch -c agent/x` plus `git commit` in a shared checkout still goes through, which is the gap this issue closes at the hook layer. Acceptance from the plan: the refusal, the default-branch pass-through, and a human `--no-verify` still passing.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
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
allod/tools#119
No description provided.