agentleFS
dayvisonassisdayvisonassis/sdd-skills/skills/implement-feature/SKILL.md

implement-feature

Skill3 starsChanged 32 days agoMITView on GitHub

Implements a feature autonomously based on its spec, plan, AND contract.md, committing one commit per phase, satisfying the contract's quality gates and observable criteria, writing progress.json, and reporting results against the feature's acceptance criteria. Delegates test writing to the matching test-writer skill (unit/integration/e2e), chosen from the suites the project's GATES.md declares, and falls back to writing tests itself when no suite covers the file.

  • Reads credentials

26 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use prepare-release, create-skill and 3 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • ShopifySkill

    prepare-release

    Prepare the changeset-release/main branch for release by syncing version.ts files and running pnpm install

    Also in 3 projects that use this

  • ElasticSkill

    create-skill

    Interactively create a new Claude Code skill and add it to the elastic-docs-skills catalog. Use when the user wants to generate a new skill, scaffold a slash command, or build automation for docs tasks.

    Also in 3 projects that use this

  • VercelSkill

    find-skills

    Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.

    Also in 3 projects that use this

  • GoogleSkill

    code-review

    Adversarial systems, concurrency, memory-model, and architecture code review protocol. Use this skill whenever asked to review code, PRs, diffs, or branches in Filament.

    Also in 3 projects that use this

  • SentrySkill

    skill-creator

    Create new agent skills following the Agent Skills specification. Use when asked to "create a skill", "add a new skill", "write a skill", "make a skill", "build a skill", or scaffold a new skill with SKILL.md. Guides through requirements, writing, registration, and verification.

    Also in 3 projects that use this

The file

Show its rules and text

We split this skill into the rules it gives an agent

30 rules. 0 are common, 18 are distinctive, and 12 are very specific to this project.

  • 0

    Common

    Most of the 25 edited versions we read keep these.

  • 18

    Distinctive

    This author's own choices. Worth a look.

  • 12

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    The PRD: If explicitly passed, use it.

    line 28
  2. Very specific:

    If contract.md is missing, the feature was spec'd without a contract.

    line 30
  3. Very specific:

    No files are written besides code changes, commit objects, and progress.json.

    line 38
  4. Distinctive:

    No PRD found → abort: "No PRD found.

    line 56
  5. Distinctive:

    If the PRD has no acceptance-criteria content for this feature, proceed with an empty AC checklist and note it under soft-fails.

    line 69
  6. Distinctive:

    Do NOT explore the codebase eagerly.

    line 71
  7. Distinctive:

    All dependencies present → proceed to Step 5.

    line 97
  8. Distinctive:

    If the PRD has no dependency content, skip this step.

    line 99
  9. Distinctive:

    Read spec.md sections relevant to the phase.

    line 111
  10. Distinctive:

    Every file listed for this phase in spec.md's Component Overview exists and contains the described content.

    line 115
  11. Distinctive:

    Every contract (API, schema, function signature) described for this phase matches what was written.

    line 116
  12. Very specific:

    Read the gates before writing the code they cover: Before a phase writes code in the scope of a gate the contract declares, read that …

    line 122
  13. Very specific:

    e2e is dispatched per surface, not per file: When the project has an e2e suite (GATES.md lists an e2e gate proven green) and the contract's …

    line 191
  14. Very specific:

    Never bend production code to a wrong test: open a dispute — replace the test's title in its coverage-table row with disputed — <test …

    line 206
  15. Distinctive:

    Generic fallback: when no declared suite covers the file and the repository reveals none — or a writer answered that the project's test …

    line 219
  16. Distinctive:

    If an override disabled commits, skip this sub-step and keep working-tree changes.

    line 252
  17. Distinctive:

    After the last phase commits (or when the run aborted), run an independent verification pass over the whole feature before writing the …

    line 260
  18. Very specific:

    If failures appear that weren't flagged per-phase → they count as regressions.

    line 268
  19. Distinctive:

    If the feature produces runtime surfaces that per-phase validation couldn't exercise (UI page, HTTP endpoint, migration, CLI command), do …

    line 288
  20. Very specific:

    If the environment cannot be brought up in this run, log each skipped smoke check under Soft-fails.

    line 303
  21. Very specific:

    Never report success when any of the checks above has an unresolved failure, even if every phase individually committed clean.

    line 314
  22. Very specific:

    Update (creating if absent) progress.json at the root of docs/, setting the target feature's entry:

    line 318
  23. Distinctive:

    If aborted, the report still lists whatever committed phases achieved and clearly marks which phase failed and why.

    line 391
  24. Distinctive:

    Commit 1 per phase (default), staging only the files that phase touched.

    line 400
  25. Distinctive:

    Run validation after each phase, including the contract's Quality Gates.

    line 403
  26. Distinctive:

    Before claiming a phase is "done": confirm every file listed for that phase exists with the described content AND validation has passed.

    line 404
  27. Very specific:

    Write progress.json (Step 7) on completion.

    line 409
  28. Very specific:

    Write CLEAN / FAIL / PENDING / ABORTED into progress.json — those states belong to the evaluator.

    line 416
  29. Distinctive:

    Create or switch branches.

    line 417
  30. Distinctive:

    Use git add -A or git add ..

    line 420

