Stop letting your AI agent one-shot 2000-line changes it doesn't understand.
Recursive decomposition workflow for AI coding agents β turn a vague idea into an implemented, verified change through small, confirmable steps.
You ask an AI agent for a non-trivial feature. It either:
- dives straight into code and you discover its (wrong) design decisions in a 1500-line diff, or
- writes a 10-page design doc that you skim, approve without really reading, and that drifts from reality by step three.
Both fail the same way: the unit of review is too big. Humans are great at judging one small, concrete decision β and terrible at auditing a wall of text or a mega-diff.
PRISM splits design into small recursive nodes β one digestible node.md at a time, each with
an explicit decision gate. The agent proposes, you react, it drills deeper. Nothing gets implemented
until every node is atomic β small enough to be obviously right.
flowchart LR
P[propose] --> D[decompose]
D --> R[drill]
R -->|until atomic| R
R --> I[integrate]
I --> A[apply]
A --> V[verify]
V --> X[archive]
The core principles, baked into every command:
- Decision-first, not analysis-first. Not "here are 3 options, you weigh them" β but "I propose X because Y; rejected B/C in one line." One thing to react to.
- One small node at a time. You never face the whole analysis at once.
- Recursive decomposition until a node becomes obvious.
- Grounded in real code β the agent reads your codebase before designing, never in a vacuum.
- No big upfront docs. They overwhelm and get skimmed. Forbidden by convention.
- Sized to the change. A
small-tier change is one atomic node: two gates total, no decomposition theater,integrateskipped entirely. The full flow is for changes that earn it.
Every node carries an explicit status (βͺ proposed β π‘ in progress β π’ atomic β π΅ applied β
β
verified, plus βΈ for user-deferred parts) with formally defined transitions β a killed
session resumes exactly where it stopped, and status offers a gated repair when the state
table and reality disagree.
# Go toolchain:
go install github.com/mcoder33/prism@latest
# or, no Go required β prebuilt binary (Linux/macOS):
curl -fsSL https://raw.githubusercontent.com/mcoder33/prism/main/install.sh | sh
# (Windows: grab the .zip from the Releases page.)
cd your-project
prism init # interactive TUI β pick your agentsThen, inside your agent:
/prism:propose # describe the problem, get a 1-screen seed proposal (+ change tier)
/prism:decompose # split into 2-4 small parts (a single part for small-tier changes)
/prism:drill # drill ONE part until atomic (spec, detail, diagram, tasks)
/prism:integrate # cross-part wiring: diagram + combined signatures (skipped for small)
/prism:apply # implement part-by-part, one commit per part, checks after each
/prism:verify # pedantic QA on a running dev env: tests, smoke, concurrency, load
/prism:status # where am I β phase, node table vs reality, the one next action
All design artifacts live in .prism/ at the repo root β git-excluded automatically,
it's local working state. (Optionally a project can commit .prism/archive/ as shared
reference β see the conventions installed by prism init.)
- Skim the principles above.
- Open the worked example β a complete small-tier change, every artifact in its final state:
.prism/archive/example-json-list/. Start with itsREADME.md(the status table), thenproposal.mdand the01-json-flag/node. - Run
/prism:proposein your agent and let the gates walk you through your first change.
/prism:drill takes one part and brings it to atomic. It writes the node.md digest first
and stops at a gate β you react to the digest and the proposed artifact set before anything
else is generated (trivial nodes skip the diagram and spec). Here's what that looks like for a
01-token-bucket node of a rate-limiter change β three artifacts carry the weight:
node.md β the unit of review. 5-7 lines. You react to this, not to a design doc:
concept.drawio β a real diagram, not ASCII art. The agent hand-crafts mxGraph XML and
validates it with xmllint. Open it in draw.io or the VS Code extension:
signatures.md β the API before any code. Signatures + what/why comments, no implementation.
Catch a bad interface here, where changing it costs nothing:
Plus spec.md (Requirement/Scenario β they drive the tests later) and tasks.md (the checklist
apply executes). If a node turns out too big β drill redirects to decompose instead of
patching on the fly.
.prism/<change>/
βββ proposal.md Why / What / Constraints / Decisions / Non-goals (< 1 screen)
βββ concept.md candidate + chosen/rejected strategies
βββ data-flow.drawio conceptual data-mutation chain
βββ 01-parser/ β a node
β βββ node.md 5-7 line digest β the unit of review
β βββ spec.md requirements as Requirement/Scenario
β βββ detail.md decision-complete implementation plan
β βββ signatures.md code sketch: signatures + what/why
β βββ tasks.md checklist the agent executes
βββ 02-renderer/ β another node (drills into 02a, 02b... if needed)
βββ integration.drawio how the parts connect
βββ tasks.md root order + cross-cutting concerns only
Switch between concurrent changes like git branches: /prism:use persists the active change
in .prism/CURRENT, and every command targets it automatically.
One prism init installs native slash commands for every agent you use β same methodology,
shared .prism/ state, so you can propose in Claude Code and apply in Cursor.
| Tool | Commands | Invocation |
|---|---|---|
| Claude Code | .claude/commands/prism/ |
/prism:propose |
| Cursor | .cursor/commands/ |
/prism-propose |
| Codex CLI | .codex/prompts/ |
/prism-propose |
| Gemini CLI | .gemini/commands/prism/ |
/prism:propose |
| GitHub Copilot | .github/prompts/ |
/prism-propose |
| Windsurf | .windsurf/workflows/ |
/prism-propose |
| OpenCode | .opencode/command/ |
/prism-propose |
| Roo Code | .roo/commands/ |
/prism-propose |
| Cline | .clinerules/workflows/ |
/prism-propose.md |
Adding a tool is one adapters.Tool value (internal/adapters/adapters.go) β
file path + naming + frontmatter format. PRs welcome.
Two kinds of files, two different fates β this trips people up:
- Generated command files (
.claude/commands/prism/,.cursor/commands/, β¦) are normal repo files. Commit them so every teammate gets the slash commands on clone, without installing anything. .prism/(theconventions.mdthe commands read, plus your in-flight change artifacts) is git-excluded β local working state. On a fresh clone it isn't there.
So a teammate who clones a repo with committed commands still needs the shared conventions locally.
The one-time bootstrap: install the CLI and run prism update (or prism init) once β it
regenerates .prism/conventions.md in place. Run prism doctor to confirm everything lines up
(versions match, .prism/ is git-excluded, no stale CURRENT). If you'd rather not have teammates
install the CLI at all, commit .prism/conventions.md too (see the archive-sharing note in the
installed conventions for how to un-exclude selectively).
OpenSpec and spec-kit pioneered spec-driven AI development, and PRISM borrows the installer model from them. The difference is the shape of the artifact:
| Spec-driven (OpenSpec, spec-kit) | PRISM | |
|---|---|---|
| Unit of review | a spec document | a 5-7 line node |
| Structure | flat: spec β tasks | recursive tree, drill until atomic |
| Decision style | options to evaluate | one decision to react to |
| Depth control | fixed | per-node β drill only where it's murky |
| Post-implementation | done at merge | verify: tests, smoke, concurrency, load |
If your changes are small, spec-driven is enough. PRISM earns its keep on changes where the design itself is the risk: refactors, new subsystems, concurrency, integrations.
prism init [path] [--tools claude,cursor|all] # install commands (TUI without --tools)
prism update [path] [--force] # regenerate after a CLI upgrade
prism list [path] # list active changes in .prism/
prism doctor [path] # diagnose: version drift, stale pointer, prereqs
prism uninstall [path] [--tools β¦] [--shared] # remove generated commands (keeps .prism/ work)Generated files are tool-owned: each carries a prism:generated v<version> stamp and is
overwritten wholesale by prism update β edit templates/, not the output.
How to write template text (budgets, style, rejected framings):
docs/template-style.md.
Single static binary, zero runtime dependencies, templates embedded via go:embed.
make ci # everything CI runs: test -race, vet, lint, vuln, mod-check
make test # just the tests
make cover # tests + coverage summary
make install # build + put `prism` on PATH
make help # list all targets
prism init --tools claude /tmp/sandbox # smoke testCI (GitHub Actions) runs the same five checks on every push and PR β the test job across a
Linux/macOS/Windows matrix; lint and vuln auto-install their tools, so a fresh clone only
needs Go. Pushing a v* tag runs GoReleaser to publish cross-platform
binaries to the release (see .goreleaser.yaml).
Layout:
main.go entrypoint β internal/cli
templates/ tool-neutral command bodies + shared conventions (go:embed)
internal/
workflows/ command registry (id, title, description) + Version
adapters/ per-tool: paths, slash-command naming, frontmatter
installer/ detection, rendering, writing, git-exclude
cli/ cobra commands + bubbletea TUI
Stack: Go stdlib + cobra + bubbletea/lipgloss.
If PRISM saves you from one bad mega-diff, consider a β β it helps others find it.



