/steer:work¶
Execute a GitHub issue end-to-end from local Claude Code — the execution
counterpart to /steer:issues (which owns backlog management and
never edits code).
When to use
Use to start, resume, check, or finish a specific issue.
Argument hint: [start | resume | status | finish] [--reviewed | --hotfix] [#issue ...]
--reviewed — the review-gated path
Add --reviewed to wrap execution in the review loop formerly carried by the
standalone deliver skill: an independent plan-gate review → implement →
/code-review gate → bounded fix. The shared protocol lives in
templates/reference/REVIEW-LOOP.md.
--hotfix — the production-incident fast-path
Add --hotfix only for a genuine production incident — a change to an
already-deployed system with real users/data and an active outage or
regression (rule 62-hotfix). "Urgent" feature work is not a hotfix. The lane
relaxes ceremony and ordering — the issue may be filed after-the-fact on a
hotfix/<n> branch, one reviewer approval suffices — but keeps every human
authority gate (merge / deploy stay human-gated; pushing the branch and
opening the PR are autonomous, as everywhere). Once the fire is
out, a mandatory follow-up backfills the issue, the spec/ADR, and a
/spec/history/ entry: Definition of Done is deferred, never waived.
End-to-end flow¶
flowchart TD
START["/steer:work start #123"] --> VALIDATE[Read + validate the issue]
VALIDATE --> CLAIM[Claim it · self-assign · set in-progress]
CLAIM --> BRANCH[Create or reuse issue/* branch + work marker]
BRANCH --> SPEC[Load linked /spec]
SPEC --> IMPL[Implement + test<br/>commit autonomously]
IMPL --> PROGRESS[Update progress on the issue]
PROGRESS --> FINISH["/steer:work finish #123"]
FINISH --> PR[Open PR]
PR --> WATCH[Watch CI to conclusion]
WATCH -->|red| FIX[Fix · re-push · re-watch]
FIX --> WATCH
WATCH -->|green| STATE[Transition to validate · hand reviewer a green PR]
Delivery mode¶
How the work reaches main is governed by the repo's delivery mode, declared
in the product CLAUDE.md ## Delivery mode section (the same marker the steer
hooks read — solo-trunk vs pr-flow; absent or unreadable → pr-flow).
Issue-first holds in both modes — every implementation-affecting change above
Tiny is tied to a GitHub issue; the modes
differ only in the branch/PR ceremony around it.
| pr-flow (default) | solo-trunk (pre-MVP greenfield) | |
|---|---|---|
| Branch | issue/<n> branch + spec/.work marker |
none — commit straight to main |
| Marker | written for Stop-hook reconciliation | skipped (stay on main) |
| Delivery | push + open the PR autonomously; the merge review is the human gate (server-enforced by branch protection) | Closes #N trunk commit + push under Commit autonomy (rule 45) |
| Terminal evidence | merged PR | closed issue from the trunk commit |
Determine the mode once at start / finish. In solo-trunk, wherever a step below
says branch, marker, or PR, skip it and substitute the trunk commit —
validation, managed-block progress, CI-watch (via gh run watch on the trunk push),
and the Definition of Done are unchanged. Committing to main is authorized in this
mode; deploy stays human-gated all the same, and graduating the repo to the PR
flow is /steer:protect's job, never this skill's.
Modes¶
| Mode | What it does |
|---|---|
start |
Validate, claim (self-assigns the invoking GitHub user), branch + write the work marker (pr-flow) or stay on main (solo-trunk), load specs, begin implementing. |
resume |
Pick a claimed issue back up where it left off — including offering to re-enter the Claude Code session that last worked it. |
status |
Report progress on the issue(s) — read-only. |
finish |
Open the PR (pr-flow) — the first push of the new issue/<n> branch sets the upstream (git push -u origin <branch>; later pushes are a plain git push) — or commit straight to main with a Closes #N trailer (solo-trunk), watch CI to conclusion (gh pr checks --watch, or gh run watch on the trunk push) and fix a red build before transitioning to validate — the reviewer gets a green PR, not a running or red one. |
Closing refs across repositories¶
GitHub honours issue-closing keywords only within one repository. If
/spec/tracker.md declares a repository: other than the repo the code lives in
— a team centralizing issues in a dedicated tracker repo, or a polyrepo member
whose spine lives in the workspace — then Closes #N renders as a plain
cross-reference and the issue silently stays open. Nothing warns, and because
finish reads the merged PR as its lifecycle-transition evidence, the issue never
advances state either.
finish therefore resolves both sides before writing any closing ref: the
declared tracker (steer_tracker_repo, lib/scope.sh) against the actual repo
(gh repo view --json nameWithOwner).
In a polyrepo member
the mismatch is structural rather than incidental — the tracker is always the
workspace's — so the explicit-close path is taken every time. start also
resolves the spine from spec/PRODUCT.md before reading the tracker or a
feature's specs: a member carries neither spec/tracker.md nor
spec/features/**, and a missing local intent.md means the workspace has not
been read yet, never that the feature is unspecified. The spec update that a
behavior change requires lands as its own change in the workspace repo.
| Closing ref | Who closes the issue | |
|---|---|---|
| Same repo, or either value unreadable | Closes #N — unchanged |
GitHub, on merge |
| Proven mismatch | Refs owner/repo#N |
/steer:tracker-sync close, after the merge |
Only a demonstrated mismatch diverts. An absent tracker file, an unresolved
[owner/repository] placeholder, an empty value, or a failed gh call all keep
Closes #N, so the ordinary same-repo path is untouched. In solo-trunk the same
rule governs the commit trailer — and matters more there, since the closed issue
is the only terminal evidence.
Local work marker¶
start writes a local, git-ignored marker at spec/.work/<branch>.md (slashes →
underscores). Its existence is what the end-of-turn
Stop-hook reconciliation uses to recognize a branch as
issue-governed — ahead of any branch-name guess — so an unconventionally named
but properly claimed branch is still recognized.
The marker also records a newest-first list of the Claude Code session(s)
that worked the branch. The Stop hook keeps the most-recent session at the head
each turn, and resume reads it: if a different prior session is recorded, it
offers claude --resume <id> (and the transcript path) so you can re-enter that
conversation for context. These session ids are local-only breadcrumbs — they
stay in the git-ignored marker and never reach the tracker.
Rules it follows¶
- One issue per branch/PR by default (in solo-trunk, one trunk commit per
issue, each closing its own
#N). - Git and PR delivery follow the repo's commit-autonomy rules — commits, pushes, and opening the PR are autonomous; merging is gated. See the Authorization model.
- After pushing,
finishwatches CI to green and fixes a red build before treating the work as done — the skill pre-approvesgit push/gh pr create|editplus read-only CI status (gh pr checks,gh run view,gh run watch) for this; the merge step stays gated. If you have stepped away, the in-turn watch blocks the turn; re-enter monitoring by re-runninggh pr checkson a loop (steer ships no background poller). Merge and deploy remain a human's call. - All tracker-metadata I/O routes through
/steer:tracker-sync.