Invoke $reconstruct explicitly in Codex or /reconstruct in Claude Code.
The shipped skill disables automatic activation in both hosts; CLI commands
remain unchanged. Other hosts may not honor these settings. Existing installed
copies need to be updated to receive this invocation policy.
Turn any repository β or a greenfield idea β into reconstruction PRDs an AI agent can rebuild the project from: faithful to the original (logic, routes, translations, schema, config), optionally improved, and buildable enough that a fresh agent gets the contracts right β enforced by a
--checkgate.
reconstruct is an Agent Skill (the open agent-skills
ecosystem by Vercel). It pairs a thin deterministic scaffold with a thick AI
playbook: a bundled, dependency-free Node script extracts universal facts, resolves routes
(with their HTTP method) for the major frameworks, and surfaces candidate hints for
everything else; the AI agent that runs the skill supplies the deeper framework-aware
understanding β the full interface surface, the data model, and the real features β for
any stack.
π Full documentation:
DOCUMENTATION.mdβ concept, CLI reference, the analyzer pipeline, how to extend it, and FAQ.
# into the current project (committed, team-shared)
npx skills add maxgfr/reconstruct
# or globally for all your projects
npx skills add -g maxgfr/reconstructThis installs the skill into your agent. Invoke it explicitly:
Codex:
$reconstruct on this repo in redesign + complex mode. Claude Code:/reconstruct on this repo in redesign + complex mode.
reconstruction/
βββ REBUILD.md # master plan: build order + validation checklist
βββ RECONSTRUCTION.md # (--merge) the whole tree in one markdown, WITH embedded source
βββ SPECS.md # (--specs) the whole spec, code-free β the file to implement from
βββ FEATURES.md # (--features) every feature PRD only, in build order
βββ SUMMARY.md # one-page digest β written on EVERY run; read it to orient
βββ 00-overview/PRD.md # product summary, stack, metrics, feature index
βββ architecture/
β βββ ARCHITECTURE.md # architecture + external services, cross-cutting policies, i18n message catalog
β βββ INTERFACES.md # interface surface (method Β· path Β· kind Β· handler) + per-op input/output/side-effect contracts
β βββ DATA-MODEL.md # entities, fields, relations, indexes + enums & domain types
β βββ DESIGN-SYSTEM.md # design tokens, theming, typography, components & a11y (UI products)
β βββ diagram.md # mermaid module diagram
βββ features/
β βββ NN-<slug>/PRD.md # one PRD per feature/module (build-order tiered)
βββ data/ # ground truth, copied verbatim
β βββ translations/ # i18n files
β βββ schema/ # DB schema / models
β βββ config/ # build/lint/env config
βββ source/ # (fidelity=mirror) copied real source, per feature
βββ inventory.json # machine-readable manifest
| Axis | Values | Effect |
|---|---|---|
| Mode | preserve | redesign | scratch |
Keep the current architecture, design a fresh one for the same features, or build greenfield from an interview (see From scratch). |
| Level | light | complex |
Faithful & concise, or also suggest improvements the agent folds in. |
| Fidelity | mirror | embed | describe |
Copy real files / inline key code / text-only. |
Fidelity defaults are derived (override with --fidelity):
| Mode + Level | Fidelity |
|---|---|
| preserve + light | mirror |
| preserve + complex | embed |
| redesign + light | embed |
| redesign + complex | describe |
Translations, schema, and config are always copied into
data/verbatim, regardless of fidelity β you can't faithfully "rewrite" data.
The deterministic engine also runs on its own (no agent, no API key):
node scripts/analyze.mjs --repo ./my-app --out ./my-app/reconstruction \
--mode preserve --level light --fidelity mirror
# inspect the raw inventory without writing anything
node scripts/analyze.mjs --repo ./my-app --jsonRun node scripts/analyze.mjs --help for all flags.
Four optional, combinable flags collapse the multi-file tree:
--mergeβRECONSTRUCTION.md: the whole tree in one coherent markdown (single H1, linked table of contents, headings demoted one level; ordered overview β architecture β features β build order), with the embedded original source. The complete archive.--specsβSPECS.md: the same whole tree as--mergeβ overview, architecture (interfaces + data model), every feature PRD, build order β but with each document's## Source materialsection (the embedded original source code) stripped. Self-sufficient (it carries the contracts the feature PRDs reference) yet code-free, so it's the single file you hand an agent to (re)implement the project from.--featuresβFEATURES.md: every feature PRD only β the product functionality β in build order, in one file (single H1 + table of contents). The features-only counterpart to--merge.SUMMARY.md: a one-page digest from the inventory (stack, libraries, size, features in build order, interface/data counts, locales, unknowns, next steps). Written on every run β it is the cheap orientation document, a few KB against aninventory.jsonthat grows linearly with the repo.--summaryonly selects it for the standalone post-step below.
# inline: produce the tree and the bundles in one run
node scripts/analyze.mjs --repo ./my-app --out ./my-app/reconstruction --merge --specs --features
# standalone post-step: (re)build the bundles from an existing output, no --repo
node scripts/analyze.mjs --merge --specs --features --summary --out ./my-app/reconstruction
# just the code-free spec to implement from, from an existing reconstruction:
node scripts/analyze.mjs --specs --out ./my-app/reconstructionThe standalone form reads <OUT>/inventory.json + the .md files, is idempotent,
and errors clearly if the directory holds no inventory.json.
A reconstruction is only useful if a fresh agent can rebuild each unit correctly from the PRD + architecture docs alone. Once the PRDs are enriched, run the buildability gate:
node scripts/analyze.mjs --check --out ./my-app/reconstructionIt exits non-zero on the structural failures β unresolved π§ callouts or fill this in
placeholders, a feature that references an undocumented entity/operation, a feature PRD
missing its spine, an uncovered locale, and a gutted data model / interface surface /
feature PRD (an emptied contract fails too, not just a callout-laden one).
--check covers structure; the ten contract categories a PRD must actually carry β
field-level data model, fully-enumerated enums, operation & write contracts (a public write
can't require an owner foreign key), format validations, external services, quantified
policies, the i18n message catalog, shared/owned UI components, and β for UI products β the
design-system contract (tokens, theming, components, a11y) β are in
references/buildability-checklist.md. In
greenfield mode the engine also validates the plan's consistency before rendering, so
dangling references and anonymous-write-to-owner-FK contradictions are caught up front.
--check is deterministic β it proves structure (no leftover callouts, the docs
declare entities/operations, every PRD keeps its spine). It can't judge substance: a PRD
can pass the gate and still be unbuildable (vague requirements, happy-path-only criteria, an
unsatisfiable write contract, an enum value that contradicts the data model). That second
judgement is the AI review β performed via the skill, not the script: there is no
--ai flag and no API key, because the agent running the skill is the reviewer. After
--check passes, the agent re-reads the tree and applies
references/ai-review-rubric.md (story completeness,
testable requirements, real Given/When/Then incl. failure paths, satisfiable write contracts,
enum fidelity, cross-doc consistency, faithfulness, i18n, and the rebuild self-test), fixing
every blocker in place. Layer 1 is fast and CI-friendly; layer 2 is where a smart model
earns its keep.
The layer-2 review is itself orchestrated by a review ledger so it terminates instead of
looping by feel. --review writes a per-feature worklist (REVIEW.todo.json), flagging only
the units whose content hash changed since the last round; an agent fans out one reviewer per
flagged unit plus one independent verifier per blocker, then --review --apply findings.json reduces the structured findings to REVIEW.json (ok, residual,
noProgress/staleRounds):
node scripts/analyze.mjs --review --out ./my-app/reconstruction
node scripts/analyze.mjs --review --apply findings.json --out ./my-app/reconstruction--check --semantic folds both semantic gates into the structural one β VERIFY.json
(requirements that don't trace to source) and REVIEW.json (unresolved blockers) β additively,
never relaxing --check. The gate is trustless and fail-closed: it re-reduces the persisted
verdicts/findings (never a stored ok), re-resolves every cited evidenceRef against the
inventory, and errors when a ledger is missing or unreadable (pass --allow-unverified to
downgrade that to a warning). For larger trees the enrichment and the review/fix loop both fan out
across subagents; the protocol (map-reduce + the ledger) is in
references/orchestration.md, and the loop
itself β rounds, stopping conditions, the known-gaps report β in
references/convergence-loop.md.
The third gate, --verify, checks faithfulness: it pairs every requirement with the evidence
the analyzer captured and makes you adjudicate each pair (supported Β· partial Β· refuted Β·
unsupported, stamped confirmed Β· inferred Β· gap). Its worklist is capped at 60 pairs
by default β the cap is reported on stdout, in VERIFY.md, and as coverage in
VERIFY.todo.json, and --max-verify <n> raises it. Full contract:
references/verify-playbook.md.
A normal --repo/--scratch run re-renders every document, so pointing one at a tree you
have already enriched would destroy the prose. The CLI detects an enriched tree β a document
whose π§ callouts are all resolved, or a REVIEW.json/VERIFY.json ledger β and refuses:
<out> already holds an ENRICHED reconstruction β re-running the analyzer would overwrite it.
To continue an existing tree use --check/--review/--verify; to re-scaffold, point --out
at a new directory; --force overwrites and loses the enrichment.
The skill shells out to the CLI and parses its output. An MCP server skips both: your agent calls reconstruct as typed tools, with JSON schemas in and structured results out. Same engine, same tree, no wrapper.
# stdio β the default, and what Claude Code / Claude Desktop / Cursor expect
claude mcp add reconstruct -- node /abs/path/to/scripts/analyze.mjs --mcp
# or over HTTP, on loopback
node scripts/analyze.mjs --mcp --transport http --port 7343
claude mcp add --transport http reconstruct http://127.0.0.1:7343/mcpIt serves all three MCP primitives, because a skill is three things: the engine (tools), the method (prompts), and the documentation the method refers to (resources). Here that is the whole point: the markdown is the program and the engine never reasons, so a client given only the tools treats an empty scaffold as a finished spec.
| Tool | What it does |
|---|---|
reconstruct_inventory |
What a repo is made of β stack, entry points, routes. Writes nothing |
reconstruct_check |
The buildability gate: no missing document, no unresolved callout |
reconstruct_review |
Per feature, what a builder would still have to guess |
reconstruct_verify |
Requirementβsource: does the original actually do what the PRD claims? |
reconstruct_specs |
Every feature PRD, source stripped β the hand-to-an-agent bundle |
reconstruct_features |
Every feature PRD, nothing else |
reconstruct_merge |
The whole tree as one document, source included |
reconstruct_read |
A file, or a line range, from the tree or the original repo |
--allow-write additionally exposes reconstruct_scaffold and
reconstruct_brainstorm. The scaffold is annotated destructive: with
force:true it discards prose an agent spent real work writing, and nothing
here can bring that back. It is also the one tool that never inherits the
server's default --out β a delete-shaped operation does not get to guess its
target.
| Prompt | Arguments | What it drives |
|---|---|---|
enrich_feature |
out, feature?, repo? |
Read the real implementation, then write what it DOES β not what its file names suggest |
review_buildability |
out |
What is missing vs what is merely absent; plus the faithfulness direction |
greenfield_interview |
idea |
No repo to read, so every fact comes from the user β and inventing one invents the product |
SKILL.md and all 42 references/*.md β including the 22 per-stack cheat-sheets under references/stack-guides/ β are served under skill://, read off
disk at request time β so a documentation fix reaches every client without a
rebuild.
Two things worth knowing:
- Nothing here reaches the network. The whole engine is a deterministic local walk; no tool is marked open-world.
- The HTTP transport binds
127.0.0.1and refuses anything else unless you pass--allow-remote. This server reads local files; an exposed port is a read-anything primitive for whoever finds it.
Not sure what to build yet? Run the divergent phase before converging. Ask your agent to
"brainstorm ideas" (or run node scripts/analyze.mjs --brainstorm --out ./ideas) and it scaffolds a
BRAINSTORM.md β generate 3+ genuinely different concepts, score them, pick one. Every section
carries a > π§ callout so an un-enriched brainstorm fails --check, the same gate the PRDs use.
Point it at an existing reconstruction (--brainstorm --out ./reconstruction) and it seeds the
recovered surface so you brainstorm evolutions of what's already built. The chosen direction feeds
the greenfield interview below, or lands as iteration PRDs β see
references/brainstorm-playbook.md.
No repo yet? Invoke $reconstruct (Codex) or /reconstruct (Claude Code) to turn an idea into the same reconstruction tree:
"Use reconstruct to turn my idea into a build plan."
You don't write plan.json by hand β the agent does. Following SKILL.md β
references/scratch-playbook.md, it interviews you
(grill-with-docs style: one question at a time, recommending an answer each time), writes the
domain docs (CONTEXT.md, docs/adr/) and a plan.json β the structured transcript of the
interview β then runs the engine and enriches the PRDs:
# the agent runs this for you, once the interview has produced plan.json
node scripts/analyze.mjs --scratch --plan plan.json --out ./reconstruction --level complex --tddplan.json is an intermediate artifact the agent generates from your answers. You can
hand-write one if you prefer β the schema and a worked example are in
references/scratch-plan-schema.md.
Greenfield collapses two axes β mode is always scratch, fidelity is forced to describe
(there is no source to mirror) β while --level still applies (complex = a deeper interview
that also proposes alternatives and more ADRs). On top of the usual tree it also writes the
interview's domain docs, and INTERFACES.md / DATA-MODEL.md / DESIGN-SYSTEM.md come
pre-filled from the plan β along with the enums, external services, cross-cutting policies,
and i18n message catalog the interview captures, so the from-scratch tree is as buildable as the
reverse-engineered one:
reconstruction/
βββ β¦ # the same REBUILD / overview / architecture / features tree
βββ CONTEXT.md # the glossary (from plan.glossary + data-model relations)
βββ docs/adr/NNNN-*.md # one terse ADR per recorded decision
CONTEXT.md and docs/adr/ are written if-absent, so a richer version you authored during
the interview is never clobbered. Add --tdd (here or in any mode) to make every feature PRD and
REBUILD.md drive the build test-first (red β green β refactor).
- The interview:
references/scratch-playbook.md - The
plan.jsoncontract + example:references/scratch-plan-schema.md - A full worked plan:
tests/fixtures/scratch-plan/example.plan.json(pnpm run parityrenders this plan and checks it is buildable-by-construction; pass-- --repo <repo>to also check the code path and the from-scratch path converge).
- Read
00-overview/PRD.md,architecture/ARCHITECTURE.md,architecture/INTERFACES.md,architecture/DATA-MODEL.md, and β for a UI product βarchitecture/DESIGN-SYSTEM.md. - Follow the dependency-tiered build order in
REBUILD.md, implementing onefeatures/<slug>/PRD.mdat a time. - Use
data/(andsource/when present) as ground truth.
Any stack. The deterministic scaffold is universal (tree, deps, env, i18n, stack/library
detection, plus candidate hints for routes/API/schema/entry points β so a stack without a
dedicated adapter is never invisible). On top of that, route adapters resolve the real
routes β with their HTTP method β for twelve framework families (Next.js, Express, Fastify,
Hono, Flask, FastAPI, NestJS, Django, Rails, Go, ASP.NET Core, and tRPC procedures as dot-paths) through a
small pluggable registry. The deeper
framework-aware depth β the full interface surface and data model β comes from the AI playbook
in SKILL.md + references/, with per-stack cheat-sheets in
references/stack-guides/ (Next.js, Remix, Nuxt, SvelteKit,
Astro, Angular, Express/Fastify/Hono, NestJS, Django/Flask/FastAPI, Rails, Laravel, Go, Spring
Boot, .NET/ASP.NET, tRPC/gRPC, GraphQL, mobile, desktop Electron/Tauri, serverless/edge, and
libraries/CLIs/SDKs for repos with no web framework at all).
stack-guides/INDEX.md maps every
label the engine emits onto its guide β the names are deliberately not one-to-one (Flask lives
in django-flask-fastapi.md). Adding agent guidance for a stack is just markdown; adding a
deterministic route adapter is a small, self-contained code PR β see
references/adapters.md.
Monorepos too. Workspaces are detected across ecosystems (npm/yarn/pnpm β with Lerna and
Nx as fallbacks β, Cargo [workspace], go.work) and the analysis is attributed per
workspace: each entry of inventory.workspaces carries its own stack, dependencies, hints,
and the manifest-derived dependsOn graph; features group per workspace and the build order
follows the workspace topological order (shared packages before the apps that consume them).
See references/stack-guides/monorepo.md.
Use an explicit local cases.json with schemaVersion: 1 and nonempty cases:
each case has id, shared stdin, original and rebuilt objects containing
command plus args, and optional timeoutMs (default 5000).
node scripts/analyze.mjs --compare cases.json --original ./original --rebuilt ./rebuilt --run-tests --jsonRead the fixture and explicitly authorize execution first. Without --run-tests,
nothing executes and the result is not-tested/exit 1. A pass requires identical
stdout/stderr bytes and exit 0 for each case (or an explicitly declared
expectedExitCode for negative cases). Timeout, missing commands, empty suites
and output overflow fail. The JSON includes current observations and fixture
SHA-256; it proves only the listed exercised cases, not whole-program equivalence
or source faithfulness. This is local code execution, not a sandbox. See the
fixture schema, limits and workflow.
pnpm install
pnpm run build # bundles src/ -> scripts/analyze.mjs (committed, zero-dep)
pnpm test # vitest unit + integration over multi-stack fixtures
pnpm run typecheckThe analyzer only reads the target repo's filesystem and copies files into the
output. Analysis never executes the analyzed project's code. The separate
--compare --run-tests mode explicitly executes local fixture commands; read them
and authorize execution first. It is not sandboxed. Review scripts/ before
running on untrusted repositories.
MIT Β© maxgfr
See shared engine maintenance for pins, source adoption checks and the daily repin workflow.
These skills run when explicitly invoked: reconstruct. Use $name in Codex or /name in Claude Code and OpenCode (with the plugin namespace when installed as a Claude plugin).
The skill bundle disables implicit selection in Codex and Claude Code. OpenCode V2 reads metadata.opencode/autoinvoke: "false". For OpenCode V1, merge these entries into permission.skill in ~/.config/opencode/opencode.json or the project configuration; retain unrelated permissions:
{
"permission": {
"skill": {
"reconstruct": "deny"
}
}
}On OpenCode 1.18.30, these rules hide the skills from the agent and reject skill-tool loading, while explicit /name commands remain available. Installation with skills add does not apply this OpenCode V1 configuration.