Files
hq/00-META/process/07-feature-branches.md
T
mesh-adminandClaude Opus 5.5 071fc1c29d
mesh/merge-gate head 071fc1c29dce merged into trunk 21b79a04a283 — pass: the change touches no module of the mesh's graph
mesh/repo-check head 071fc1c29dce merged into trunk 21b79a04a283 — pass: its merge-check.sh passed
mesh/delivery delivered
Name the lead, and have it take over a finished issue
A finished issue's agent is gone, so left in fixing it goes stale; the lead
takes it over until the feature is delivered. One repository is one
delivery, not a group; readiness comes from depends-on links (review
comment 12466).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 19:53:20 +00:00

7.1 KiB

Playbook 07 — Feature branches across repos

Trigger. Work that changes code — in one code repo or in several at once (mesh-sdk, mesh-controller, mesh-catalog, mesh-host, mesh-lab, and hq when a decision rides along).

Who runs it. Anyone who writes code, engineers and agents alike. Agents follow it exactly — it is the guard against the failure it was written for.

The failure it prevents

A feature was worked as a branch-and-MR per unit of thought — one per decision, one per stacked increment — and each MR was treated as finished when it was opened, not when it was merged. Across repos the same feature took a different branch name in each. The MRs piled up unmerged: one session left sixteen stacked intermediate MRs that had to be consolidated and closed by hand. An MR is a review checkpoint, not a scratchpad.

It failed the other way too. A large feature was worked as one pull request per issue into protected integration branches, each waiting for the forge's merge check, again whenever another merge moved the branch, and for a review. Most of a day went to waiting on checks while the code itself was ready.

The rule

One feature is one branch name, one worktree per repo, one MR per repo, opened once, at the end.

  1. Name the feature once. feat/<slug>. The same branch name in every repo the feature touches — never a different name per repo, never a fresh branch per increment within the feature.

    The feature branch is never protected and takes no pull request until step 4: a protected branch forces a merge check on every merge into it, which is the waiting this playbook avoids.

  2. Isolate each repo. One git worktree per touched repo under .work/<slug>/<repo>, branched off main:

    git worktree add .work/<slug>/<repo> -b feat/<slug> origin/main
    

    Parallel features never collide, and no shared checkout is edited.

    Add the untouched siblings the lab reads. The lab beds find the other repositories by sibling path from the lab checkout (../mesh-tools/module.json, ../mesh-sdk, …), the way the main layout has them. A .work/<slug>/ directory holding only the touched repos fails a bed at once with no manifest for mesh-tools at …/.work/<slug>/mesh-tools/module.json, after genesis has already passed. Give the directory those repos as detached worktrees on main — never symlinks:

    git worktree add --detach .work/<slug>/mesh-tools main
    
  3. Commit as you go — locally. Increments land on the one branch. Nothing is pushed and no MR is opened mid-feature.

    The unit of work is an issue. Each commit message names the issue it fixes, such as "Keep the assignments on the bus (issue 652)". No pull request, merge check, review or delivery per issue.

  4. Finish, then publish. When the whole feature is done — every repo, tests green — push every branch and open one MR per touched repo, together.

    Each repository's change gets one independent review before its MR opens; the checks run once, on those MRs, and the feature is delivered as one delivery plan. MRs in two or more repositories that share the branch name are one delivery group (ADR 0239 §2); a feature in one repository is one delivery.

  5. Merge promptly, once approved. Every merge into main is notified and approved (ADR 0023); once it is, merge — do not leave it sitting. The branch is deleted on merge.

  6. Leave nothing behind. After the MRs merge, no feat/<slug> branch and no .work/<slug> worktree survive.

Working one feature with several agents

A large feature (a design's whole work) is fixed by several agents at once. The lead is the session that runs the feature: it holds the feature branch, sends an agent per issue, and pushes, reviews and delivers at the end. The agents never push.

  • One feature worktree per repository, held by the lead. Each agent works on a local branch of its own, in a worktree of its own, branched from the feature branch's current head.
  • Land by fast-forward, under a lock. An agent brings its branch up to the feature branch, runs the repository's tests and merge-check.sh in its own worktree, then fast-forwards the feature branch under a lock (flock <feature worktree>.lock git -C <feature worktree> merge --ff-only <its branch>). If another agent landed first, it merges again and repeats.
  • At most five issues are being fixed at once. When one lands, the next ready issue starts at once; an issue is ready when every issue its depends-on links name has landed on the feature branch.
  • An issue partly done goes back to open with a note naming the commits that landed and what is left, linked depends-on to what it waits for. An issue is never left in fixing while nobody works on it. A finished issue's agent is gone, so the lead takes it over in fixing (its by names the lead) and keeps working it: it is resolved, with fixed-by naming the feature's MRs, once the feature's delivery is done.
  • Two issues in one file: keep both sides' behaviour; where both added tests or list lines in one place, keep all of them. Never resolve code with a blind git merge-file --union: it can interleave two functions' braces. Build and test after every resolution.
  • Fetch by name. In a shared clone a plain git fetch may update only main. Fetch the feature branch with an explicit refspec before branching from it or comparing against it, or an agent merges a stale copy.
  • Report every ten minutes, short, as a tree or a table: the issues done (of the total), each issue being fixed with its active time (minutes since its agent was sent, from a start time written down then, never guessed), the issues ready next, the ones waiting, and anything that needs the operator. Times are local and absolute.
  • When this playbook meets a problem, the lesson is added here, so the next feature avoids it.

What this is not

  • Not a licence to batch unbounded work. A feature is a bounded unit; if it sprawls for days, end-of-feature bloat merely replaces per-increment bloat. Split it into features, each its own branch and MR.
  • Not a second trunk. Every repo branches off main. There is no longer an initialization trunk.

How it is checked

The end state is visible, and its absence is the smell:

  • After a feature merges, git branch -r | grep feat/<slug> and git worktree list return nothing for it. A surviving branch or worktree means step 6 was skipped.
  • A bed run from .work/<slug>/mesh-lab that fails naming a .work/<slug>/<repo>/… path it cannot find is a missing sibling worktree, not a mesh fault.
  • A feature's issues show their commits on the feature branch (git log --grep 'issue <n>'), and no pull request into the feature branch exists. A pull request per issue, or an agent waiting on a merge check mid-feature, is the second failure above.
  • More than one open MR in a repo that share no feature name, or a stack of MRs none of which is merged, is the failure this playbook exists to prevent — stop and consolidate before opening more.