allod change begin: always isolate a branch change in its own worktree #116

Closed
opened 2026-07-27 15:52:56 +01:00 by vnprc-agent · 0 comments
Contributor

allod change begin only creates a worktree for repos listed in protected-branches; for every other repo it hands back the shared checkout path, so two agents changing the same repo work in one tree and move HEAD out from under each other without any warning. Make isolation follow the need for a branch instead of the branch's protection status.

Part of allod/tools#115.

Primary goals:

  • Always isolate when a branch is requestedbegin creates a worktree and an agent/<description> branch for every repo, protected or not, so protected-branches goes back to governing only which branch is protected rather than doubling as the isolation switch.
  • Keep the in-place flow for default-branch commits — an agent committing directly to a repo's default branch keeps working in the shared checkout with no worktree and no added friction, because that is the low-ceremony memory and planning-doc flow and git cannot isolate it anyway.
  • Site worktrees outside the registry projection — place them under ~/changes/<slug>-<description>-XXXXXX so ~/work stays exactly the set of checkouts the inventory registry declares.
  • Give worktrees a lifecycle — orphaned worktrees must be reclaimable without hunting for them, because agents die mid-task and the current location is never cleaned.

Current state

allod:267-272 returns early for any repo whose $HOME-relative path is absent from protected-branches:

protected_branch=$(protected_branch_for_dir "$repo" || true)
if [[ -z "$protected_branch" ]]; then
  printf '%s\n' "$repo"
  return 0
fi

tests/allod-change.sh:255-256 pins that passthrough as intended behavior, so both the assertion and the code change together. For protected repos the worktree already lands at mktemp -d "/tmp/allod-change-${slug}-${desc}-XXXXXX" (allod:293), and duplicate descriptions already fail loud through the existing local and remote branch-existence checks (allod:279-284), so neither path naming nor description collision needs new machinery.

Why ~/changes rather than a directory under ~/work

architecture.md principle 8 makes the inventory registry the single source of truth for what lives in ~/work; a worktree placed there is a second, undeclared source for the same fact, and principle 5 separately says registry-owned and tool-owned material should not share a namespace. Two verified mechanical consequences reinforce it: a worktree under ~/work is collected by workspace_collect_repos as though it were a repo, so pull-all runs git pull against branches with no upstream and reports errors; and its $HOME-relative path becomes a lookup key that matches nothing in protected-branches, which is exactly the fail-open shape tracked in allod/tools#112.

The current /tmp location has its own problem. On a dev VM /tmp is a directory on the root ext4 filesystem with no tmpfiles cleanup rule, so the original design's claim that worktrees "self-clean on reboot" (allod/strategy archive/dev-plans/allod-change-dev-plan.md:212) does not hold and orphans accumulate indefinitely. ~/changes also keeps agent working directories inside the workspace boundary agents are told to stay within.

Why the default-branch flow must stay in place

Git refuses to check out one branch in two worktrees — fatal: 'master' is already used by worktree at '<path>' — so a worktree cannot isolate two agents that both want to commit to master. Attempting to route the memory and planning-doc flow through worktrees would produce a fatal error for the second agent rather than isolation. That flow's collision safety comes from allod/tools#118 instead.

Scope

In: allod change begin, the worktree path scheme, allod change cleanup and a way to reclaim orphans, and the affected assertions in tests/allod-change.sh. Out: hook-level enforcement that agents commit only from worktrees, collector visibility of worktrees, and record's concurrency guards — each tracked separately under allod/tools#115.

`allod change begin` only creates a worktree for repos listed in `protected-branches`; for every other repo it hands back the shared checkout path, so two agents changing the same repo work in one tree and move HEAD out from under each other without any warning. Make isolation follow the need for a branch instead of the branch's protection status. Part of allod/tools#115. Primary goals: - **Always isolate when a branch is requested** — `begin` creates a worktree and an `agent/<description>` branch for every repo, protected or not, so `protected-branches` goes back to governing only which branch is protected rather than doubling as the isolation switch. - **Keep the in-place flow for default-branch commits** — an agent committing directly to a repo's default branch keeps working in the shared checkout with no worktree and no added friction, because that is the low-ceremony memory and planning-doc flow and git cannot isolate it anyway. - **Site worktrees outside the registry projection** — place them under `~/changes/<slug>-<description>-XXXXXX` so `~/work` stays exactly the set of checkouts the inventory registry declares. - **Give worktrees a lifecycle** — orphaned worktrees must be reclaimable without hunting for them, because agents die mid-task and the current location is never cleaned. ### Current state `allod:267-272` returns early for any repo whose `$HOME`-relative path is absent from `protected-branches`: protected_branch=$(protected_branch_for_dir "$repo" || true) if [[ -z "$protected_branch" ]]; then printf '%s\n' "$repo" return 0 fi `tests/allod-change.sh:255-256` pins that passthrough as intended behavior, so both the assertion and the code change together. For protected repos the worktree already lands at `mktemp -d "/tmp/allod-change-${slug}-${desc}-XXXXXX"` (`allod:293`), and duplicate descriptions already fail loud through the existing local and remote branch-existence checks (`allod:279-284`), so neither path naming nor description collision needs new machinery. ### Why `~/changes` rather than a directory under `~/work` `architecture.md` principle 8 makes the inventory registry the single source of truth for what lives in `~/work`; a worktree placed there is a second, undeclared source for the same fact, and principle 5 separately says registry-owned and tool-owned material should not share a namespace. Two verified mechanical consequences reinforce it: a worktree under `~/work` is collected by `workspace_collect_repos` as though it were a repo, so `pull-all` runs `git pull` against branches with no upstream and reports errors; and its `$HOME`-relative path becomes a lookup key that matches nothing in `protected-branches`, which is exactly the fail-open shape tracked in allod/tools#112. The current `/tmp` location has its own problem. On a dev VM `/tmp` is a directory on the root ext4 filesystem with no tmpfiles cleanup rule, so the original design's claim that worktrees "self-clean on reboot" (`allod/strategy` `archive/dev-plans/allod-change-dev-plan.md:212`) does not hold and orphans accumulate indefinitely. `~/changes` also keeps agent working directories inside the workspace boundary agents are told to stay within. ### Why the default-branch flow must stay in place Git refuses to check out one branch in two worktrees — `fatal: 'master' is already used by worktree at '<path>'` — so a worktree cannot isolate two agents that both want to commit to `master`. Attempting to route the memory and planning-doc flow through worktrees would produce a fatal error for the second agent rather than isolation. That flow's collision safety comes from allod/tools#118 instead. ### Scope In: `allod change begin`, the worktree path scheme, `allod change cleanup` and a way to reclaim orphans, and the affected assertions in `tests/allod-change.sh`. Out: hook-level enforcement that agents commit only from worktrees, collector visibility of worktrees, and `record`'s concurrency guards — each tracked separately under allod/tools#115.
vnprc closed this issue 2026-07-28 03:57:16 +01:00
Sign in to join this conversation.
No description provided.