Spec to Code skill for Codex

Every requirement traced to code and a test. Codex stops treating a ticket as a loose suggestion. It splits the spec into numbered must, should and may requirements, logs ambiguities with proposed defaults, writes a test named after each requirement, and finishes with a table that links every requirement to the exact code and test that satisfy it, plus assumptions, deferrals and deviations stated plainly.

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- spec-to-code

Installs to ~/.agents/skills/spec-to-code/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $spec-to-code, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Implements a feature faithfully from a written spec, ticket, PRD or issue by first breaking it into numbered, testable requirements, logging every ambiguity and assumption, mapping each requirement to code and a test in a traceability table, and reporting gaps instead of silently inventing behaviour. Use when asked to implement a Jira or Linear ticket, a GitHub issue, a design doc section, an RFC, an API spec or acceptance criteria, or when a reviewer says the code does not match the spec.

Use it when

  • You have a written ticket, issue, PRD or RFC section to implement
  • Acceptance criteria must be demonstrably met before review
  • A reviewer or QA reports the code drifted from the spec
  • The spec is long enough that requirements could be missed

Use something else when

How to check the result

Every mandatory requirement has a row with a file reference and a named test that passes, and every file in the diff maps to a requirement, an assumption or a stated supporting change.

The mistake it prevents

Coding the spec's example values instead of its rule, or quietly narrowing a requirement that was awkward to implement without reporting it.

~/.agents/skills/spec-to-code/SKILL.md

--- name: spec-to-code description: Implements a feature faithfully from a written spec, ticket, PRD or issue by first breaking it into numbered, testable requirements, logging every… license: MIT ---

Done well means every statement in the spec that demands behaviour maps to code and to a test that would fail without it, every gap was raised as a question or recorded as an explicit assumption, and nothing outside the spec was added without saying so. The deliverable is the code plus a traceability table, not just the code.

Workflow

- [ ] 1. Collect the spec and everything it points to
- [ ] 2. Read AGENTS.md and the code the spec touches
- [ ] 3. Extract numbered requirements (R1..Rn) and non-goals
- [ ] 4. Log ambiguities; ask about blocking ones before coding
- [ ] 5. Write tests per requirement (failing first where practical)
- [ ] 6. Implement in requirement order, smallest vertical slice first
- [ ] 7. Fill the traceability table and run the full check suite
- [ ] 8. Report: done, assumed, deferred, deviated

1. Collect the whole spec

A ticket is rarely the whole spec. Pull in what it references before reading closely:

gh issue view 812 --comments            # GitHub issue plus discussion (needs network)
gh pr view 790 --json body,comments     # linked design PRs

For Jira or Linear tickets without a CLI, ask the user to paste the description, the acceptance criteria and any comments that changed scope. Comments often override the description; the most recent decision from the ticket owner wins. Note mockups, API schemas and linked docs you could not open; they are gaps, not optional extras.

2. Read the ground before reading the spec closely

  • AGENTS.md: test command, layering rules, naming, where new modules go.
  • The existing code paths the spec names. Specs describe intent in product language; find the real entities (rg -n "class Invoice|invoice_status" src/).
  • Existing tests for the area: they show what “done” has meant here before.

A spec that contradicts the code (“users already have a timezone field” when they do not) is a finding to raise now, not something to quietly fix by adding the field.

3. Extract requirements

Rewrite the spec as atomic, testable statements. One behaviour per line, numbered, with the source quoted or located so a reviewer can check your reading.

Spec languageRequirement typeTreatment
“must”, “shall”, “will”, “is required”MandatoryRequirement with a test
“should”, “ideally”, “where possible”PreferredImplement if cheap and clear; otherwise list as deferred
“may”, “can”, “optionally”PermittedDo not build unless asked
Example values, screenshotsIllustrativeUse as test cases, not as the full rule
“e.g.”, “such as”, “etc.”Open listAsk for the full list or record which members you covered
Silence on errors, limits, permissionsGapLog as ambiguity

Also write the non-goals: things the spec explicitly excludes and things a reasonable reader might expect but the spec does not mention. Scope creep starts with an unlisted non-goal.

4. Ambiguity log

Hunt for these gaps deliberately; they are where implementations diverge from intent:

  • Empty, null, zero, maximum and duplicate inputs.
  • Error behaviour: what the user sees, what status code, whether anything is retried.
  • Permissions: who may do this, and what happens for everyone else.
  • Time: time zones, “daily” boundaries, DST, ordering of concurrent updates.
  • Existing data: does the rule apply retroactively? Is a migration or backfill needed?
  • Compatibility: do existing API clients, events or exports change shape?
  • Numbers: rounding mode, currency precision, units, inclusive vs exclusive ranges.

