build_spec
maps the demand report you already ran to a feature list — every feature grounded (backed by a
real quote) — and scaffold writes a project on disk for your agent (Claude Code, Cursor, etc.)
to build inside.
metalworks writes the spec and scaffolds the project. It does not write your product code.
No React components, no API routes, no migrations. It carries the demand forward — as a spec and
a frozen quote table — so the agent that does write the code can’t drift from what real users
asked for.
What you give it / what you get back
You give it: a finishedResearch bundle (the report on .demand), your positioning, and a
target surface ("auto" to let the spec choose). The report argument to the CLI is a stored
report id or prefix (metalworks research list), a path to a report.json, or — omitted entirely
— your latest run.
You get back: a BuildSpec — each line tied to a real quote:
- Features. The model proposes features from the demand clusters; metalworks attaches each cluster’s real quotes as the feature’s evidence. A feature with no real cluster behind it is dropped — the build stays tied to real demand. What survives is only what people actually asked for (capped at 8 core features).
- Build order is grounded, not arbitrary. Features come back ordered by the demand strength of
the cluster behind them (
source_cluster_rank, 1 = strongest).features[0]is the spine — the feature to build first — andSPEC.mdrenders them as a numbered build order. The sequence is a deterministic read of real demand, not a model’s guess at importance. - Surface. With
surface="auto"the same model call that maps features also picks the surface (sdk/web/mobile/cli/ …) and returns a one-linesurface_rationale, grounded in who asked and how technical they are — no generic web-app default, no second model call. Pin a surface and the spec honors it and skips the pick (no rationale). - Screens. The UX skeleton is sketched after the features exist, so each screen maps to real
feature_ids (the old standalone skeleton was blind to what got built). A screen inherits its feature’s evidence: it shipsvalidatedwhen a real voice backs it, an unvalidated hypothesis otherwise. Shell screens (auth/settings) are flaggedscaffolding— needed by every product, not a demand bet. - Personas. Derived from the report’s audience segments, each tied to a real voice.
- Pricing. Tiers are copied straight from the report’s price evidence (
Starterat the low end of observed willingness to pay,Proat the high end). No price signal → no tiers.
scaffold writes the project — pure deterministic templating, no model, idempotent:
EVIDENCE.md is the frozen verbatim quote + permalink table — every id SPEC.md cites appears
here with its exact Reddit text and a source link. The agent must not edit it; to add a feature,
go back to metalworks and re-run the research.
How your coding agent uses it
Once the project is written, metalworks is done. The hand-off:- Open the scaffolded directory in your coding agent (the project’s
CLAUDE.mdand skills are now in scope). - Run
/scaffold-startup. The agent readsdocs/SPEC.md(what to build) anddocs/EVIDENCE.md(the proof), picks the stack hint’s starter, stands up the surface, and builds the features in order — top is the spine (strongest demand), each one a demand a real user voiced. - The lint holds it to the evidence. As the agent writes user-facing copy, a hook runs
cite_or_die.pyon the edited files. A headline that cites an id not inEVIDENCE.mdfails the build; the agent has to find the real supporting quote or drop the claim.
When the result is thin
When the report can’t back a buildable plan, the spec comes backpartial with a caveat. A
partial spec still writes (so you can read the evidence), but it opens with a “Partial spec”
banner instead of pretending to be buildable. The CLI prints the caveat before scaffolding.
One honesty guarantee: an infra error (a 404, an auth failure, a network blip during the model
call) surfaces as a real failure — it’s never silently relabelled a thin-demand partial.
scaffold() raises ValueError if the spec wasn’t built from the report you pass it — otherwise
the frozen EVIDENCE.md would resolve the spec’s refs against the wrong report. Always scaffold a
spec against the report it came from.
Next: plan where it gets distributed — distribution and GEO / LLM-citability — from the same report. Or read why you can trust the output — the rule that keeps every feature tied to a real quote.