Splitting build (cheap) from review (Opus) means the technical review is done by an agent that didn't
write the code — and the lander's later semantic review is too, so neither review of a branch is its
author's. A producer never merges to trunk, closes the ticket, pushes trunk, or writes the
main checkout — a single /land lander owns every write to trunk and lands reviewed branches.
Concurrency cap — one shared budget for every dispatch below (lode-2cf). 7 concurrent agents
(builders + reviewers) crashed the Claude Code host twice on 2026-07-10: each agent's gate is
nox -s tests with pytest-xdist — back then -n auto, one worker per CPU core (noxfile.py) —
each holding a cached ONNX reranker, and 7 × 8 workers exhausted this 15GiB/8-core WSL2 machine's
memory. Staggering to ~4 concurrent agents ran the identical workload with zero further crashes.
Before step 0, compute the cap once and hold it for the rest of the invocation:
CODE_MAX_CONCURRENT_AGENTS="${LODE_CODE_MAX_CONCURRENT_AGENTS:-$(
mem_kib=$(awk '/^MemAvailable:/{print $2; exit}' /proc/meminfo 2>/dev/null)
[ -z "$mem_kib" ] && mem_kib=$(awk '/^MemTotal:/{print $2; exit}' /proc/meminfo 2>/dev/null)
nproc_n=$(nproc 2>/dev/null || echo 4)
workers_n="${LODE_TEST_WORKERS:-8}" # same effective width noxfile.py's gate uses (lode-bv6y)
# Anything that is not a positive integer — `auto`, xdist's `logical`, a typo,
# an exported-empty var — means "we cannot know the width here", and the widest
# the gate can get is one worker per core. Assume that. Bash arithmetic silently
# evaluates a non-numeric string to 0, which would collapse the per-agent budget
# to the 2GiB floor and OVER-dispatch (cap 12 on a 24-core box) — a bad value
# must err tight, never optimistic; over-dispatch is what crashed this host.
case "$workers_n" in ''|*[!0-9]*|0) workers_n=$nproc_n ;; esac
if [ -n "$mem_kib" ]; then
# Per-agent gate budget = 2GiB fixed + 0.125GiB/xdist-worker: the gate's
# footprint scales with the WORKER COUNT the gate actually spawns
# (LODE_TEST_WORKERS, default 8 — lode-bv6y), not with this machine's
# core count.
# Measured, not extrapolated; 3GiB/agent @ 8 workers, 5GiB @ 24 workers.
# docs/agents-workflow.md#concurrency-cap-lode-2cf holds the measurements,
# the modelling assumption, and how to re-measure when the suite grows.
per_agent_kib=$(( 2 * 1024 * 1024 + workers_n * 1024 * 1024 / 8 ))
by_mem=$(( mem_kib / per_agent_kib ))
else
by_mem=4 # /proc/meminfo unavailable (non-Linux) — conservative fallback
fi
by_cpu=$(( nproc_n / 2 ))
[ "$by_cpu" -lt 1 ] && by_cpu=1
cap=$by_mem
[ "$cap" -gt "$by_cpu" ] && cap=$by_cpu
[ "$cap" -lt 1 ] && cap=1
echo "$cap"
)}"
LODE_CODE_MAX_CONCURRENT_AGENTS (env var) wins outright when set — no clamping, no
derivation; a static per-machine number the user sets beats a heuristic that guesses wrong. Set it
durably, machine-locally, without editing this file, via .claude/settings.local.json's
"env" block (gitignored, applied to every session on that machine):
{"env": {"LODE_CODE_MAX_CONCURRENT_AGENTS": "6"}} — or export it in the shell that launches
claude for a one-off override. The skill re-reads it fresh at the start of every invocation.
- Unset → derived from
/proc/meminfo (MemAvailable, falling back to MemTotal), divided by a
per-agent gate budget that scales with the effective pytest -n worker count — LODE_TEST_WORKERS
if set (mirroring whatever the gate itself uses, noxfile.py), else its default of 8 regardless
of core count (SPIKE lode-mtuy: -n auto measured slower than -n 8 on this suite, so it is no
longer the default anyone hits by not setting anything) — 2 + workers/8 GiB — then capped at
nproc/2 and floored at 1. Resolves to 4 on the original 15GiB/8-core WSL2 machine (unchanged —
2 + 8/8 = 3GiB/agent, identical to before, so the empirically-stable stagger is preserved) and to
9 on a 31GiB/24-core box now that its gate defaults to 8 workers instead of 24 (2 + 8/8 =
3GiB/agent; 29 / 3 clamped by by_cpu = 24/2 = 12 → 9) — up from the prior 5, which was the
safe number only while that box's gate still spawned 24 workers by default. Setting
LODE_TEST_WORKERS=auto on a box (opting back into one worker per core) restores the old
nproc-scaled budget and the cap correspondingly drops back toward 5 there — the two knobs are meant
to move together. All of these numbers are backed by a real measurement of the gate's peak memory,
recorded in docs/agents-workflow.md —
the cap is a throughput heuristic, not a worst-case memory bound; don't "tighten" it into one
without reading that section.
- The cap is one shared budget across every dispatch source in this invocation — step 0's
rebase pickups, step 1's stranded-review pickups, Phase 1 builders, and Phase 2 reviewers all draw
from the same count; builders and reviewers are not separate pools. Track how many dispatched
agents are still in flight; when the next dispatch would exceed
CODE_MAX_CONCURRENT_AGENTS,
queue it instead and dispatch it only once an in-flight agent completes and frees a slot —
across all sources, not per-step (e.g. a Phase 2 review that becomes dispatchable while step 0's
rebase pickups are still running competes for the same slots they hold). Full rationale and the
override mechanism are documented in
docs/agents-workflow.md.
-
Sweep for needs-rebase kick-backs first — every invocation, regardless of argument.
/land's cheap conflict precheck can kick a ready-for-land branch back: it strips
ready-for-land, adds needs-rebase, and keeps the same land/<id> branch + build worktree
(the ticket stays in_progress, so it never surfaces in bd ready). Nothing else consumes that
label, so before resolving the requested task set, always check for stranded kick-backs:
rtk bd list --label needs-rebase --status in_progress --json
For each hit, dispatch a coding producer (subagent_type: "coding", isolation: "worktree" — required for the same reason as Phase 1 below: a subagent is pinned at the repo
root and cannot call EnterWorktree to create its own, so the harness must hand it a launch
worktree at dispatch). From there it fetches origin/land/<id> and checks it out into that same
launch worktree — no EnterWorktree, no git -C into anything else needed; Edit/Write/nox
all work natively once the branch is checked out locally. Tell it explicitly this is a rebase
pickup, not a fresh build, e.g.:
lode-ai1 carries needs-rebase (kicked back by /land's conflict precheck) — fetch it and
merge current trunk in (do not rebase): git fetch origin land/lode-ai1 trunk, then
TOP=$(git rev-parse --show-toplevel) and git checkout -B "land/lode-ai1--${TOP##*/}" FETCH_HEAD (a local name suffixed with your own launch worktree's directory — unique by
construction, so it never collides with a leftover checkout and the old --detach fallback is
never needed), git merge origin/trunk, re-gate (nox -t fix / nox -s tests), commit anything the gate loop produced,
then git push origin HEAD:land/lode-ai1 (an ordinary push by explicit refspec — the merge only
appends, it never rewrites what's already on land/lode-ai1), refresh land_head/land_summary,
and swap needs-rebase straight to ready-for-land yourself. Do not merge, close, or push trunk.
On a merge conflict: if both sides added independent, non-overlapping content (a mechanical
conflict), resolve it directly with Edit and continue, then finish the same way; if the two
sides genuinely disagree, abort the merge and escalate yourself (land-escalated, leave the
branch as it was) rather than guess — that stays a human decision. Don't try to remove your own
launch worktree on the way out — you can't remove the one you're standing in, and I reclaim it for
you after you return.
Merging trunk into the branch — rather than rebasing the branch onto trunk — is what keeps
this whole cycle inside the one dispatched producer, start to finish: a merge commit appends to
history, it never rewrites what land/<id> already carries on origin, so the push back is an
ordinary fast-forward. Expect the merge to conflict — a branch only carries needs-rebase
because it already failed /land's clean-merge precheck — and resolving it keeps the push a
fast-forward all the same. Full reasoning:
docs/agents-workflow.md.
Dispatch every hit concurrently with each other and with any Phase 1 builds below
(run_in_background: true), subject to the concurrency cap (CODE_MAX_CONCURRENT_AGENTS,
computed above) — a rebase pickup and a fresh build never share a ticket, so they can't collide,
but they draw from the same budget, so queue the overflow and dispatch it as slots free. Do not
dispatch a Phase 2 code-reviewer for a rebase pickup: it lands directly at
ready-for-land, skipping technical review entirely, the same way /land's kick-back skipped
land-review — the content was never judged bad, it only needed to replay onto where trunk
moved. If the sweep finds nothing, say so and move on; it's not an error.
Reclaim its launch worktree the moment it returns — either outcome (lode-vs7g). A subagent
cannot git worktree remove the worktree it is standing in, so I do it, from my own (repo-root)
context, immediately after collecting its result — not batched to the end of the fan-out, and not
left for the ticket to land. This same block is the reclaim referenced by step 1 and Phase 2
below; it is the only copy. I don't need the agent to tell me which worktree was its own — since
lode-em6v every reviewer / rebase pickup checks the branch out as land/<id>--<its-own-worktree-dir>,
so the ticket id alone derives both the path and the branch:
ID=lode-ai1
git worktree list --porcelain | awk '
/^worktree /{p=$2} /^branch /{sub("refs/heads/","",$2); print p"\t"$2}' \
| while IFS="$(printf '\t')" read -r WT BR; do
case "$BR" in "land/$ID--"*)
git worktree remove --force "$WT" 2>/dev/null
git branch -D "$BR" >/dev/null 2>&1 || true ;;
esac
done
Deriving rather than trusting a reported string is what makes this actually close the leak: it
needs no cooperation from the agent, so it works even when the agent crashed, escalated, or returned
a garbled path — and it reclaims every worktree that ticket accumulated (a ticket reviewed or
picked up across N cycles leaves N of them), not just the last one. It cannot touch the builder's
worktree: that one is branch-named worktree-agent-*, never land/<id>--*, so it stays for /land's
review_worktree GC exactly as before.
Two details that are load-bearing, both verified against live git behaviour:
- Plain
git, not rtk — rtk reformats worktree list --porcelain, which breaks the field
parse, the same way it did for /land's own GC (lode-9j7).
- A single
--force, never -f -f. The harness locks a launch worktree while its agent runs
(locked claude agent <name> (pid …)) and unlocks it on exit. A single --force therefore removes
a finished agent's worktree but refuses a still-locked one — it fails safe. -f -f would
override the lock and rip the worktree out from under a live agent; if a reclaim ever looks like a
no-op, the agent is still running, and the answer is to wait, not to escalate the flag.
Safe on both outcomes: by the time the agent returns, everything in its worktree is already on
origin/land/<id> — a clean pickup pushes first, and an escalation's aborted merge leaves the
checkout an exact mirror of what was fetched. Reclaiming here rather than leaving it to /land
matters most on an escalation: that branch never merges into trunk, so backstop 1 — which only
reclaims a merged-into-trunk worktree — can never reach it, and it would otherwise leak until
a human resolves the escalation and the branch eventually lands. /land's backstops stay in place,
unchanged; note they are a partial net, not a total one — they catch a crashed agent whose branch
does eventually merge, but a crashed escalation is reachable only by the derived reclaim above,
which is the other reason it must not depend on the agent reporting anything.
-
Sweep for stranded ready-for-code-review re-entries too — same invocation, same reason. A
human resolving a code-reviewer technical-review escalation or a coding build-time escalation
applies exit (a) per docs/agents-workflow.md by re-adding ready-for-code-review (and removing
land-escalated) directly on the ticket, outside any /code run. That ticket stays
in_progress exactly like a needs-rebase kick-back, so bd ready never returns it either — and
unlike needs-rebase, nothing in the ordinary Phase 1/2 flow below ever looks for it, because
Phase 2 only dispatches a reviewer for a ticket this same invocation's Phase 1 just built
(lode-t83). Check for it the same way as step 0:
rtk bd list --label ready-for-code-review --status in_progress --json
Any hit here is, by construction, stranded from a previous invocation — this check runs before
this invocation's own Phase 1 has built anything. For each hit, confirm the hand-off is actually
reviewable before dispatching:
rtk bd show <id> --json | jq -r '.[0].metadata.review_head'
If it's empty (this can only happen for a build-time escalation predating the coding.md fix for
lode-t83's Gap 1), don't guess a head SHA — leave the label alone and surface it in the final
report as needing a human to re-escalate or rebuild instead. Otherwise dispatch a code-reviewer
exactly as Phase 2 does below (subagent_type: "code-reviewer", isolation: "worktree", same
prompt shape: read review_head, fetch + check out land/<id> into its own launch worktree,
/code-review --fix + /simplify, re-gate, re-push, swap to ready-for-land or escalate again).
Dispatch every hit concurrently with each other, with any step-0 rebase pickups, and with this
invocation's own Phase 1 builds, subject to the same concurrency cap — a stranded re-entry
never shares a ticket with a fresh build or rebase pickup, so none of these collide, but all of
them draw from the one shared budget; queue the overflow and dispatch it as slots free. If the
sweep finds nothing, say so and move on; it's not an error. Reclaim each reviewer's launch
worktree the moment it returns — step 0's reclaim block, ID set to that ticket
(lode-vs7g). This sweep dispatches the identical subagent, so the identical reclaim applies.
-
Resolve the task set from the argument:
- No argument (the default), or
--all-ready → read the filtered bd ready --json
frontier (callout below) and fan out across the independent, unblocked frontier (honoring
the dependency graph and phase-a ordering).
Don't dispatch a ticket whose blocker is also in the batch — surface that instead of guessing the
order.
--single (no ID) → one producer; /code resolves the pick itself — build the same
filtered bd ready --json frontier the callout below defines, take the top entry (bd ready
is already priority-ordered, so no extra sort is needed), dispatch it as an explicitly-named id.
--single collapses to "bare /code, limited to one ticket": same selection, same filter, same
skip-reporting; only the fan-out width differs.
- One bd issue ID (e.g.
lode-ai1) → one producer; tell the agent to claim and implement it.
- Several bd issue IDs → fan-out: one producer per ID. Only dispatch IDs that are
genuinely independent (no unmet dependency between them); if two share a dependency, say so
and let the human sequence them rather than racing.
- Free-text (e.g. "add a --json flag to search") → one producer; tell the agent that is the
task — it files the bd issue itself before coding, per its own rules.
Auto-select paths only — exclude human-labeled tickets and epics (lode-8pqv). bd ready is
a dependency-satisfaction query, not a build queue: nothing about it guarantees a ticket is
something a producer can actually build. Two categories reach it anyway and must never be
auto-selected, on the no-argument, --all-ready, and --single paths:
- any ticket carrying the
human label — it exists precisely because an agent cannot resolve
it (that's what /sweep surfaces it for); dispatching a producer at one either invents the
decision the label exists to prevent, or burns a build cycle re-discovering that a human was
already asked.
- any ticket with
issue_type == epic — a container with no implementable acceptance
criteria of its own.
Read the frontier as JSON on every auto-select path, including --single; the human label is
invisible otherwise. Plain bd ready prints an [epic] type marker but renders no labels at
all, so a human ticket is indistinguishable from a buildable one unless you ask for the fields:
rtk bd ready --json | jq -r '.[] | select((.labels // []) | index("human") | not) | select(.issue_type != "epic") | .id'
(labels is null, not [], on a ticket with none — hence the // [].) bd ready is already
priority-ordered, so this list's first entry is the highest-priority buildable item — no extra
sort needed. On the no-argument and --all-ready paths, filter the frontier this way before
fanning out across all of it. On --single, filter the same way and dispatch just the top
entry. Either way, report each ticket dropped — id + reason
(human-labeled or epic) — per step 5: a skip is a signal to the operator, not noise to drop
silently.
If nothing survives the filter, dispatch nothing and say so — never fall back to a
filtered-out ticket. A frontier of nothing but human tickets and epics is a real, reachable
state (both sit in bd ready indefinitely by nature: a decision ticket is its own blocker, and
bd won't let a task block an epic), and it means there is no buildable work right now — a signal
for /sweep, not a build target. That holds on all three auto-select paths: --single dispatches
no producer at all, and the fan-out paths fan out across nothing.
This filter applies only to auto-selection. Explicitly-named IDs are an operator override
and are never filtered — /code lode-wbv8 (a single named ID) or /code lode-wbv8 lode-ai1
(named among several) must keep dispatching exactly as before, human label or epic type
notwithstanding: the operator named it on purpose, so the ticket's kind is not this skill's call
to second-guess on that path.
-
Phase 1 — dispatch one coding builder per task via the Agent tool with
subagent_type: "coding" and isolation: "worktree". The isolation is required: a subagent is
pinned at the repo root and cannot call EnterWorktree to create its own, so the harness must
hand each builder a worktree at dispatch — isolation: "worktree" launches it already cwd'd inside
.claude/worktrees/agent-<hash> on its own branch off trunk HEAD.
- Solo (
/code <id>, /code --single, free-text): dispatch exactly one builder in the
foreground.
- Fan-out (bare
/code, --all-ready, /code <id> <id> …): dispatch one builder per ticket,
concurrently (run_in_background: true), up to the concurrency cap
(CODE_MAX_CONCURRENT_AGENTS, shared with steps 0/1's sweeps and Phase 2 below) — queue any
remaining tickets and dispatch each as an in-flight agent completes and frees a slot. Collect each
result as it finishes. Each builds, pushes origin/land/<its-id>, keeps its worktree, and
marks its own ticket ready-for-code-review independently; one builder's escalation must not
block its siblings.
Pass the resolved task in each prompt, e.g.:
Implement lode-ai1 as a producer following your cycle (claim → worktree → gates → push
origin/land/<id> → mark ready-for-code-review, recording review_worktree/review_head →
keep the worktree → stop). Do not review your own work, merge, close, or push trunk. Stop and
escalate (revert to green, annotate land-escalated, don't hand off) if a clarifying decision is
needed during the build; stop and report if a gate fails.
--single dispatches the same way, with the single id /code already resolved in step 2 — the
builder never re-reads bd ready to pick its own ticket.
-
Phase 2 — verify the hand-off, then dispatch a code-reviewer per built ticket. Never trust a
builder's task-notification alone: a builder that backgrounded its gates and stalled (lode-95o) can
still emit a status=completed notification with a benign-looking summary, even though nothing was
pushed and the ticket is still sitting in_progress. Before dispatching a reviewer, check the
actual state in bd and on origin:
rtk bd show <id> --json | jq -r '.[0].labels'
rtk git ls-remote origin refs/heads/land/<id>
Dispatch the reviewer only for a ticket where both checks pass. Otherwise read the labels before
reacting — the two failure modes are not the same ticket:
land-escalated present → the builder escalated deliberately: it reverted to green, pushed,
and stopped because a human owes a build decision. Skip it. No reviewer, and never resume it to
"complete the hand-off" — that would override the escalation. Surface it in step 5.
- Otherwise (no
ready-for-code-review, or origin/land/<id> doesn't resolve) → the builder
stalled or never finished. Do not send a reviewer into an unverified worktree. Resume that same
builder (SendMessage to its agent id/name — it resumes with full context) and tell it plainly:
any background gate it armed will never notify it back (a subagent with no live background children
is stopped by the harness), so it must re-run the gate in the FOREGROUND within its own turn and
complete the hand-off. Re-check both conditions once it returns before proceeding.
For every ticket that passes both checks: use the Agent tool with subagent_type: "code-reviewer"
and isolation: "worktree" — the isolation gives it a launch worktree off the repo root, so it
never writes trunk. From there it fetches origin/land/<id> and checks the branch out into that
same launch worktree — no EnterWorktree, no git -C into the builder's worktree; the builder's
worktree is never opened by the reviewer under this architecture. Match the build cadence: one
reviewer in the foreground for a solo build; one reviewer per ticket concurrently
(run_in_background: true) for a fan-out, each dispatched as its builder's hand-off is verified —
subject to the same concurrency cap as everything else (CODE_MAX_CONCURRENT_AGENTS): a
reviewer that becomes dispatchable while the budget is already full from Phase 1 builders (or step
0/1 sweeps still in flight) queues behind them and dispatches the moment a slot frees, rather than
exceeding the cap.
Pass the ticket id, e.g.:
Technically review lode-ai1 (it is ready-for-code-review): read review_head from bd, git fetch origin land/lode-ai1 trunk, then TOP=$(git rev-parse --show-toplevel) and git checkout -B "land/lode-ai1--${TOP##*/}" FETCH_HEAD (a local name suffixed with your own launch
worktree's directory — unique by construction, so no --detach fallback is ever needed) into your
own launch worktree, run /code-review high --fix trunk...HEAD + /simplify, re-gate, commit,
git push origin HEAD:land/lode-ai1, and swap the ticket to ready-for-land. Do not merge,
close, or push trunk. Escalate (revert to green, swap to land-escalated, don't mark ready) only
on a clarifying decision or "making it worse."
Reclaim its launch worktree the moment it returns — either outcome (lode-vs7g). Run step 0's
reclaim block with ID set to this ticket, right after collecting the reviewer's result
(per ticket, not batched to the end of the fan-out). Nothing needs to be passed back for this: the
reviewer's branch is land/<id>--<its-own-worktree-dir>, so the ticket id derives both the worktree
and the branch. Everything in that worktree is already on origin/land/<id> by the time the reviewer
returns — a clean pass pushes at step 7 of code-reviewer.md, and an escalation re-pushes its
reverted-to-green commit too, so nothing local is ever lost. It matters most on an escalation: that
branch never merges into trunk, so /land's backstop 1 can never reclaim this worktree.
-
Relay each result to the user. Agent final messages aren't shown to the user — surface what
matters per ticket across both phases: that the build gates passed and the technical review +
re-gate passed, the land/<id> branch and head SHA, and that it reached ready-for-land
(so /land can pick it up). If a builder escalated, say so — it reverted to green, pushed,
applied land-escalated, did not hand off, and a human owes a build decision. If a reviewer
escalated, likewise — green branch pushed, land-escalated set, not landable until the human
decides. For a fan-out, give a per-ticket roll-up: which reached ready-for-land, which are still in
review, which escalated (at build or review) and why. Report the Step 0 sweep the same way —
which needs-rebase tickets were found, which rebased clean and are back at ready-for-land, and
which hit a rebase conflict and were escalated (say which one, so a human can resolve it). Report
step 1's sweep too — which stranded ready-for-code-review tickets were found, which got a
code-reviewer dispatched, and which were left alone for missing review_head. If the concurrency
cap ever throttled dispatch this invocation (more dispatchable work than free slots at some point),
say so — which cap value was in effect and roughly how the queue drained — so a fan-out that took
longer than the ticket count alone would suggest isn't mistaken for a stall. On an auto-select run
(no argument, --all-ready, or --single), also report every ticket the human/epic filter
passed over — id + reason (human-labeled or epic). You did that filtering yourself in step 2 on
all three paths, so report it directly. Say so explicitly even when nothing was
skipped ("no human/epic tickets on the frontier"), so the operator can tell a filter that found
nothing from a filter that never ran. Mention the launch-worktree reclaims (lode-vs7g) only as a
one-line tally ("reclaimed N reviewer/pickup worktrees") — it's routine housekeeping, not a caveat;
report it individually only where one failed to reclaim, which means an agent is somehow still
running and is worth surfacing.