Instal·la
npx skillscat add varigg/agent-driven-development/addw-implement Instal·la des del registre de SkillsCat.
Implement Mode
You are implementing one ticket — a single GitHub issue — and you stop when its pull
request is open. The human reviews and merges it; nothing here touches the main branch.
Every tracker operation goes through the tracker layer at.claude/skills/lib/tracker/tracker.sh. Never call the tracker CLI directly for issue reads,
labels, comments, assignment, or closure. Pull-request operations are not tracker operations
and use gh pr directly.
Bare Invocation — the Frontier
Invoked with no issue number, list what can be started and stop:
bash .claude/skills/lib/tracker/tracker.sh frontierThe four sections are fixed. frontier is what is workable now — tickets annotated[in progress: …] already have a branch or an assignee, so pick an unannotated one unless
you are resuming your own work. needs-rescoping and unknown-blockers are for the
human, not for you: report them and do not start those tickets. complete-specs means a
spec has no open child left — surface it so the human can close it with the command each
line names (tracker.sh close-spec <n>); a release closes no spec (ADR 0011).
Step 1: Mode Detection
Before anything else, check whether the ticket already has an open PR:
gh pr list --state open --search "<issue-number>" --json number,headRefName,urlConfirm the match is real (the PR closes this ticket) rather than a coincidental number.
- Open PR exists → Mode A: Review-Comments Resume.
- No open PR → Mode B: Fresh Build.
Getting this backwards restarts finished work, so resolve it before reading anything else.
Mode A: Review-Comments Resume
The human has reviewed and left feedback. Same skill, not a separate procedure.
Check out the PR's branch and read all the feedback. A Mode-B session may have
built this ticket in its own worktree (§ Step 3), which still holds the branch checked
out — git refuses to check it out a second time in this checkout, so look for that
worktree first and enter it rather than checking out in place:branch="$(gh pr view <n> --json headRefName -q .headRefName)" wt_path="$(bash .claude/skills/lib/worktree/find.sh "$branch")" [ -n "$wt_path" ] || gh pr checkout <n>When
$wt_pathis non-empty, switch the session into that worktree andgit pullthere.
Either way, the rest of this session runs from that directory —$wt_pathor this
checkout, whichever it resolved to. Two reads, not one, for the feedback itself — the conversation
timeline and the comments anchored to diff lines are different endpoints, and inline
comments are where most review feedback actually lands:gh pr view <n> --comments # timeline + review summaries gh api "repos/{owner}/{repo}/pulls/<n>/comments" --paginate \ --jq '.[] | "\(.path):\(.line // .original_line)\t\(.user.login): \(.body)"'No
gh prsubcommand exposes inline comments (cli/cli#5788), so the API read is not
optional. Skipping it produces the worst failure this mode has: reporting feedback
addressed while never having seen it.Also run
bash .claude/skills/lib/tracker/tracker.sh approval-drift <issue-number>—
the final review round posted the ticket's approval marker, so drift from the body the
verdict judged is one command. Surface drift before addressing anything: the feedback
may be responding to a ticket the verdict never saw.Address the feedback. Push back in a PR reply where a comment is mistaken — agreement
is not the goal, resolution is. Commit with explicit paths and a conventional subject.Re-run the gate (Step 9) and refresh the PR body's gate summary — a stale summary
is worse than none, because it reads as current evidence.Re-enter the codex loop by judgment. Substantive changes — new logic, changed control
flow, a different approach — earn another round. Comment-only or rename-only changes do
not. If you skip the loop, the PR body must say which commit the recorded verdict covers,
so the gap between the verdict and HEAD is visible rather than implied.Push, then update the PR body, and stop. Do not merge. Push before touching the body:
a body advertising a gate summary and a verdict SHA for commits that exist only on your
machine is evidence for a PR the reviewer cannot see.
Mode B: Fresh Build
Step 2: Eligibility — read-only
Nothing is written until the ticket is confirmed workable:
bash .claude/skills/lib/tracker/tracker.sh view <issue-number>The ticket must be open, labeled ready-for-agent, and labeled neither spec norbacklog — a spec is decomposed by to-tickets, not implemented. Every issue in its## Blocked by section must be closed as completed: a blocker closed as not planned
never unlocks it, and the ticket needs human re-scoping instead. Its ## Parent section is
read when present but never required — standalone tickets are workable.
Those checks are mechanical; one judgment call remains. A ticket carries exactly one
Deliverable — an independently-checkable unit of work, one a reviewer can verify passed or
failed without reference to the ticket's other criteria. Read the acceptance criteria and
judge their breadth: criteria that can pass or fail independently of one another mark a
bundle of Deliverables. A bundled ticket is not started — report it for rescoping, the
same human-facing disposition the frontier's needs-rescoping section gets (that section
itself stays mechanical and will never list the bundle; the report is yours). Decomposition
should have split it, so this is a backstop, not a routine gate; but breadth is not
mechanically computable, so no script runs the check for you.
Stop and report if any of that fails. Derive the branch slug from the ticket title: a few
lowercase, hyphenated words, no issue number in the slug itself.
Step 3: Branch and Self-Assign
The branch and the assignment are the in-progress marker the frontier listing shows —
not a lock. Push before building, so a second session sees the work exists.
eval "$(bash .claude/skills/lib/config/vars.sh ADDW_MAIN_BRANCH || echo "(exit $?)")"Four outcomes. The branch name is the only shape they prescribe; where the branch is
checked out is decided from the clone's observable state, not from a config key.
The ticket branch
<type>/<issue-number>-<slug>starts from the remote main —origin/$ADDW_MAIN_BRANCHafter a fetch — never from this checkout's own$ADDW_MAIN_BRANCH. Agit checkout && git pullhere is exactly the shared-working-tree
collision this rule exists to remove when another session is mid-ticket, while a plaingit fetchtouches no working tree or index and is safe with another session doing the
same thing at once.feat/,fix/,docs/— the type the work will carry.The branch is checked out somewhere the rest of this session runs from, without
disturbing another session's checkout. Read the clone to decide where. When it sits
clean on$ADDW_MAIN_BRANCH— that branch checked out, nothing modified or staged —
nobody else is using this checkout, and in place is fine:git fetch origin "$ADDW_MAIN_BRANCH" git checkout -b <type>/<issue-number>-<slug> "origin/$ADDW_MAIN_BRANCH"Anything else — another branch checked out, a dirty tree — is a session's work in
progress, possibly your own, and this ticket gets a separate worktree. A second session
arriving while the first works in place sees exactly that and isolates itself; that is
the whole rule.worktree/create.shis the portable way to get one:bash .claude/skills/lib/worktree/create.sh "$ADDW_MAIN_BRANCH" \ <type>/<issue-number>-<slug> <path>It fetches and branches off the remote-tracking ref (outcome 1) and, in this repo's own
dogfood setup, recreates the gitignored.claude/skillssymlink inside the new worktree,
pointed at its own trackedskills/copy — a no-op wherever.claude/skillsis an
ordinary tracked copy, as in a real install.<path>is yours to choose: somewhere this
harness can make its working directory, and that stays out of the clone'sgit status.Every later step runs from the checkout holding the branch — Steps 5 through 11,
the Step 6 delegate call included, since the adapters are cwd-scoped. When that is a
worktree, switch the session into it; the mechanism is yours to choose for your harness.Push and self-assign from that checkout:
git push -u origin <type>/<issue-number>-<slug> bash .claude/skills/lib/tracker/tracker.sh assign <issue-number>
If the branch already exists on the remote, surface that to the human before proceeding
— somebody, possibly you in an earlier session, has already started.
Step 4: Read the Ticket and Its Spec
Read the ticket body in full, then the parent spec when the ticket names one
(tracker.sh body <parent>) — the spec carries the decisions the ticket assumes. After
reading the parent spec, runbash .claude/skills/lib/tracker/tracker.sh approval-drift <parent>. If it reports drift,
surface it to the human before building — the tickets may descend from content the spec
reviewer never saw. no approval hash recorded needs no action; it identifies a pre-feature
approval. Then read docs/ARCHITECTURE.md, the glossary — CONTEXT.md at the repo root, or
the per-context files a root CONTEXT-MAP.md points at, fixed to Matt's own convention and
never project-declared (ADR 0014) — and the ADRs at the location the domain-layout contract
(docs/agents/domain.md) declares. Never hardcode the ADR path.
Step 5: Frozen Contract Tests
If the ticket touches the critical-path floor — auth, deletion, persistence, cost, or
external request shape — write those tests now, before any implementation:
- Author behavioral tests from the ticket's acceptance criteria, following the project's
testing guide. - Confirm they fail for the right reason.
- Commit them with explicit paths:
test: add contract tests for <ticket>.
They are off-limits to the implementer — say so in its instructions. If an interface
mismatch surfaces later, you fix the test yourself and say why in the PR body. Work outside
the critical-path floor skips this step; its tests are authored in Step 9. Freezing is an
agent discipline against implementer drift, not a human gate: test code receives no
pre-Boundary approval — PR review is where tests are judged, like every other part of the
diff (ADR 0005).
Step 6: Implementation
The implementing agent is the role key ADDW_IMPLEMENT_SKILL in docs/addw.env:
The reserved value
inlinemeans no adapter — you drive thetddskill yourself in
this session. Never invoke Matt'simplementskill;tddis the programmatic primitive.
If notddis installed, drive the discipline directly — failing test first, then the code
that passes it. The skill encodes the loop; it does not own it.Any other value names an adapter skill, invoked through the adapter contract. The issue
number is the target, so the thread keys per ticket; the instruction block carries the
scope, because the adapter cannot read the tracker:eval "$(bash .claude/skills/lib/config/vars.sh ADDW_IMPLEMENT_SKILL || echo "(exit $?)")" bash ".claude/skills/${ADDW_IMPLEMENT_SKILL:-codex-implement}/scripts/start.sh" \ <issue-number> "<what to build, from the ticket and the spec's decisions>. \ Make the tests in <paths> pass. Do NOT modify any test file."You have read the ticket and its spec; the adapter has not. State the scope in your own
words — what to build, what to leave to a later ticket, which conventions bind — rather than
pasting the ticket wholesale. The instruction block must also name any ADRGatebearing on
the ticket's work: the adapter cannot read the tracker and is never told to read the ADR
directory, so a constraint reaches it only if you carry it. Parse the
trailing tag:IMPLEMENTATION_COMPLETE→ proceed.IMPLEMENTATION_PARTIAL→ read the report, thenresume.shfor the remainder or finish
small leftovers yourself.The adapter runs in a sandbox —
codex-implement's is workspace-write with no network —
and three of its refusals shape how you read the report. It cannot write.git: you
commit, and a git-write failure in the report is the sandbox, not the repository. It has
no package registry: a dependency reported as a leftover is yours to install and lock
here, outside the sandbox. And a "suite blocked" or "hangs" claim is unverified until
you re-run the command outside the sandbox — sandbox hangs are usually sandbox artifacts,
not defects, and one filed as a ticket sends a human chasing the sandbox.
Either way, read the full diff yourself afterwards against the ticket, ARCHITECTURE.md
patterns, and project conventions. What happens to a problem depends on whether the ticket
covers it:
In scope — a finding against the ticket's own Deliverable: fix it in-branch yourself,
never ping-pong fixes back to the adapter.Discovered work — work outside the ticket's acceptance criteria, however small it
feels mid-flight: it does not ride the PR. File it and move on:bash .claude/skills/lib/tracker/tracker.sh create "<conventional subject>" <body-file> backlogbacklogbecause frontier entry is a spending decision that stays human (ADR 0005
gate 3) and the PR ships one Deliverable (ADR 0006). Deliberately no merge-graduation
via the PR body naming the filing: a mid-implementation discovery has no prior
authorizing act, unlike the hotfix follow-up — graduation is an explicit human label
flip.Mechanical drive-bys — formatting on a line the diff already touches — are not
"work"; just do them.
Commit with explicit paths (never git add -A, never "wip") and a conventional subject.
Step 7: Cold Pre-Filter Review
Run a cold code-review over the branch diff before spending codex rounds. It breaks
ownership bias: you are reviewing your own work, and a cold read catches what a warm one
cannot. Matt's is the one this step was written around, but nothing turns on whose prompt
runs — any competent two-axis review earns the same thing, and a plain instruction to review
the diff against the ticket is a fair substitute where no skill is installed. Name in the PR
body which one ran, since more than one plugin publishes a code-review and "the pre-filter
ran" should not imply a skill that did not.
Skippable by judgment for a genuinely trivial diff — two nets remain (the codex loop and
human review). A skip is not free: it is disclosed in the PR body, with the reason.
Step 8: Doc Impact
If this ticket changed documented design, update the affected living-doc passages now —
ARCHITECTURE.md, the charter, an ADR — so the reviewed diff carries them and the docs are
reviewed alongside the code that changed them. A new decision gets an ADR from the project's
template, with the ticket or PR as its Origin; use .claude/skills/lib/docs/next-adr-number.sh
to get its number.
A document this ticket made untrue leaves the tree here. This is the only step in the
workflow that archives one — everywhere else a stale document is noticed, it is filed as a
ticket that arrives back here:
bash .claude/skills/lib/docs/archive-doc.sh <path> <adr|proposal> "<why it stopped being true>"The test is "is this still true?" — never "is this about the past?" A document may narrate
history and remain entirely true: rejected alternatives, incident notes, and an ADR's own
reasoning are the highest-value content in a tree precisely because the code cannot supply
them. What leaves is a document making present-tense claims about a tree that has moved on.
Before running the command, confirm two things — that the document's durable content survives
elsewhere, in the spec issue, an ADR, or the superseding document, and that no living doc still
points at the file. Re-aim the pointers first; a deletion that strands one has moved the defect
rather than fixed it. The script refuses on a surviving reference, but the judgment is yours,
and it prints no document content, which is why it exists at all. It leaves the deletion
staged — commit it with the rest of the ticket's changes.
An ADR that supersedes another archives the superseded one in the same PR, since this is
where both documents are in hand and nowhere later are they. The departing ADR is not edited on
its way out: a merged ADR is never edited, and the reason you pass the script — which names the
superseding ADR — is what records the supersession. Then sweep the vocabulary the superseded
decision introduced out of the living docs, in this same PR, and list the swept terms in the
PR body so a reviewer can tell a thorough sweep from a cursory one. That list lives in the PR
body and nowhere else: it is needed once, while you hold both documents, and an in-tree list of
retired terms would serve a transient purpose forever.
If nothing documented changed, say so; the PR body carries the note either way.
Step 9: Testing Gate
Author any missing tests for new logic first, then run the gate with the affected test paths —
selecting them is your judgment, running and reporting them is mechanical:
bash .claude/skills/lib/gate/gate.sh <affected test paths>Keep its single summary line verbatim; the PR body carries it and the review loop is
handed it as context. The gate must be green before cross-model review starts — a red gate
wastes codex rounds on findings the ladder already found.
Coverage discipline: test observable behavior, never internal wiring. If mock setup outgrows
the test's assertions, record the gap in the coverage-debt ledger rather than fighting it —
but the critical-path floor keeps at least one behavioral test regardless. Never hide
untested code behind ignore comments or lowered gates.
Step 10: Codex Code Review Loop
The reviewing agent is the role key ADDW_CODE_REVIEW_SKILL. It reviews the full
merge-base-to-working-tree diff — everything the PR will deliver, not the last commit — with
the ticket and parent spec as context, which the adapter fetches for itself.
eval "$(bash .claude/skills/lib/config/vars.sh ADDW_CODE_REVIEW_SKILL || echo "(exit $?)")"
bash ".claude/skills/${ADDW_CODE_REVIEW_SKILL:-codex-code-review}/scripts/start.sh" \
<issue-number> "$GATE_SUMMARY"Parse the trailing tag:
APPROVED→ converged.REQUEST_CHANGES→ continue.NEEDS_REWORK→ surface to the human before mass-editing.Address findings — quote each with
file:line, read the actual code, fix the
legitimate ones, push back on the incorrect ones. Critical and Major block approval;
Minor and Suggestion are case-by-case.Re-run the gate, commit the round's fixes, and resume with implementer notes so the
reviewer stops re-flagging what you settled:bash ".claude/skills/${ADDW_CODE_REVIEW_SKILL:-codex-code-review}/scripts/resume.sh" \ --notes "Fixed X. Pushed back on Y because Z." <issue-number> "$GATE_SUMMARY"Cap at 5 rounds unless the human says otherwise; surface whatever remains open.
The final round must run against a fully committed HEAD. Commit everything before the
round you expect to be the last, and record git rev-parse HEAD plushash="$(bash .claude/skills/lib/tracker/tracker.sh body-hash <issue-number>)" at that
moment — before invoking the round, when the ticket the reviewer is handed is the ticket
the hash pins. The verdict SHA pins the diff, the body hash pins the ticket it was judged
against, and the PR body states both. After the verdict, post that recorded hash as the
ticket's approval marker — never recompute it here, which would hash bytes the reviewer may
never have seen — so anyone, the merging human included, can re-check the ticket with one
command (tracker.sh approval-drift <issue-number>) for as long as the PR sits unmerged.
The empty-hash guard is what keeps a failed capture from posting an empty marker, which
would read as never-recorded and silently disable the check:
[ -n "$hash" ] || exit 1 # the hash recorded before the final round
f="$(mktemp)"
printf 'Codex code review: <TAG> after <R> round(s).\nApproved-body: %s\n' "$hash" > "$f"
bash .claude/skills/lib/tracker/tracker.sh comment <issue-number> "$f"Any change made after that verdict either earns another round or is disclosed as
uncovered.
Step 11: Open the PR
Push the branch and open the PR against $ADDW_MAIN_BRANCH:
eval "$(bash .claude/skills/lib/config/vars.sh ADDW_MAIN_BRANCH || echo "(exit $?)")"
git push
gh pr create --base "$ADDW_MAIN_BRANCH" --title "<conventional subject>" --body-file <file>The title must parse as a conventional-commit subject — it becomes the squash subject on
main, and the mechanical changelog projects exactly those subjects. A title the changelog
cannot classify is a defect at the source.
Then stop. You do not merge, and you do not start another ticket — one ticket per
session. Report the PR URL and what the human is being asked to judge.
PR Body Contract
Every ticket PR body carries all seven, in this order. A missing element is a review the
human has to do by archaeology:
- Closure link —
Closes #<issue-number>, so the merge closes the ticket as completed. - Gate summary — the gate's line, verbatim.
- Codex verdict — the tag, the round count, the commit SHA it covers, and the ticket-body
hash the verdict covers. - Disclosures — a skipped pre-filter, a skipped review round, an edited contract test,
an accepted open finding. If there are none, say none. - Doc-impact note — which living docs this changed, or that none needed changing. A
document archived here is named with its archive issue number; a supersession also lists the
vocabulary it swept, since that list exists nowhere else. - What changed — a short prose summary of the change and anything the reviewer should
look at first. - Merge recommendation — squash by default. Recommend rebase-merge only when the
branch's commits are each individually substantive and each conventionally titled, since
the changelog projects every subject that lands on main.
Operating Notes
- One ticket per session. Context from a finished ticket contaminates the next one's
judgment, and the frontier may have moved. - The gate before the loop, always. Cross-model review is expensive; the ladder is not.
- Surface reviews verbatim. Do not paraphrase a finding you are about to argue with.
- If the reviewer repeats a finding you addressed, re-read it carefully — you likely fixed an
adjacent concern rather than the one raised. - If the ticket turns out to be obsolete or wrong, stop and say so. Closing it as completed
with an explanatory comment (its dependents' need is met some other way) or as not planned
(it never will be) is the human's call, and the two mean opposite things to the frontier.