Classify each entry:

ClassRule
BlockingDifferent answers lead to different data models or public contracts. Stop and ask before coding
Non-blockingChoose the most conservative option, mark it ASSUMPTION in the log, isolate it so it is cheap to change
CosmeticFollow existing conventions; no need to mention

Ask blocking questions in one batch, each with your proposed default, so the answer can be “yes to all”:

Before I implement #812 I need three decisions:
1. R4 says "refund the order". Partial refunds: allowed? Proposed: full only for now.
2. R6 "notify the customer": email only, or also in-app? Proposed: email via existing Mailer.
3. Existing 1,240 orders in `pending_review`: apply the new 14-day rule to them? Proposed: no.

5. Tests per requirement

Write at least one test per mandatory requirement, named so the requirement is visible:

def test_r3_refund_rejected_after_30_days(order_factory, clock):
    order = order_factory(paid_at=clock.now() - timedelta(days=31))
    with pytest.raises(RefundWindowClosed):
        refund(order)
  • Turn the spec’s examples into table-driven cases verbatim; they are the cheapest evidence that you read the spec the way its author meant.
  • Add boundary cases the spec implies (day 30 vs day 31) even when it gives no example.
  • For acceptance criteria in Given/When/Then form, keep the same structure in the test body so a product owner can read it.

6. Implement

  • Order by dependency, then by risk: data model and contracts first, UI last.
  • Ship the thinnest vertical slice that satisfies R1 end to end before widening.
  • Keep assumptions in one obvious place (a constant, a config value, a policy function) with a comment pointing to the log entry: # ASSUMPTION A2 (#812): full refunds only.
  • Do not refactor neighbouring code, rename things or “improve” behaviour the spec did not ask for. If you find a real defect nearby, report it separately.
  • If the spec turns out to be wrong (impossible, contradicts itself, breaks an invariant), stop and report with evidence rather than implementing a workaround.

7. Trace and verify

Run the project’s full checks from AGENTS.md (tests, types, lint). Then fill the table by actually locating each item, not from memory:

rg -n "R[0-9]+" tests/ | sort          # requirement-named tests
git diff --stat origin/main...HEAD     # every changed file appears in some row

Every changed file must belong to a requirement, an assumption or a stated supporting change. A changed file with no row is scope creep or a missing requirement.

Decision rules

  • Spec and existing behaviour disagree, and the spec is explicit: follow the spec, call out the behaviour change in the report.
  • Spec is silent and existing behaviour exists: keep existing behaviour.
  • Spec and design mockup disagree: ask; meanwhile follow the text for logic and the mockup for layout.
  • A requirement is untestable as written (“fast”, “intuitive”): propose a measurable version (“p95 < 300 ms on the list endpoint”) and treat it as an assumption.
  • More than about a third of requirements have blocking questions: the spec is not ready. Return the question list instead of a partial implementation.

Gotchas

  • Implementing the example instead of the rule: the spec shows “USD 10.00” and the code hardcodes two decimals, breaking JPY.
  • Gold-plating: extra filters, settings or endpoints nobody asked for still need review, tests and maintenance.
  • Silent narrowing: implementing “admins and owners” as “admins” because owners were awkward, and never mentioning it.
  • Treating ticket comments as noise. A later comment like “drop the CSV export for v1” is part of the spec.
  • Marking a requirement done because code exists, while no test exercises it.

Output template

## Implementation of <ticket id>: <title>

### Requirements traceability
| ID | Requirement (source) | Code | Test | Status |
|---|---|---|---|---|
| R1 | Refund allowed within 30 days of payment (desc, para 2) | `billing/refunds.py:41` | `test_r1_refund_within_window` | Done |
| R2 | Customer is emailed on refund (AC-3) | `billing/notify.py:18` | `test_r2_refund_email_sent` | Done |
| R5 | Should support partial refunds (desc, para 4) | - | - | Deferred: needs decision Q1 |

### Assumptions
- A1: Window counted in UTC calendar days from `paid_at`. Change in `REFUND_WINDOW` policy.

### Open questions
- Q1: Partial refunds in scope for this ticket?

### Deviations from spec
- None. (Or: what differs, why, and who agreed.)

### Out of scope, noticed
- `orders/export.py` rounds totals with float math; unrelated, not changed.

### Verification
- `pytest tests/billing` 48 passed; `mypy src` clean; `ruff check` clean.

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Spec to Code"
  short_description: "Every requirement traced to code and a test"
  default_prompt: "$spec-to-code Implement issue #812 exactly as written and show me how each acceptance criterion is covered"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc