implement
Drives filed issues to a reviewed, draft-PR-ready branch, running build, verify, and review for each issue on its own and working independent issues in paral...
npx skills
npx skills add JoshuaOliphant/compost --skill implement
Works for Codex, Cursor and other harnesses. Use -a <agent> to target one, e.g. -a codex.
Claude Code
/plugin marketplace add JoshuaOliphant/compost
/plugin install compost@compost
Implement
Issues are a task graph, not a to-do list. At any moment some of them are unblocked; that set is the
frontier, and this skill's job is to keep it moving until every issue under the parent is built,
verified, and reviewed on one feature branch. You pick the flow from here without being led:
each issue goes through compost:build, compost:verify, and compost:review, and you decide
everything a reasonable colleague would decide, writing each ruling down on the issue instead of
stopping to ask.
Keep the orchestration light. A plain agent working an issue lands it; ceremony around that agent (ledgers, status files, pilot runs, verifier agents that rerun one command) costs more than it buys. The tracker and git are the only records. Parallelism is for work that splits, never for show. Order the work so each step can be checked before the next builds on it (sequence verifiable units).
Steps
-
Orient. Read
docs/agents/issue-tracker.mdfor the tracker and its commands; if it is absent, runcompost:setupnow, then continue. Inside a run, setup's questions get its recommended answer, posted as a ruling on the parent, and its irreversible step (uninstalling orphaned plugins) is left for the user. Ifdocs/agents/observability.mdis absent, runcompost:setup's observability step on this branch before any worker branches from it. Whendocs/agents/testing.mdnames no verify command, build it the same way, bycompost:verify's step 1, so parallel lanes don't each write their own. Read the parent issue, every sub-issue, and every comment on them: an architectural parent (**Class:** architectural) with no approval comment stops here for approval, unless the ask that started this run said to build it; earlier rulings bind you, and a status comment fromcompost:pausemeans you are resuming, so start from its next action. ReadCONTEXT.mdand the ADRs indocs/adr/for the areas the issues touch. Rungit logandgit worktree listto see what already landed. -
Compute the frontier. These definitions are the only ones;
compost:buildandcompost:pauseuse them too. - An issue is done when it is closed, or ticked on the parent's checklist. A remote tracker closes an issue only when its pull request merges, so inside a run "done" almost always means ticked: reviewed and landed on the feature branch (step 7).
- An issue is blocked while any issue on its "Blocked by #n" lines is not done. The forge's own dependency count (open blockers) stays non-zero until the PR merges; don't read it.
- An issue is taken when a branch for it exists after
git fetch, the issue isn't done, and the branch isn't this run's own. Match by prefix,refs/heads/<issue>-*:compost:buildnames the branch<issue>-<slug>and step 4 pushes it, but another session may derive a different slug. This run's own are the branches this session made and, when this session resumed from acompost:pausestatus comment (and posted the "resumed" comment after it), the branches that comment lists. Git is the claim; a second session on the same parent skips a taken issue. A claim expires when no comment on the parent from any session but this one is under a day old: a live run keeps posting rulings and review rounds there, and your own comments say nothing about whether the other session is alive. Take the issue over from its branch's head. - The frontier is every open issue that is not done, not blocked, not taken, and not
labelled
ready-for-human(that label is for work only a person can do; list those issues under Risk in the close-out recap instead of building them).
Compare the Files blocks of the frontier issues: issues whose file sets don't overlap can run at once; issues that share a file go into one lane and run in order. How many issues you take on at once is your judgment; there is no size rule.
-
Set up the feature branch. Work in a worktree on a feature branch named for the parent issue; if you are already in one, use it. Open a draft PR only when the tracker closes work through PRs (its reference in
docs/agents/issue-tracker.mdsays an issue closes when its pull request merges) or the user asks for one. That PR waits until the first issue lands on the branch (step 5), because the forge rejects a PR with no commits over its base. Committing, pushing this branch, and opening the draft PR need no one's OK; merging it does. -
Work the frontier.
- One issue, or one lane, outside a lane-routing run: do it yourself in this session. Load
compost:build, thencompost:verify. A subagent for a single issue only adds a handoff. - Several independent issues or lanes: a lane earns a subagent when its work outweighs the
handoff: a brief, a worktree, a merge, and a report to read. Lanes that are each a short edit
(a doc fix, a config value, a few lines in one file) don't; work them yourself, in order, as
above. Spawn the rest, one subagent per lane in a single message, so the lanes run in
parallel, each with
isolation: "worktree"and in the background, without asking. A lane of one issue is just that issue; a worker with a longer lane works its issues in order. In a lane-routing run every lane spawns, whatever its size. When agent teams are enabled (CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1), spawn them as named teammates instead; a teammate spawn cannot takeisolation, so its brief tells it to create its own worktree first. - Before starting an issue, in a lane or yourself, push its branch name at the feature SHA
(
git push origin <feature SHA>:refs/heads/<issue>-<slug>), so a session in another clone sees the issue as taken. - An isolated worktree starts from the default branch, not the feature branch. Every brief names the feature branch's head SHA, and the worker switches to it before any work.
- Write each brief from references/task-brief.md: the issue, its
acceptance criteria, its Interfaces block, the
CONTEXT.mdterms it uses, and pointers to any rulings that touch it. Size the brief to the issue; a one-file change gets a paragraph. - Leave
modelandeffortunset on every spawn, so each lane inherits yours, except in a lane-routing run. A run is one when its ask is to tier the lanes by model or to run the untiered control a tiered run is compared against, or when the parent's latest "Lane routing:" comment is not "ended". In a lane-routing run, references/lane-routing.md decides how every lane spawns, a lone lane included, and whether a leftover marker still applies. -
Keep a rolling window, not batches: when one worker finishes, spawn whatever its landing unblocked right away instead of waiting for the slowest sibling.
-
Land each finished issue. A completion is an event to handle, not a review to do inline. Read the worker's short report; if it says
DONE_WITH_CONCERNS, read the concerns first. Once its branch is merged, apply any AC-table row retirements it reports (compost:verifystep 5), and refresh the committed AC-table cache if the verify command keeps one. Merge its branch into the feature branch with--no-ff, then run the suite on the feature branch; a merge is a change like any other. A red suite after a merge goes tocompost:diagnose. When the repo's instructions want a version bump for a changed package, commit it right after the first landing, before the first push, so the PR's checks are green from its first run, and again after any later landing that first changes another package; lanes still leave versions alone. After the first landing, push the branch and, when step 3 calls for a PR, open a draft PR whose body closes the parent and every sub-issue ("Closes #12, closes #13"), leaving outready-for-humansub-issues, and the parent while any of those is open. -
Review every issue. Load
compost:reviewfor the issue's commits. It runs the/compost:review-changesworkflow through subagents; you never wait to be asked. Scope it to the one issue: for an issue landed by a merge, passbaseas<merge>^1,headas<merge>^2, andissueas its number; for one built in this session, passbaseas the parent of its first commit andheadas its last. No issue skips review for being small: the workflow gives a small diff its light path, one reviewer on both axes, and that is the cheap option. Take its findings through the reception protocol there: check each against the code, fix what holds, and rule on what doesn't. - Fix findings where the work was done: resume the worker that built the issue with the findings
verbatim, or fix them yourself when you built it. Each fix is seen failing before it passes, then
compost:verifyruns again. A worker's fixes land on its own branch, so land it again (step 5) before the re-review. -
If three rounds of fixes still leave findings open, stop the loop. Count rounds from the issue's
compost:reviewcomments, each headedReview round <n>, not from memory, so the cap holds across a pause or a compacted context. Rule on each remaining finding (park it, or make the smallest change that unblocks dependent issues) and post the ruling. A loop that won't converge is a design problem, not an effort problem. -
Record progress. When an issue passes review, tick it on the parent's checklist (only this skill ticks the parent; workers tick their own issue's AC boxes) and comment on the issue with its commits and the verification you ran. With no PR to close it, close the issue the way the tracker says; with a local tracker that is
Status: closedand a closing note in the issue file. Then recompute the frontier and go back to step 4. The checklist and git log are the progress record; there is no other. -
Step sideways when the work calls for it. A defect you can't fix on sight goes to
compost:diagnose; a question about a module's shape or an interface goes tocompost:deepen. Both hand back here. An issue that turns out bigger than its acceptance criteria goes tocompost:slicefor a follow-up issue rather than growing in place. -
Decide, log, proceed. Every judgment call you make on the user's behalf (an ambiguous criterion, a spec conflict, a library choice, a finding you decline) is posted as a comment on the issue it concerns, then you keep going:
markdown
**Ruling:** what you decided
**Why:** the reason, citing the doc or line when it rests on an external fact
**Cost if wrong:** what it takes to undo
Then ask Jev whether the ruling deserves an ADR: run adr-worthy with the ruling's fields and
write one in docs/adr/ only on offer_adr (jev). Exit 3 means Jev
is unavailable: apply the three tests in domain docs yourself.
A wrong ruling costs a review comment; a stalled run costs the user's day. Stop only for:
- merging to the repository's default branch;
- a force-push or a history rewrite on a shared branch;
- a deploy or release, including one flagged for the user's approval;
- deleting data;
- a message that reaches people beyond the run's own issues: an email, a chat post, or a
comment, mention, or review request on someone else's issue or pull request;
- approval of an architectural spec: one never approved (step 1), or one the work shows has
to change;
- starting a Claude Code workflow the agent wrote itself, since one can spawn dozens of agents
(the plugin's own /compost:review-changes needs no ask). When a job fits codify the orchestration,
propose it in a ruling comment and carry on without it.
compost's Stop hook holds you to this list during an implement run: when your last message waits
on the user for anything else, Jev flags it and the hook sends you back to post a ruling and
continue. The run ends when compost:finish loads, or compost:pause once the user has sent a
message during the run; a pause you start on your own leaves the guard on, so stop only for the
list above (resuming loads implement again, which starts a new run). A turn that answers a
message the user typed is attended, so waiting on them there is allowed.
When the run repeats a mistake (a command that needs a flag, a fixture that lies, a service that
must be up), record the gotcha with compound-knowledge:compound-capture if it is installed, so
the next run starts knowing it; otherwise note it on the parent issue. A note is the lowest level
of fix: when a check could catch the mistake instead, file an issue for that check
(make mistakes impossible).
- Close out. When the frontier is empty and every sub-issue is ticked, except those labelled
ready-for-human, runcompost:verifyon the whole feature branch, push, and hand off throughcompost:finish, whose recap is Goal, Decisions, Changes, Validation, Risk. The Decisions section lists every ruling comment, each with its cost if wrong. A lane-routing run lists its per-lane records in Validation. Without a PR, report the feature branch by name, since no PR link points to it, and leave the parent open:compost:finishcloses it once the branch merges. Clean up worker worktrees whose branches are merged into the feature branch, and delete the issue branches step 4 pushed from the remote (git push origin --delete <issue>-<slug>).
For a run that outlives the session, compost:pause writes the checkpoint and resuming starts at
step 1.
Next moves
compost:finishwhen every issue but theready-for-humanones is reviewed and the feature branch passes verify.compost:diagnosewhen a test, merge, or behavior breaks and the cause isn't obvious.compost:deepenwhen an issue raises a design question about a module or interface.compost:fan-outwhen a ruling has two or more defensible designs worth building side by side.compost:pausewhen the session has to stop before the frontier is empty.