An execution specification language · MIT
Specs that compile into tests. Nothing lost in between.
A .feat file instructs how a feature is built, predicts every observable effect it will produce, and compiles — deterministically — into complete test suites. Anything unpredicted is a failure.
Rejection predicted → zero side effects asserted across every configured service.
- LLMs in the translation layer
- 0
- closed reference spaces
- 4
- exemplar conformance corpus
- 9
- its own CI · green
- 28/28
The problem
Every spec tool has a translation layer. That layer is where the truth leaks.
Gherkin needs step definitions. Contract tools need hand-written provider tests. Markdown specs need a person — or a model — to decide what they mean. Every spec-to-test approach puts a manual translation layer between the contract and the assertions.
That layer is where drift, interpretation, and error live. The spec says one thing; the tests check another; the two diverge silently, and nobody notices until production does.
AI-generated code makes the gap worse, not better. Agents write more of the code, faster — and a model interpreting requirements into tests is the same translation layer, relocated into an LLM: non-deterministic, unverifiable.
Spec-driven workflows tell your agent what to build. Feature proves it got built — to the spec, in its original form.
Show it
One file in. One suite out. Byte for byte.
The prediction is the assertion. No step definitions, no glue code, no model in between. Same spec, same tests — sha256 in the header, byte-compared in CI.
Generated. Committed. Byte-locked to the spec.
Prediction inversion
The test fails on what's missing — and on what you didn't predict.
A spec declares the complete observable footprint of a feature — responses, events, writes, messages — across the services you configure. Predictions are exhaustive: an extra write is a violation, not a surprise.
Side effects can't hide. And queries can't lie — a spec of type query grammatically cannot express a write.
You didn't write that assertion. You didn't have to.
The loop
Four steps. One lock around them.
Author the .feat contract — instructions, predictions, scenarios.
feat generate derives the complete suite. Deterministic — no model in the path.
Agent or human builds against red tests. The spec's construct block is the briefing.
Standard Vitest execution. Coverage, reporters, JUnit out of the box.
Drift is a build failure. feat verify re-derives every committed suite from its spec and byte-compares. Touch the tests without touching the spec — or the reverse — and the merge gate goes red.
The guarantees
Deterministic
Same spec, same tests, byte for byte. The generated header carries an inputs sha256 — no timestamps, no model, nothing to interpret.
Closed
Four closed reference spaces — schemas, service keys, commands, actors. A typo isn't a silent mismatch; it's a parse error with a hint, at compile time.
Enforced
feat verify byte-locks committed suites to their specs in CI. The spec you agreed to is the spec that shipped — provably.
Dogfood
It runs on itself.
Feature's own components are specified in .feat. The nine-exemplar corpus is its conformance suite. Its CI chain is its own product: feat verify && feat run.
Before the toolchain trusted its own compiler, every suite was hand-derived, then machine derivation was flipped on and diffed: zero semantic disagreements across all 27 original cases.
The full loop, on the toolchain's own repo. 28/28 green.
The adversarial benchmark
One planted defect. Every tool's own workflow. One binary question.
We plant one deliberate defect in a small feature, run each tool's full recommended workflow against it, and ask: did the tool's own verification catch it? A lane only counts if its tests passed the clean implementation first. Where competitors succeed — Cucumber on drift, pinned assertions on B5a and B6 — it's published too.
"Not caught" is a statement about that tool's produced verification on this scenario — not about the tool overall. Every cell regenerates from the harness; pending lanes stay visibly pending.
- 01 Same defect for everyone — one planted bug, every tool’s full workflow.
- 02 Steelman setups — each tool configured the way its docs recommend.
- 03 Binary outcomes — caught or not caught. No scoring judgment calls.
- 04 Date-stamped — every result carries its version and run date.
- 05 Misses published too — scenarios where competitors succeed ship as well.
Ecosystem
Adapters, not lock-in.
Your infrastructure, your keys
Service names in predictions are yours — eventStore, database, whatever your architecture has. First-party adapters ship for handler, http, and fs.
Write one in an afternoon
An adapter is a plain package exporting one function. No plugin registry, no framework ceremony.
Vitest-native output
Generated suites are standard Vitest — coverage, IDE debugging, reporters, JUnit all work unchanged. If you loved Given/When/Then and hated maintaining step definitions: the scenario shape is familiar. The step-definition layer is gone.
Clone it. Break it. Every claim on this page is reproducible.
The samples above run verbatim against the released toolchain. Start with the language guide, or go straight to feat init.
init, generate, run — first green suite in minutes.
The grammar reference and the nine-exemplar corpus.
Run feat parse in the browser — break the grammar, watch the hints.