| name | issue-lane |
| description | "1 issue = 1 lane" lifecycle discipline for herdr-managed agent fleets. Use when assigning an issue to a worker lane, when an issue closes ("close the lane too"), or for lane audits ("lane audit", "lane stocktake", "1-issue-1-lane check"). Creates lanes with issue-ID labels on BOTH the tab and the pane, tears lanes down when their issue closes, and audits drift by three-way cross-checking tab label × pane label × issue tracker state. |
issue-lane — 1 issue = 1 lane lifecycle discipline
English | 日本語
Lane creation, teardown, and model escalation each have their own canonical
procedures (bootstrap / teardown / model-gear conventions of your fleet). This
skill binds them to the issue lifecycle and provides drift detection.
Why
Observed failure modes in a multi-PO agent fleet: lanes kept an expensive
model from a previous boost and carried it into unrelated work; lanes for
closed issues lingered and made the fleet unreadable; lanes were silently
reused across issues by relabeling the pane, leaving the stale truth only on
the tab. Binding lanes 1:1 to issues makes pane list equivalent to "what is
actually in progress" — management returns to measurement.
Invariants (4)
-
1 issue = 1 lane = 1 writer. Labels carry the issue ID on both
layers:
- tab label: first word =
<ISSUE-ID> (e.g. PROJ-123 api-freeze)
- pane (agent) label:
<space>/<ISSUE-ID>[-role] (e.g. api/PROJ-123)
If the two layers disagree about the issue, that is reuse drift (the
pane label was swapped while the lane kept working on something else).
Resident PO panes (tab label po) are exempt.
-
A lane lives exactly as long as its issue. Born at assignment, torn
down when the issue reaches Done/Canceled. "Reuse for the next issue" is
forbidden — the next issue gets a fresh lane (model, history, and worktree
start clean). The inverse — rotating to a fresh session mid-issue — is
not reuse but recommended hygiene: a lane's state lives in receipts, PRs,
and the tracker, so sessions are disposable. Long-lived, token-heavy
sessions degrade (declaration stalls, hollow output; we measured a lane
grown to 116M input tokens). "1 issue = 1 lane" means one at a time —
serial generational replacement on the same issue is fine. When a session
shows degradation, try a free refresh before a paid model boost.
-
Model = fleet standard gear by default. Lanes may be Codex or Claude
Code agents — default implementers: Codex gpt-5.6-terra (medium; boost
gear sol, effort low), Claude Code sonnet (boost tier e.g. opus).
Running on a higher gear is allowed only while a model ledger has an open
entry for the lane. Unledgered high gear is demoted on sight.
-
No lane registry file. The source of truth is herdr pane list (live)
cross-checked with the issue tracker. A registry file would become a
second, drifting authority.
Assign (issue → lane)
-
Duplicate check: herdr pane list for the target workspace — if a pane
already carries this issue ID, do not create another; message that pane.
-
Create via your fleet's lane-bootstrap procedure. Choose the agent
runtime per lane (Codex or Claude Code) and pass the model explicitly —
never rely on defaults (Codex: gpt-5.6-terra; Claude Code: sonnet).
Tab label starts with the issue ID.
-
Kickoff message (sent to the pane ID) must include:
This lane is dedicated to . On completion, stop all background
terminals, then park and report. Do not work on any other issue.
Weakening tests or satisfying them with a skeleton implementation is a
protocol defect — a held-out test you have not seen will catch it and
the work will be redone. Do not diff the tests.
Close (issue closed → lane teardown)
Trigger: PR merged + issue Done/Canceled measured in the tracker — never
on the lane's self-report. Works with any tracker: Linear (MCP get_issue),
Jira (CLI/MCP; issue keys like PROJ-123 follow the same ABC-123 pattern),
or GitHub Issues (gh issue view).
- Confirm issue state in the tracker.
- Teardown safely: verify no background processes remain (especially holders
of shared locks), stale-check before killing, then remove worktree/branch.
- Close the pane (do not rename-and-reuse — that is how label/issue drift
starts).
- If the lane held a model-ledger boost entry, close the entry.
Audit sweep ("lane audit")
Never audit from pane list alone. Measured lesson: a pane label looked
current while the tab label still named a closed issue — cross-issue reuse
left its only trace on the tab layer.
herdr workspace list, then per workspace take BOTH herdr tab list and
herdr pane list, joined on tab_id.
- Extract issue IDs from tab label and pane label; cross-check (a) the two
layers against each other and (b) against the tracker state (three-way).
The
ABC-123 key pattern covers both Linear and Jira; for GitHub Issues
use #<n> / owner/repo#<n>.
- Measure the model from the pane footer:
herdr pane read <pane> --source visible --lines 3 --format text | tail -1
- Violations and dispositions:
| Violation | Detection | Disposition |
|---|
| Orphan lane | no issue ID on either label layer | ask the owning PO; close if still unclaimed next sweep |
| Zombie lane | issue Done/Canceled but pane alive | teardown → close immediately |
| Duplicate writer | same issue ID on 2+ panes | stop the later one; consolidate into the first |
| Unledgered boost | footer shows high gear, no open ledger entry | demote — Codex panes: scripts/model-switch.sh (fail-closed; no blind menu numbers); Claude Code panes: its /model picker with the same measured-menu + verify discipline. Notify the owning PO |
| Reuse drift | tab and pane disagree, or tab names a closed issue | identify the real work item; if working, wait for park → teardown; next issue gets a fresh lane |
| Unassigned work | issue In Progress with no lane | report to the owning PO (do not create lanes on their behalf) |
- Report in one final message: workspace / pane / issue / violation /
disposition. If clean, say "swept N panes, 0 violations" with the count.
Anti-goals
- No lane registry file (live measurement + tracker are the SOT).
- No keeping closed-issue lanes around "just in case".
- No deferring an unledgered-boost demotion — finish it in the turn that
found it.
- No overriding the owning PO's assignment judgment (the sweep detects and
applies mechanical dispositions only).