Implement a GitHub ticket with checks and a reviewed PR. Use the supplied ticket number and repository,
defaulting to the current gh remote and step 0's selection. Solo runs load orchestrator-mode in standing
mode first: the main thread coordinates, and workers complete Setup, then steps 0
through 8. Workers cannot invoke a user-only skill, so each handoff names this skill's root by path and the
steps the worker owns. A worker reports an auto-pick, a stop condition, or a question through
open_questions; the coordinator puts it to the user and dispatches the answer.
Orchestrated dispatch
For a feature dispatch, read references/orchestrated.md first. Skip steps 0 through 3, use step 4 for local exploration, then follow steps 5 through 7 and self-review in step 8. The coordinator owns PRs, issue actions, and independent review.
Workflow
Implement what the ticket asks, at the scope it asks for. Adjacent bugs, drive-by refactors, and missing tests outside the acceptance criteria get reported in the PR body (or open_questions under an orchestrated dispatch), not fixed here.
Make the smallest change that solves the ticket. Prefer deletion over addition, keep the call hierarchy flat, and put each decision in one place; a diff a maintainer would find exhausting is the wrong solution. The principle-laziness-protocol skill, when installed, is the full protocol; follow it.
Apply Writing to authored prose using technical-writing and unslop. Include the resolved writing references in worker briefs. Solo PR creation and updates follow PR body, which uses pr for structure and preserves the repository template.
Use configured execution permissions. Run commands normally. If a necessary command is blocked, use the available scoped escalation and report a denial accurately. The task's existing authorization governs external mutations. Reuse the user's authorization for lifecycle comments without asking again. Record which assignments and labels this run changes and alter only those on a stop path.
Ticket lifecycle comments
Post a comment on the ticket when starting work and when stopping work on each attempt, including resumes. In solo runs, the implementing agent posts both comments. In feature runs, the coordinator posts them through its tracker worker on behalf of the implementing worker.
- Start: after eligibility and workspace preflight, before implementation, post "Started
work on # on branch
<branch>." Identify a resume and the integration branch when relevant. - Stop: before ending the attempt, post "Stopped work on #: ." Cover completion, blockers, failure, pause, cancellation, and handoff. Include the PR or preserved branch and HEAD, what remains, and any failed checks or required decision. A successful worker return says "implementation complete, awaiting integration" until integration is verified.
Use gh issue comment <N> --repo <owner/repo> --body-file <comment-file>. Record the returned comment URL in
the findings or run record. A local draft or chat update does not satisfy this step. If posting is prohibited
or fails, retain the body and report the missing comment and reason. Check ticket comments before retrying an
uncertain post. On recovery from an abrupt interruption, reconcile the prior attempt's missing stop comment
before posting a new start.
0. Resolve the ticket number
If the user provided a number, use it as <N>. Otherwise auto-pick the lowest-numbered open ready-for-agent ticket, excluding specs, unassigned and free of stop-condition labels, with the query in references/auto-pick.md (read it first: it paginates before selection). If it returns a ticket, announce the pick (number + title) before proceeding; if the user declines it, exclude that number and take the next survivor. If it returns null or nothing, stop and ask; do not implement a spec directly (specs get broken into tickets first, e.g. via a to-tickets skill).
1. Read the ticket and claim it
gh issue view <N> --comments: read the body AND comments. Note title, acceptance criteria, blocked-by links, and scope labels (needs-info, wontfix, etc. → stop and ask, with one exception: needs-info applied by a prior agent's own stop (its findings comment is on the ticket) when the user explicitly named this ticket resolves that prior stop; defer any label change until ownership and workspace preflight pass). Before claiming, confirm it is a ticket, not a spec: a body with no concrete acceptance criteria that reads as a multi-ticket document (solution/scope sections, user stories, several independent deliverables) is a spec the auto-pick regex missed. Stop and ask. If assigned to someone else, surface that before any issue mutation. An assignment to self is advisory, not an exclusive lock. Complete the base and workspace preflight first; then claim within existing authorization and record whether this run added the assignment. Post the start comment after step 3 completes.
2. Pick a base branch
- Default base and
pr_base: the repo's default branch (gh repo view --json defaultBranchRef). - Detecting blocked-by: check GitHub's native issue-dependency (blocked-by) data first (
gh apidependencies endpoint, sub-issue parentage is not a blocking relation), then also scan the body: a## Blocked bysection, lines likeBlocked by #12/Depends on #12, task-list references inside a dependency section, or ablockedlabel requiring investigation, either source alone may carry an edge. - If open blockers have branches, choose a base containing every required blocker tip. For a stacked ticket, record the blocker branch as the PR target and explain the dependency. Independent blocker branches need a combined authorized base or a surfaced dependency decision; selecting one does not satisfy the others. Record both the immutable
base_shaand explicitpr_base. - If the blocker has no branch yet, stop and surface to the user. Don't branch off nothing or implement the blocker yourself.
3. Create the ticket branch
Check applicable branch conventions and git status --porcelain. Preserve unrelated dirty work in place and
use an isolated checkout if needed. Ask only about required uncommitted inputs or overlapping edits whose
ownership is unclear; do not automatically stash or reset. Fetch the intended base and pin base_sha. Use the
environment's branch prefix, keeping ticket-<N>-<slug> in the name. Recognize older feat/ticket-<N>-* and
feat/issue-<N>-* branches when investigating resumes. Create the branch from the SHA, not a moving branch
ref.
For a prior attempt, read its findings and compare local and remote tips before choosing it. Multiple
candidates require evidence of which attempt belongs to this task. Preserve the existing WIP tip; work on a
fresh attempt branch before rebasing onto base_sha when rewriting a pushed branch is not already authorized.
Abort an unsuccessful rebase explicitly. Keep its saved tip and findings available if rebuilding from the base
is necessary. Report the actual branch and preservation state, including any push failure.
Post and record the start comment before proceeding to step 4.
4. Explore before editing
Grep/search for the modules the ticket touches. Read AGENTS.md, CONTEXT.md, and ADRs in docs/adr/ for invariants. Match existing patterns; don't introduce new infrastructure (test framework, linter config) unless the ticket asks for it.
For solo runs, identify the feedback-loop commands: the type-checker/linter (e.g. mypy, pyright, ruff) and the test command (e.g. pytest), plus the run command (AGENTS.md, pyproject.toml, Makefile, package.json scripts, CI workflows, docker-compose.yml). Run the configured type-check/lint and test commands on the pinned clean base_sha before editing, or reuse an original baseline with that proven SHA. On resume, use a separate checkout for this base check; failures on the WIP branch remain separate and cannot become baseline exemptions. Record commands, checked SHA, and original failures.
Done when you have: (a) the type-check and test commands, (b) the run command, and (c) recorded baseline results for all configured checks. Mark absent commands as absent, not passing.
5. Implement
Before choosing a path: an acceptance criterion that is subjective or unverifiable ("looks right", "feels fast") is the ambiguous-acceptance-criteria stop condition, whichever kind of work the ticket is. Untestable is not the same as unspecified. A criterion tied to a concrete reference artifact (design mockup, screenshot, spec doc) is untestable but specified: take the "everything else" path and record the manual comparison against the artifact in the PR body. The stop is per criterion: name the ambiguous ones in your question rather than declaring the whole ticket ambiguous. Then recognise what kind of work the ticket is; it decides how you build:
- Testable backend work (a service, pipeline, API, library function with a working test suite and acceptance criteria that describe verifiable behaviour): build it in tracer bullets: the red → green loop, one test at a time. One failing test (red), then the minimal code to pass it (green). Don't write all the tests up front; each test responds to what the last one taught you. Refactoring is not part of the loop. It belongs to the step 8 review pass. Follow the
tddskill for the full loop. Thetddskill expects tests at pre-agreed seams: with no user in the loop, the ticket is that agreement: place tests at the seams its acceptance criteria and the existing test layout imply. If no sensible seam exists for a criterion, treat it as ambiguous acceptance criteria (a stop condition), not a licence to test implementation details. - Everything else: frontend code (the suite doesn't cover it), exploratory data analysis, notebooks, one-off scripts, or any change where no test can pin the behaviour: implement directly and lean on the step 6 feedback loop and the step 7 smoke check instead. Mixed tickets split by part: tracer bullets for the testable seams, direct implementation for the rest. Say which path you took.
Throughout:
- In solo runs, open a draft PR within the first 1–2 commits. Follow PR body, including pending evidence and
Closes #<N>. Push the branch, then usegh pr create --draft --base <pr_base> --head <ticket_branch> --title "<title>" --body-file <body-file>. Reuse an existing branch PR on resume. If publication fails, preserve the body, keep implementing locally, and report the error. - Capture before/after observations with their commands, commits, and artifact paths as you work. Preserve red-test output or the prior artifact for the PR's Evidence section.
- Keep the loop tight while building: type-check and run the single test file you're touching as you go; save the full suite for step 6.
- Keep commits scoped and conventional (
feat:,fix:,test:, …).
6. Feedback loop: types + tests (REQUIRED before marking ready)
Commit intended changes before final checks. After fixes, commit again and record the checked SHA with each result so review and publication can identify the tested tree.
Run the type-checker/linter, then the test suite from step 4, and loop until both are clean: type-check → fix → test → fix. Everything green at baseline must still be green; new failures and new type errors are yours to fix. If acceptance criteria describe verifiable behaviour and the project has a test suite, add tests covering it, matching existing style. If the project has no type-checker or test suite, note it and rely on the step 7 smoke check.
7. Runtime smoke check (REQUIRED before marking ready)
Verify the changed artifact before declaring done. Pick the applicable branch:
- Long-running app (server/web): start it in the background with the run command; wait for the ready signal (port listening, "compiled successfully", health 200); exercise the changed behavior through a relevant endpoint or UI; read the last ~50 log lines for tracebacks/warnings introduced by your change; stop it cleanly.
- CLI / library / script / pipeline (no port): run the entrypoint once with a representative invocation:
<cli> --helpplus one real subcommand, import the package and call the changed API, or execute the flow once against safe inputs. Confirm exit code 0 and no new tracebacks. - Docs or configuration with no runnable entrypoint: run the relevant validator and inspect the rendered or consumed artifact. Record why runtime execution does not apply.
Allocate separate ports and test resources for parallel workers, or serialize shared-state checks. Missing credentials or tools are blocked checks, not passes. Fix failures and retry proportionately; preserve a concrete blocker when further authorized progress is unavailable.
8. Review, then finalise the PR
Read the committed git diff <base_sha>...HEAD and fix in-scope findings, including refactoring deferred from
step 5. Commit fixes and rerun steps 6 and 7 for affected paths. Feature workers return through their
orchestrated contract without nested review.
Solo runs follow Independent review with the pinned base and ticket snapshot, then Solo finalization.
Stop conditions
Stop and surface to the user (do not improvise) if:
- The ticket is labelled
needs-info,wontfix, orneeds-triage, or is already assigned to someone else. - Acceptance criteria are ambiguous or contradict the codebase's invariants.
- The ticket is blocked by a ticket/PR that has no branch yet.
- Required uncommitted inputs or overlapping work cannot be used safely without a user decision.
- A required check is blocked and diagnosis or a different authorized approach cannot make further useful progress. Repeated identical failures call for a changed approach, not an arbitrary claim of completion.
When stopping, preserve work and report the actual branch, HEAD, worktree path, dirty files, and push outcome. Push WIP when authorized; a failed push leaves local work that must remain. Record the failure, attempts, and pending decisions in a local findings artifact. Post and record the stop comment with these findings. Leave any draft PR open and report its state accurately. In solo runs, release only a claim this run added; label changes require lifecycle ownership and existing authorization. In orchestrated runs, the feature coordinator owns the lifecycle.