“Common” is measured: kept by at least 6 in 10 of the 25 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Implement Feature

Autonomously implement a feature from its existing spec.md + plan.md + contract.md. It implements phase-by-phase with per-phase commits, retry policy, and a final verification/AC report, and is contract-aware — it must satisfy the contract's environment, quality gates, and observable criteria, and it records the feature's state in progress.json so the evaluator can pick it up.

Base docs (in this package): https://github.com/dayvisonassis/sdd-skills/blob/main/docs/Contrato_de_Feature.md, https://github.com/dayvisonassis/sdd-skills/blob/main/docs/Como_criar_gates.md, https://github.com/dayvisonassis/sdd-skills/blob/main/docs/ARQUITETURA_DAS_SKILLS.md (flow + progress.json schema). Start with https://github.com/dayvisonassis/sdd-skills/blob/main/docs/GUIA_DO_WORKFLOW.md for how the skills fit together.

INPUT

Free-form. The skill figures out what was passed. Any combination works:

  • A feature identifier: F09, Video Upload, or similar.
  • A feature folder: docs/F09-in-video-transcription-search/, ./F09/, etc.
  • A file inside the feature folder: docs/F09-in-video-transcription-search/spec.md.
  • A PRD path: @docs/PRD.md, docs/PRD.md, @PRD.md.
  • Extra natural-language instructions appended anywhere (see Overrides).

The skill needs to locate three feature files and one reference source:

  1. spec.md, plan.md, and contract.md for the target feature. If the input points to a folder, look inside. If it points to a file, look in its parent folder. If it points to an ID or name, search under docs/ for a folder matching <ID>-* or whose name kebab-cases to the given name.
  2. The PRD. If explicitly passed, use it. Otherwise, auto-discover: docs/PRD.md → PRD.md → any top-level *.md whose content reads like a product spec. If none found, abort. If multiple are plausible, abort and list them.

If contract.md is missing, the feature was spec'd without a contract. Abort: "contract.md missing in <folder> — regenerate the spec with spec-writer." (Do not silently proceed without the contract.)

OUTPUT

  • Commits: one per phase of plan.md, on the current branch (no branch creation, no branch switching).
  • progress.json at the root of docs/: the target feature's entry is set to state: PENDING_EVALUATION, attempt: 0 on successful completion (ready for the evaluator). See the schema in the flow doc.
  • Chat report at the end: the feature's acceptance-criteria checklist marked ✓ / ✗ / — against actual test results, plus a Contract gates section, plus sections for Deviations, Soft-fails, Pre-existing failures, Overrides applied, Overrides ignored, and Phase status.

No files are written besides code changes, commit objects, and progress.json. The chat report is ephemeral.


EXECUTION STEPS

Step 1: Resolve Input

Parse the entire input as free-form. Extract:

  • Feature reference: the first token that resolves to a folder containing spec.md + plan.md + contract.md. Matches: ID patterns like F\d+, folder paths, file paths (parent folder = target), feature names (kebab-case + fuzzy match to folder names under docs/).
  • PRD reference: an explicit *.md path prefixed with @ or written literally; if it looks like a PRD, accept it. Otherwise auto-discover.
  • Extra instructions: any remaining text that isn't a path/ID/name — treat as natural-language overrides (Step 3).

If resolution fails:

  • No spec.md or plan.md in the resolved folder → abort: "spec.md/plan.md missing in <folder>."
  • No contract.md in the resolved folder → abort: "contract.md missing in <folder> — regenerate with spec-writer."
  • No PRD found → abort: "No PRD found. Pass the path explicitly."
  • Multiple plausible PRDs → abort and list candidates.
  • Ambiguous feature reference (multiple folders match) → abort and list candidates.

Step 2: Load Context

Read in full:

  • spec.md of the target feature — Component Overview, Data Model, API Contracts, Business Rules, UX Flows, Error Handling, Testing Strategy, Assumptions/Decisions.
  • plan.md — phases and steps in order.
  • contract.md — Environment Contract, Quality Gates (with their ids), Coverage Manifest, Surfaces & Behaviors, Observable Criteria (with their ids). These define the technical floor and the observable acceptance the evaluator will later check.
  • The PRD's acceptance-criteria content for this feature — locate it semantically, not by section number. Typical headings: "Acceptance Criteria", "Critérios de Aceitação", "AC". Also locate any cross-feature/integration checklist that references this feature.

If the PRD has no acceptance-criteria content for this feature, proceed with an empty AC checklist and note it under soft-fails.

Do NOT explore the codebase eagerly. Open files lazily as each phase requires them.

Step 3: Apply Overrides

Interpret extra instructions as natural-language overrides on the defaults:

DefaultExample overrides
Hard-fail retry limit = 3"no retry limit", "max 5 tries"
Fully autonomous"pause between phases" — skill waits in chat for a reply containing ok, continue, segue, yes, or similar
1 commit per phase"single commit at the end", "no commits, just implement"
Run lint + typecheck + tests + contract gates"skip tests", "skip lint", "skip typecheck"
Implement all phases"only phases 1 and 2", "skip phase 3" — phase positions are ordinal; labels like A/B/C map to 1/2/3
Abort tests on external dep missing"stub missing services", "assume empty response for missing APIs" — substitutes stubs ONLY in test code, never in production modules

For each recognized override, record before/after for the final report's "Overrides applied" section.

Immutable core (cannot be overridden): the final AC checklist, its traceability to the PRD, and writing progress.json on completion. Instructions that would disable the report or skip the contract gates entirely are logged under "Overrides ignored" with the reason. (Individual gate skips like "skip lint" are allowed and logged as soft-fails.)

Ambiguous or contradictory instructions → default wins; logged under "Overrides ignored" with "ambiguous, kept default".

Step 4: Pre-flight Dependency Check

