GitHub - blentz/spec-forge · GitHub
/" data-turbo-transient="true" />
Skip to content
Type / to search
Sign in<br>Sign upAppearance settings
You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.
Dismiss alert
{{ message }}
blentz
spec-forge
Public
Notifications<br>You must be signed in to change notification settings
Fork
Star
main
BranchesTags
Go to file
CodeOpen more actions menu
Folders and files<br>NameNameLast commit message<br>Last commit date<br>Latest commit
History<br>46 Commits<br>46 Commits
assets
assets
references
references
workflows
workflows
.gitignore
.gitignore
LICENSE
LICENSE
README.md
README.md
SKILL.md
SKILL.md
View all files
Repository files navigation
spec-forge
A Claude Code skill that adversarially certifies a specification as behaviorally<br>complete — before any code is written.
The goal is not a longer spec. It is a spec with no observable residual freedom:
Spec S is behaviorally complete iff every implementation satisfying S is<br>observationally equivalent to every other, under a declared observation alphabet Σ.
Names, formatting, and internal structure are not in Σ, so a complete spec does not<br>have to mention them. What it must not do is leave a coding agent guessing about<br>behavior that Σ can see.
Why this exists
If you hand a spec to a coding agent and it stalls — asking questions, or worse,<br>silently inventing unstated behavior — the spec was underdetermined. That is<br>measurable without rendering the application:
A spec is underdetermined exactly where an adversary can exhibit two implementations<br>that both satisfy it and diverge on Σ.
That divergence is the gap, it is localized, and it is already a test case. spec-forge<br>runs adversaries to produce those distinguishing pairs, has a human ratify each one, and<br>turns the ratified answers into clauses and into the acceptance suite. You never author<br>the acceptance suite; you harvest it from the ambiguity resolution.
Two limits are stated up front, because pretending otherwise would be a lie:
The limit is Rice, not Gödel. "Is S complete?" is undecidable in general, so the<br>process is adversarial and statistical and issues a certificate , never a proof. The<br>certificate has a mandatory RESIDUALS section.
Completeness is relative to (agent class A, toolchain T).<br>spec_bits + prior_bits + toolchain_bits ≥ behavioral_entropy. A non-zero integer type<br>discharges "quantity is always ≥ 1" totally and unspoofably; a language without that type<br>needs prose plus a runtime validator plus a property test to get the same teeth. The same<br>spec can be complete in Rust and incomplete in Python, so the certificate names A and T.
Acceptance criterion
Spec completeness = the coding agent's question count + its uncited-decision count.<br>Both zero, or you are not done.
Not "a human read it and liked it." That is not a gate, it is a chore, and it is the first<br>thing anyone skips.
Installing
The repo root is the skill. Put it where Claude Code looks for skills:
git clone https://github.com/blentz/spec-forge ~/.claude/skills/spec-forge
Then ask Claude something like "is this spec complete?" or "certify this spec" and the<br>skill triggers. Python assets are stdlib-only; spec_gate.sh needs bash and python3.
Prerequisite: the Workflow tool. Every phase from 1 on is a Workflow({ scriptPath })<br>call, and it is not delegable — subagents do not get the tool, so you cannot hand this<br>skill to a general-purpose agent and walk away. Drive it from the main loop.
The workflows/*.js files are Workflow scripts, not Node programs. node workflows/ontology.js<br>will fail: agent(), parallel(), and phase() are injected by the Workflow runtime.
The pipeline
Phase 0 OBSERVATION.md declare Σ — what counts as observable<br>Phase 0.5 SPEC.md CLAUSIFY: prose → S-NNN clauses<br>Phase 1 ONTOLOGY.md subject × stimulus grid; the adversary work-list<br>Phase 2 WITNESSES.md underdetermination loop — run until DRY ←──────┐<br>Phase 2b contradiction contradiction hunter — run until CLEAN │<br>Phase 2c ratification did the answer actually ANSWER? earns `seen` │<br>Phase 3 spec-mutation anti-vacuity: every clause must carry bits │<br>Phase 4 CERTIFICATE.md Σ, A, T, dry rounds, RESIDUALS │<br>Phase 5 DISCHARGE.md route each clause to its cheapest enforcement rung │<br>Phase 6 build loop harness first, implementation last ─────────────────┘<br>uncited decision = new witness
Phase 1 is 3% of the spend and finds the worst defects — including entities the author never<br>named, which cannot show up as a MISSING cell because they have no cell. Never skip it.
Driving it
Use the driver. Do not drive it by hand.
assets/forge.py init spec/ # scaffold EMPTY templates<br>assets/forge.py status spec/ # loop state, Σ lint, void counters<br>assets/forge.py next spec/ # what to run now, and why<br>assets/forge.py next spec/ --sigma # the `sigma` arg every...