Parcel Roster
The across-the-board view of active parcel worktrees. Answers: what parcels are in flight, what state are they in, and which ones are ready for audit or merge?
Bundled with rookery. Pairs with rookery worktree list (the lower-level CLI view) and rookery status / rookery land history (history-side views). This skill is the agent-friendly markdown analogue.
Mirrors lane-roster but targets the parcel tree (the configured worktrees root) rather than the lane tree (.claude/worktrees/*). The two are separate — do not conflate them.
When to use
- Starting a wave-triage pass and needing a snapshot of the fleet
- Asking "what's ready to merge?" after a wave of parallel builds
- Deciding whether a parcel is still in flight, done but unaudited, or audited-and-waiting
- Before authoring a new parcel, to see which ids are already taken
When NOT to use
- You want lane sessions (
.claude/worktrees/) — uselane-rosterinstead - You want detailed verdicts per parcel — use
parcel-audit - You want merge-order decisions — use
wave-triage
Path resolution (read this once per session)
This skill operates on parcel worktrees that live under a configurable root. Resolve <worktrees_root> once, in this order:
rookery.yamlin CWD: read theworktrees_rootkey (top-level). Use this if present and non-empty.ROOKERY_WORKTREESenv var: fall back to this if step 1 yielded nothing.- Default:
./worktrees(relative to CWD).
The audits sibling lives at <worktrees_root>/audits/.
Workflow
Step 1 — Enumerate parcel worktrees
Resolve <worktrees_root> per the path-resolution block above. Iterate directory entries under <worktrees_root>/ (Bash for-loop over */, or Glob+filter). For each entry, include it only if both are true:
- It is a directory (skip loose files — real fleets have
*.pid,*.iter, and occasional log files at top level that are NOT worktrees) - It contains a
.gitfile or directory (real worktrees always do; Glob alone can't confirm)
Special-case dirs to skip by name: audits/, logs/, smoke-runs/. These are sibling artefact roots, not worktrees. Extending this blacklist is cheap — prefer the .git presence check as the authoritative filter.
If the Glob returns nothing, emit:
STATUS: no parcel worktrees found
ROOT: <worktrees_root>
and stop. An empty tree is a valid answer.
Step 2 — Per-worktree git state
For each candidate <wt>:
git -C <wt> branch --show-current
git -C <wt> log --oneline -1
git -C <wt> rev-list --count main..HEAD # commits ahead
git -C <wt> rev-list --count HEAD..main # commits behind
git -C <wt> status --porcelain | wc -l # dirty count
git -C <wt> stash list | wc -l # stash count
Use git -C <path> — never cd. If any command errors (e.g. the dir is not a git worktree, or main no longer exists), record the error verbatim in that row's error column and move on. Do not abort the whole roster on one bad worktree.
Step 3 — Check completion + audit markers
For each <wt>, check file presence via Glob (not Bash ls):
<wt>/PARCEL_DONE.md— the parcel's own completion report<worktrees_root>/audits/<id>.v*.md— audit files (zero or more; record the highest version present)
Where <id> is the worktree directory name.
Step 4 — Emit the table
Produce a markdown table sorted by parcel id (alphanumeric, so I1 < I2 < P1 < P10 < P2 unless a natural-sort is explicitly requested). One row per worktree:
| id | branch | ahead | behind | dirty | stash | DONE? | audit | last-commit |
|----|--------|-------|--------|-------|-------|-------|-------|-------------|
| I1 | parcel/I1-merge | 4 | 0 | 0 | 0 | ✓ | v2 | ab7502d fix(...) |
| I2 | parcel/I2-wire | 1 | 0 | 3 | 0 | ✗ | — | 72a2e29 feat(...) |
DONE?:✓if PARCEL_DONE.md exists,✗if notaudit: highest version present (e.g.v1,v2), or—if nonelast-commit: short hash + subject, truncated to fit
Below the table, emit a one-line fleet summary:
FLEET: <total> parcels, <done-count> DONE, <audited-count> audited, <at-risk> at-risk (dirty or no-DONE-after-N-commits)
Step 5 — Flag at-risk and absorbed parcels
A parcel is at-risk if any of:
dirty > 0(uncommitted work that could be lost)ahead > 0and noPARCEL_DONE.mdand no commit in the last 2 hours (stalled mid-build)
A parcel is absorbed if:
ahead == 0ANDbehind >> 0(e.g. behind ≥ 50) AND PARCEL_DONE is present
Absorbed parcels have shipped their work through main via rebase or squash; the branch is now a stale historical pointer. In practice this is the most common end state for a merged wave — operators should know the parcel is "done, not lost" so they can cleanly garbage-collect worktrees.
A parcel is fresh if ahead > 0 (still has unmerged commits) OR behind is small (close to main).
List at-risk rows separately below the main table. Mark absorbed rows with a distinct marker (e.g. trailing (absorbed)) so they do not confuse with in-flight parcels. Do not attempt to fix or prune — branch / worktree deletion is a separate concern (rookery worktree).
Hard rules
| Rule | Why |
|---|---|
Read-only; never git -C <wt> <mutating> |
Roster must not perturb parcel state |
Use git -C <path>, never cd |
Compound cd && ... breaks permission grants and violates project bash convention |
Glob for file presence, not Bash ls/find |
Grep/Glob are the dedicated tools; Bash ls is context-waste |
Audits dir is <worktrees_root>/audits/, NOT inside the worktree |
This is the project's convention — do not look inside the worktree for the audit |
Never touch .claude/worktrees/ |
Those are lane worktrees; lane-roster owns them |
Resolve <worktrees_root> from config, never hardcode |
Different deployments use different roots |
Anti-patterns
| Anti-pattern | Why it hurts |
|---|---|
ls <worktrees_root>/ instead of Glob |
Bash ls adds noise and is slower than Glob for this tree |
Aborting the whole roster when one worktree's git log fails |
Single bad worktree should degrade gracefully to a error: <msg> row, not kill the report |
| Sorting natural-numeric without the user asking | Alpha sort is predictable; natural sort surprises the caller |
| Embedding audit verdict guesses in the table | Verdict is parcel-audit's remit; this skill reports presence only |
Re-running git fetch to update main before counting |
Roster is a snapshot of local state; network calls are out of scope |
See also
lane-roster— the analogue for lane worktrees under.claude/worktrees/parcel-reader— parses a single PARCEL_DONE.md into structured sectionsparcel-audit— produces a verdict for one parcelwave-triage— consumes this roster + audits to compute merge orderrookery worktree list/rookery status— CLI views of the same fleet