Locate the dependency content in the PRD semantically (typical headings: "Dependency Graph", "Dependencies"). For each listed dependency of the target feature, verify it appears implemented in the codebase (look for the characteristic files described in that dependency's own spec.md Component Overview, or obvious source-level markers).

  • Any dependency missing → abort before any implementation. Report: "F<target> depends on F<N>, which is not implemented yet."
  • All dependencies present → proceed to Step 5.

If the PRD has no dependency content, skip this step.

Step 5: Execute Phases

For each phase of plan.md, in order:

5.1 — Skip if already done

Inspect the last ~20 commits on the current branch. If any commit message indicates this exact phase already ran (same feature ID + phase name or ordinal), skip the phase with status — already committed and move on. Detection is best-effort: match on feature ID plus normalized phase name or phase index.

5.2 — Implement

Read spec.md sections relevant to the phase. Edit/create files to fulfill the phase's steps.

What counts as "done" for a phase — all of the following, not just "I wrote the code":

  • Every file listed for this phase in spec.md's Component Overview exists and contains the described content.
  • Every contract (API, schema, function signature) described for this phase matches what was written.
  • Validation in 5.3 passes (hard fails resolved).
  • If the phase produces runtime behavior that isn't covered by unit tests (UI pages, server routes, migrations, CLI commands), actually exercise it before claiming done: run the dev server / build / migration / command against a local environment and confirm it behaves. If the environment can't be brought up in this run, log the runtime-check under Soft-fails.

Writing code without running it is not "done". Declaring completion without meeting the checklist above is a violation of the skill's contract.

Read the gates before writing the code they cover. Before a phase writes code in the scope of a gate the contract declares, read that gate's section in the project's gate documentation (GATES.md or its equivalent) — what it rejects and the accepted pattern — and write the code in that pattern from the start. Learning a rule from a failed run in 5.3 costs a retry; reading it costs nothing.

A gate exception (definition in ../evaluator/references/evaluation-report-schema.md, "Gate exceptions") is a request to a human, not a way to finish a phase. Add one only when the accepted pattern cannot express the code and the case falls in a category the gate's section accepts. Give a reason a reviewer can check, record the feature where the section says, and log it under Deviations. An allowlist entry stays pending in the evaluator until a human approves it; no other kind of gate exception is yours to make. Never add one to end a retry, and never make a gate pass by hiding the pattern it rejects from its detection (a renamed handle, a wrapping helper, code moved out of its scanned path).

UI phases — resolve the design system FIRST. When a phase creates or modifies user interface (templates, markup, styles, theme files), resolve which design rules bind it BEFORE writing the UI: use the design-system skill in apply mode, or follow its resolution order yourself (../design-system/SKILL.md, Step 1) — the project's tracked design-system doc when GATES.md or a conventional path names one, the bundled baseline otherwise. State the source you resolved, then follow it for both:

  • the machine-checkable rules — the ones the project's design-system gate enforces, when the contract declares one. Getting these right up-front avoids gate retries in 5.3; and
  • the judgement rules no gate can check (hierarchy, density, spacing, the empty / loading / failure states) — these are only honored if you read the doc.

A rule that comes only from the bundled baseline is guidance: follow it, and never report it as a requirement of the project. When the doc is silent on something the UI needs, record the gap under Deviations.

Then, because UI is a runtime surface, exercise it per the "done" checklist above and, when a dev environment is available, do a visual verification in a real browser (playwright-cli / browser tools) per ../design-system/references/measuring.md — every theme the project ships, with numeric rules read as computed values rather than inferred from a class being present. If the environment can't be brought up, log the visual check under Soft-fails. (A declared design-system gate still runs in 5.3/6.1 either way.)

Writing the tests — delegate to a test-writer when applicable. When a phase needs tests, delegate to the matching test-writer skill (dispatched in autonomous mode) instead of writing them inline. The suite is chosen by what the project declares, never by a folder's name ("Suite selection" in ../evaluator/references/evaluation-report-schema.md): take the suite of GATES.md's test profile whose sources contain the file under test; its kind picks the writer:

  • a unit suite → unit-test-writer
  • an integration suite → integration-test-writer
  • the e2e suite → e2e-test-writer, dispatched per surface (below)

Pass the target_file (or the endpoint), the feature ID and the phase context. The test-writer reads the project's test profile and its own rules, and returns a signal; on a plain done, keep implementing the phase. A writer that answers "not resolved — environment: <which>" could not work in this project: when the cause is an undeclared profile or no suite covering the file, use the generic fallback below for that file; when the cause is an environment that could not be reached, soft-fail the affected tests by name.

A unit or integration writer's done may carry lines for what only you can act on — the code is yours, and a writer never changes it. Act on each before the phase's commit (5.4), and put the writer's tests and its checklist in that commit: the checklist is where the evaluator reads these records.

  • "spec mismatch: <behavior> — spec: <x>; code: <y>" → the writer wrote that test as the code behaves. Do not take it on faith: re-read the spec and contract lines against the code.
    • The code diverges from a line of the contract, or from the spec without your having meant it → a hard fail of the phase. Fix the code, then dispatch the same writer again for that file, naming the behavior in its focus_areas: it rewrites the test to the spec. Count it against the retry budget like any other hard fail, and never edit the writer's test yourself. A behavior the contract's criteria state is never yours to adapt.
    • The divergence is an adaptation you made on purpose, of something the contract does not state, or the writer read the spec wrongly → leave the code and the test, and record it under Deviations. The note stays in the writer's checklist, where the evaluator reads it.
  • "no seam: <dependency> — <behaviors>" → those behaviors have no unit test: the test cannot replace that dependency without a change to the code. Look at the code first: when the dependency already has a seam, the writer missed it — dispatch it again saying which. Open the seam when that is a local change: the dependency received as an argument or a constructor parameter, inside the signatures the spec describes and the patterns the project's gates accept. A parameter with a default, which leaves every existing call as it is, is inside the signature; one that makes a caller change is not. Log it under Deviations when the signature no longer reads as the spec writes it. Then dispatch the writer again for those behaviors, saying which seam you opened — once per dependency, and at no cost to the retry budget: nothing failed. When it is not a local change, or the line comes back, leave the code and list the behaviors under Soft-fails, with the dependency.

e2e is dispatched per surface, not per file. When the project has an e2e suite (GATES.md lists an e2e gate proven green) and the contract's test-suite hint maps a surface to e2e — whatever the stack: the e2e writer is generic and reads the harness from GATES.md — dispatch e2e-test-writer with the feature ID and the surface ids as target — in the phase that makes that flow work end to end (UI and API both in place), once its code is written and before that phase's commit (5.4), so the tests land in the same commit; never earlier: an e2e test written against a half-built flow can only be red or wrong. It needs the stack running (Environment Contract); bring it up rather than skipping the dispatch. Act on the writer's signal:

  • done → keep implementing.
  • "not resolved — product diverges from <ref>" → do not take it on faith: re-read the contract line it quotes against what the code does.
    • The code diverges from that line → a hard fail of the phase. Fix the code, re-run that test, and count it against the retry budget like any other hard fail. Never edit the writer's test to make it pass.
    • The code matches the line and the test does not → the writer read the contract wrongly. Never bend production code to a wrong test: open a dispute — replace the test's title in its coverage-table row with disputed — <test title> (<path>) — <contract line>, per the Disputes lifecycle of ../e2e-test-writer/references/e2e-rules.md — record it under Deviations, and leave the arbitration to the evaluator. The test is committed with the phase like the rest of its file; the entry, not the commit state, stops it being routed. A dispute does not block success, and the e2e gate's failure on that test is excluded from the retries of 5.3 and 6.1.
  • "not resolved — environment: <which>" → first read the dev server's log: a build broken by this run's own code is a hard fail of the phase, not an environment problem. Otherwise soft-fail the e2e gate by id and list the surface's rows under Missing from spec, so the run cannot end as success. Tests it returns as unproven stay marked unproven in its coverage table and count as missing.

Generic fallback: when no declared suite covers the file and the repository reveals none — or a writer answered that the project's test profile is not declared — write the tests yourself, following the conventions of the tests that already exist. Record in Deviations that the generic fallback was used (which files, why no test-writer applied). The fallback never covers e2e: when the project has an e2e suite, e2e tests always go to e2e-test-writer, as above.

Adapt when reality diverges from the spec (column named pinned in DB vs isPinned in spec, different component file name, slightly different path, structurally compatible types). Specs are never 100% faithful to reality — adaptation is expected. Record every adaptation in a Deviations list. Do NOT abort on minor divergences.

Abort the entire run only on:

  • Dependency feature missing (usually caught in Step 4; if discovered mid-phase, abort here).
  • Hard fail past the retry limit in Step 5.3 below.

Missing external dependencies needed only by tests (e.g., OPENAI_API_KEY unavailable) do NOT abort the run — they soft-fail the affected test. The implementation code that calls the service is still written.

5.3 — Validate

Discover validation commands at runtime: inspect package.json scripts, or for non-Node stacks inspect the equivalent (Makefile, pyproject.toml, Cargo.toml, vitest.config.*, jest.config.*). Run the available ones. Additionally, prefer the gate commands declared in contract.md's Quality Gates when they exist — those are the canonical commands the evaluator will run.

  • Hard fail = non-zero exit from lint, typecheck, unit tests, or a contract quality gate, where the failure is attributable to code this run changed. Retry up to the configured limit (default 3). Each retry reads the error, adjusts the code, re-runs. After the limit, abort the whole run and go to Step 6.
  • Soft fail = validation cannot execute in this environment (e2e requiring browser/server not present; integration test requiring an external credential not set; suite explicitly marked non-runnable; command not found). Skip, log under Soft-fails, proceed.
    • "Not present" means it could not be brought up, not that it was not tried. When the project has an e2e suite (GATES.md lists an e2e gate proven green) and the contract declares it, bring the stack up per the Environment Contract before soft-failing it. If it still cannot run, log the gate by id as unverified — the evaluator will enforce it — and note that the e2e tests it needs could not be written either, so the run cannot end as success (see 6.5). Once the stack is up, a failing e2e test attributable to this run's code is a hard fail like any other gate.
    • Before re-running a browser gate (e2e or visual) after an edit, confirm in the dev server's log that the rebuild finished successfully — a failed build keeps serving the previous bundle with HTTP 200, and the re-run would measure old code. A 429 or every case on the sign-in screen is the auth rate limit: stop re-running, soft-fail the gate by id, and never count it as a retry of your code. Each run costs the harness its logins.
  • Pre-existing failure = validation fails but the failure is not attributable to code this run changed. Log under Pre-existing failures, do NOT count against the retry budget, proceed.

Warnings without non-zero exit are never failures.

5.4 — Commit

If validation passed (all hard fails resolved; only soft fails, pre-existing failures and failures of a test with a disputed entry remain), stage only the files this phase touched and commit with a message summarizing the phase. Match the project's commit style by inspecting the last ~10 commit messages. Fallback: feat(F<ID>): <phase name>.

Stage specific files only (no git add -A / git add .). Commit on the current branch. Do not skip hooks.

If an override disabled commits, skip this sub-step and keep working-tree changes.

5.5 — Proceed

Move to the next phase. A run-level abort (hard fail past retry limit, dependency missing mid-phase) stops execution and goes to Step 6 with whatever phases already committed.

Step 6: Final Verification

After the last phase commits (or when the run aborted), run an independent verification pass over the whole feature before writing the report. This step exists because per-phase checks can miss regressions, and because AI commonly claims "done" when it isn't.

Perform all of the following — no step is optional:

6.1 — Full-suite validation (including contract gates)

Run the full validation suite on the entire repo (not just touched files): lint, typecheck, and the complete test suite as defined by the project, plus every Quality Gate declared in contract.md (typecheck, lint, build, tests, arch, etc.). Do NOT filter to files this run changed.

  • If failures appear that weren't flagged per-phase → they count as regressions. Attempt to fix up to the retry limit. If still failing, do NOT declare success — status becomes completed with regressions and the failures are listed under Regressions.
  • A failing contract gate that this run's code caused is a regression; record which gate id failed.
  • Pre-existing failures already logged in Step 5.3 stay categorized as pre-existing.

6.2 — Component Overview walk-through

Read spec.md's Component Overview and, for every file listed, verify: the file exists, its described role is visible in the content, and its contracts (exports, routes, schemas) match the spec within the adaptation rules of Step 5.2. Any missing file/export/contract → add to Missing from spec. Do NOT claim success if this list is non-empty.

6.3 — AC + Observable Criteria re-check

For each acceptance criterion loaded in Step 2, locate the test(s) mapped to it via spec.md's Testing Strategy. Run those tests fresh right now. Mark the AC ✓ only if the test passes. If the test no longer passes → mark ✗, add to Regressions — unless the failing test has a disputed entry: then mark the AC disputed, list it under Deviations, and leave it to the evaluator's arbitration.

(v2) Additionally, for each Observable Criterion in contract.md that is unit/integration-testable, confirm a test or check covers it. Observable criteria that require runtime exercise (UI rendering, redirects) are checked in 6.4; the rest should have coverage. ACs/criteria without mapped tests remain — (no test) — they will be the evaluator's job. So do the two cases a unit or integration writer's checklist records: a test named in a spec mismatch note asserts what the code does, not what the spec says, and covers nothing; a behavior whose outcome is not unit-testable — no seam has no test.

When the Test-suite hint maps a surface to unit or integration, a criterion of that surface — or a value it names — that no test of that suite asserts is missing coverage (../evaluator/references/evaluation-report-schema.md, "Contract coverage"), and a gap in this run's own work: the evaluator fails it. Dispatch the matching writer for it now, naming the criterion and the uncovered values in focus_areas, and commit the tests and the checklist it writes in a dedicated test(F<ID>) commit, since the phase commits are already made. A gap the writer could not close goes under Missing from spec.

When the project has an e2e suite, a UI criterion whose behavior is a user flow counts as covered only by an e2e test tagged with its id — run them fresh here in one run for the whole feature (the e2e config from GATES.md, --grep "@<feature-id>(?![\w-])"), never one run per criterion, and map the results by tag. A flow criterion with no tagged test is —, not ✓, even if 6.4 exercised it by hand. Every row the Test-suite hint maps to e2e must appear in the writer's coverage table (docs/<feature-id>-<kebab>/e2e-test.md) with an outcome of the closed list in ../e2e-test-writer/references/e2e-rules.md ("Coverage outcomes") — existing, proven tagged tests, or a not e2e-testable reason worded as that list words it. A row with none of the accepted outcomes — including one marked unproven or carrying any other reason — is a gap in this run's own work: dispatch e2e-test-writer for it now — and commit what it writes in a dedicated test(F<ID>) commit, since the phase commits are already made — or list it under Missing from spec, including when the stack could not be brought up to write it. A row the writer marks out of e2e scope is a contract mapping mistake, and a disputed entry awaits arbitration (a row holding only such entries is not a gap): list both under Deviations for the evaluator.

6.4 — Environment smoke check (when applicable)

If the feature produces runtime surfaces that per-phase validation couldn't exercise (UI page, HTTP endpoint, migration, CLI command), do one final exercise of each against a local environment. Use the Environment Contract in contract.md to know what must be up.

Loading a page is not exercising it. For every interactive control the feature adds or touches, drive it and observe the result. Enumerate them and tick them off one by one — a screen that "opened and looked right" is not a smoke check:

  • Every filter/search field, individually, plus applying and clearing them.
  • Every select, toggle, checkbox and date range that changes what is fetched or displayed.
  • Every action button, including the ones meant to be disabled — confirm the reason is actually reachable (tooltip/message), not merely that the button is grey.
  • Pagination, whenever the list can exceed one page.

An empty result never validates a filter. Filtering by a value that matches nothing returns zero rows whether the filter works or is silently ignored — the two outcomes are indistinguishable, so the check proves nothing. Exercise each filter with a value that exists in the data and confirm the set narrows to exactly it; only then, optionally, try a non-matching value. If the data has no qualifying value, create one, or record that filter as not verified under Soft-fails — never as verified.

Prefer evidence over impression. Where the environment allows, confirm in the request log / network trace that the interaction issued the expected call with the expected parameters, and that one user action produced one request. Duplicate requests from a single action are a real defect this step is well placed to catch.

Any control you did not drive goes under Soft-fails by name. Never report a smoke check as passed for a control you only saw rendered.

If the environment cannot be brought up in this run, log each skipped smoke check under Soft-fails.

6.5 — Status decision

The run's final status is determined by this step, not by whether phases committed:

  • success — full suite + contract gates green (a test recorded as disputed excepted — its failure is the evaluator's to arbitrate), every Component Overview item present, every AC's test passes in 6.3 (or is disputed), (when the project has an e2e suite) every row the test-suite hint maps to e2e carries an accepted outcome in the writer's coverage table (disputed entries included), (when the hint maps a surface to unit or integration) its contract coverage complete, every smoke check passed or soft-failed.
  • completed with regressions — phases committed but 6.1 or 6.3 uncovered failures (including contract-gate failures) that the skill couldn't resolve.
  • incomplete — Missing from spec (6.2) is non-empty.
  • aborted at phase <N> — run stopped during Step 5 before reaching here.

Never report success when any of the checks above has an unresolved failure, even if every phase individually committed clean.

Step 7: Write progress.json

Update (creating if absent) progress.json at the root of docs/, setting the target feature's entry:

{
  "config": { "maxFixAttempts": 3 },
  "features": {
    "F<ID>": {
      "state": "<see below>",
      "attempt": 0,
      "lastEvaluationReport": null,
      "updatedAt": "<ISO timestamp>"
    }
  }
}
  • On success → state: "PENDING_EVALUATION" (ready for the evaluator).
  • On completed with regressions / incomplete / aborted → state: "PENDING_EVALUATION" as well only if the user should still run the evaluator; otherwise leave a clear note in the report. Default: write PENDING_EVALUATION only on success, and for non-success leave state unset/untouched so the user fixes the build first. (The evaluator owns CLEAN/FAIL/PENDING/ABORTED — never write those here.)
  • Preserve any existing config.maxFixAttempts; do not overwrite other features' entries. Merge, don't replace the file.
  • When you set PENDING_EVALUATION, commit the file by itself — chore(F<ID>): ready for evaluation, or the project's style — staged by name, as 5.4 commits; when you left the state untouched there is nothing to commit: the evaluator then finds the state wherever the branch goes, and the run leaves nothing of its own uncommitted. Skip it when an override disabled commits.

Step 8: Final Report

Output the report to chat. Status comes from Step 6.5, never from "I think I finished":

Feature F<ID> — <name>

Status: success | completed with regressions | incomplete | aborted at phase <N>
Phases: <N> committed / <M> total
Branch: <current-branch>
progress.json: state set to <PENDING_EVALUATION | untouched>

Acceptance Criteria (re-checked in Step 6.3):
✓ <AC text> (covered by <test name>)
✗ <AC text> (test failed after <K> retries: <error summary>)
— <AC text> (no test covers this AC — evaluator will check)

Contract gates (from Step 6.1):
✓ <gate-id> passed (<command>)
✗ <gate-id> failed: <error summary>

Observable criteria coverage (from Step 6.3):
✓ <crit-id> covered by <test>
— <crit-id> runtime-only (evaluator will check)

Cross-feature integration (if any):
✓ <criterion> (covered by <test name>)

Missing from spec (from Step 6.2):
- <file/export/contract that the spec required and is missing>

Regressions (from Step 6.1 or 6.3):
- <test or gate-id> started failing during this run: <error>

Deviations:
- <what was adapted and why>

Soft-fails:
- <what was skipped and why, including runtime smoke checks not exercised>

Pre-existing failures:
- <test name>: failed on entry to this run; left as-is

Overrides applied:
- Retry limit: 3 → unlimited

Overrides ignored:
- "<text>" (reason)

Abort reason (if status is aborted): <error>

If aborted, the report still lists whatever committed phases achieved and clearly marks which phase failed and why.


RULES

Always:

  • Require spec.md + plan.md + contract.md in the target folder; abort without any of them.
  • Locate AC and dependency content in the PRD semantically, never by fixed section number.
  • Commit 1 per phase (default), staging only the files that phase touched.
  • Match the project's recent commit-message style.
  • Adapt to minor spec/code divergences; log every adaptation under Deviations.
  • Run validation after each phase, including the contract's Quality Gates; differentiate hard-fail (retry ≤ limit) from soft-fail (skip + log) from pre-existing failure (log, don't retry).
  • Before claiming a phase is "done": confirm every file listed for that phase exists with the described content AND validation has passed. Writing code without running it is never "done".
  • Read the gate documentation section of every declared gate before writing code in its scope. Add an allowlist entry, the only gate exception you may make, only when the accepted pattern cannot express the code, in a category that section accepts, with the feature recorded where it says, and log it under Deviations for human approval.
  • Delegate test writing to the matching test-writer (by the suite GATES.md declares, autonomous mode; e2e by contract surface) when a suite covers the file; otherwise write the tests yourself (generic fallback) and log it under Deviations. Act on the spec mismatch and no seam lines a writer's done carries before committing the phase.
  • For phases that produce runtime surfaces, actually exercise them against a local environment (per the contract's Environment Contract) before claiming done, or soft-fail the runtime check.
  • Execute Step 6 (Final Verification) in full, including all contract Quality Gates, before reporting.
  • Write progress.json (Step 7) on completion; set PENDING_EVALUATION on success.
  • Derive the final status exclusively from Step 6.5.

Never:

  • Claim the run is success when Step 6 found regressions (including failing contract gates), missing-from-spec items, or unresolved failures.
  • Skip the AC report or its traceability (immutable core).
  • Skip Step 6 (Final Verification) or the contract Quality Gates wholesale.
  • Write CLEAN / FAIL / PENDING / ABORTED into progress.json — those states belong to the evaluator. This skill only writes PENDING_EVALUATION.
  • Create or switch branches.
  • Abort on name/path/type cosmetic divergences.
  • Abort on external dependency missing for a test — soft-fail the test, keep implementing.
  • Use git add -A or git add ..
  • Skip git hooks.
  • Count pre-existing test failures against the retry budget.
  • Re-run phases already committed on the branch (detected by commit-message match).
  • Insert service stubs in production modules — stubs are allowed only in test files.
  • Explore the codebase upfront with a broad sweep — read files lazily as phases require.
  • Modify gate infrastructure to make a gate pass — that is built by gate-builder, not here.

Overrides

Free-form instructions at the end of the invocation override defaults. Examples:

  • Retry limit: no retry limit, max 5 tries.
  • Autonomy: pause between phases — waits for user reply (ok, continue, segue, yes, etc.) after each phase.
  • Commit strategy: no commits, just implement; single commit at the end.
  • Validation: skip tests, skip lint, skip typecheck — individual gate skips are logged as soft-fails.
  • Phase selection: only phases 1 and 2, skip phase 3 — phase positions are ordinal; labels A/B/C map to 1/2/3.
  • External services: stub OpenAI, assume empty response for missing APIs — stubs apply ONLY in test code; production modules keep the real call.

Unrecognized or contradictory overrides: default wins; logged under Overrides ignored.

Immutable core: the AC checklist, its traceability to the PRD, and writing progress.json on success cannot be overridden. Skipping ALL contract gates is ignored; skipping an individual gate is allowed and soft-failed.


Edge Cases

No PRD found: abort before starting.

No spec.md or plan.md: abort before starting.

No contract.md: abort and direct the user to spec-writer to generate the contract.

Dependency feature not implemented: abort at Step 4 with a clear message.

Ambiguous feature reference: list candidates, abort asking which.

Working tree has unrelated changes at start: proceed anyway — commits stage only the specific files each phase touched.

Phase name contains special characters: fall back to feat(F<ID>): implement phase <N>.

Re-invocation after a partial run: Step 5.1 detects already-committed phases by commit-message match and skips them. Uncommitted working-tree changes from a prior interrupted run stay as-is.

Contract gate command not discoverable / not runnable in this environment: soft-fail that gate, log it, and proceed — but note in the report that the evaluator will still enforce it.

Hard fail past the retry limit on a step/gate that isn't part of any AC: abort anyway — the skill cannot judge which failures are "acceptable". User can override with skip tests or similar.

External tool emits warnings, not errors: warnings are not failures. Only non-zero exit codes count.

Override contradicts the core contract (e.g., drop the contract gates): ignore it, log under Overrides ignored, proceed enforcing the gates.

progress.json already exists: merge the target feature's entry; never overwrite other features or config.

PRD has no AC content for this feature: proceed with empty AC checklist and note under soft-fails. The contract's Observable Criteria still apply.

PRD has no dependency content: skip Step 4 and proceed.

Commit-message style is inconsistent in recent history: fall back to feat(F<ID>): <phase name>.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.