Pre-launch. Not deployable to production. This page states what the tests prove and what is missing — nothing else.

Making an AI agent write a plan a second reader can check

Decide what to build

People ask this as: make a coding agent plan before it writes code, in a format i can review

A file contract, a validator and a binder — not a planner and not a runtime. It defines what a Solution Plan is (six decision rungs, six evidence categories, a closed approval vocabulary, a canonical fingerprint), refuses anything outside that shape, and binds the plan to a real application-inspection report so a plan written against a composition that has since moved reports itself PLAN_STALE. Nothing here writes source, installs a package, configures a provider or executes a step, and a plan cannot carry a command at all: there is no command field in the shape and no code path from a step to an invocation.

Where this stops

Read this before the rest of the page. Every line below is a thing this does not do.

  • It is not a planner. Nothing here writes a plan for you — there is no built-in model, and who authors the document is outside this contract.
  • It is not a runtime. Nothing executes a plan, writes source, installs a package, configures a provider, starts a server or deploys (PLAN_NOT_EXECUTED).
  • An approval code marks a human-actor boundary, not a role. No authentication, tenancy or RBAC exists, so nothing is enforced against an identity (APPROVAL_NOT_RBAC).
  • An observed fact is checked for shape and for its citations. It is never checked for truth: no query runs and no database is opened (EVIDENCE_NOT_VERIFIED).
  • The binding is source-only. A current fingerprint says the composition has not moved; it says nothing about what is deployed, what a database holds or whether a provider works (BINDING_IS_SOURCE_ONLY).
  • The executable-content text filter is defense in depth, not a security control. It refuses some legitimate prose and will miss an encoded payload — the real protection is that nothing reads these fields as instructions.
  • There is no automated goal-to-acceptance runner. Verifying that a built solution satisfies its plan is roadmap work (DX10), not a command you can run today.

No authentication, tenancy or RBAC. The server is local-development-only. An actor header is an assertion, not an identity. Do not expose it to a network. Every claim and every limitation is on one page.

What question it answers

"What are you going to do about it, and on what evidence?" — in a shape a second reader can check rather than interpret. The `solve-business-goal` skill has always asked for a Solution Plan with sixteen named parts, and every agent wrote it differently: different section names, different order, different words for "we do not know". A human could not diff two of them, a second agent could not read one, and nothing could check whether the application a plan was written against was still the application in front of you.

`AGENTS.md` rule 15 states the consequence: a Solution Plan is a checked file with a contract, not prose with headings.

What it does

Three commands over one document. `crm solution inspect <plan.json>` prints the normalized plan without judging it. `crm solution validate <plan.json>` checks the contract alone and reads no project at all, so it runs in CI or against a repository that is not the one the plan targets. `crm solution check <plan.json>` validates and then binds the plan to this project's live inspection report.

Six decision types, each mapped to a rung: `configure` (1), `extend` and `evolve` (2), `provider` (3), `create-package` (4), `propose-kernel-capability` (5). Rung 5 exists so a plan can state a kernel gap; the validator refuses it in `steps[]` with `PLAN_DECISION_NOT_A_STEP`, because patching the kernel to make a solution fit is the exact failure the hierarchy was written to prevent. Rungs 3 and above must record every lower rung in `rungsTried`, a reason per rung in `rejectedRungs`, and the capability `gap` no installed package fills — anything missing is `PLAN_RUNGS_NOT_INSPECTED`.

Evidence comes in six categories and no others: observed facts, derived metrics, assumptions, inferences, recommendations, unavailable evidence. The set is closed in both directions — an invented category is refused and a missing one is a problem — and citations point one way only, forming a DAG over categories so a conclusion cannot be laundered into a premise. Wrong direction is `PLAN_CITATION_DIRECTION`; an unknown id is `PLAN_CITATION_UNRESOLVED`.

The binding is a 64-character `inspectionFingerprint` derived from the canonical inspection report. Running `crm solution check` against `examples/solution-plans/lead-to-won.plan.json` here exited 0 and printed "No problems. The plan is valid and current against this project", followed by this project's composition fingerprint `bbf0f37c…`. Running it against `examples/solution-plans/govern-delivery-change.plan.json` — a historical example written at milestone 14b2 — exited 1 with twelve problems, nine `PLAN_STALE` and three `CAPABILITY_NOT_AVAILABLE`, each naming exactly what moved: "the plan was written against package \"delivery\", which this application no longer composes", and "the plan was written against composition 44beabff…; this project is bbf0f37c…". That is the whole mechanism working in public.

What it refuses to claim

Four codes ride on every plan whether or not its author wrote them, and they were printed on both runs above: `PLAN_NOT_EXECUTED` (a document, not a runtime — nothing here runs, installs, deploys or modifies source), `APPROVAL_NOT_RBAC` (an approval code marks a human-actor boundary; there is no auth, tenancy or RBAC, so no role is enforced anywhere), `EVIDENCE_NOT_VERIFIED` (an observed fact is checked for shape and citation, never for truth — no query is run and no database is read), and `BINDING_IS_SOURCE_ONLY` (the bound report is source-only and says nothing about a database, a provider's health or what is deployed). A `provider` decision adds a fifth, `PROVIDER_STATUS_UNKNOWN`, whatever its author wrote.

A plan cannot carry executable content, and the guide separates the two levels honestly. By contract there is no command, script or effect field anywhere in the shape, unknown keys are refused rather than ignored (`PLAN_FIELD_UNKNOWN`), and there is no code path from a step to an invocation — that is the actual boundary. Free text is additionally matched against shell commands, substitutions, chaining, remote addresses and script tags (`PLAN_EXECUTABLE_CONTENT`), and that filter is described as defense in depth rather than a sandbox: it is deliberately conservative, refuses some legitimate prose, and will miss a sufficiently encoded payload.

The fingerprint is a drift detector over the whole composition — package identities and versions, capability resolution, resources, declared action metadata, policy and provider fingerprints, record revisions, migration checksums, and the problems and limitations that bound what may be planned. It is not proof of authorship, authorization or correctness.

`acceptance.artifacts[]` names a place and never content. An absolute path, a `..` escape, a path claimed twice, or any field carrying file content is refused — an artifact holding source is the executable-content boundary in a different costume.

What it costs to run

`validate` reads no project and finishes in milliseconds. `check` runs an application inspection internally and captures it, so it costs roughly what that inspection costs — both plan runs above returned in well under a second here, and the plan is the only thing on stdout.

Exit codes: `0` valid (and, for `check`, current), `1` the plan has problems and the complete list is still printed, `2` the plan or the project could not be read at all. `inspect` reports without judging, so it exits 0 even for a plan with problems — and prints them anyway.

Nothing is written. A plan is a file you author and commit; these commands only read it. Bounds are refusals rather than truncations: a plan is at most 1 MiB, a text field 2,000 characters, an identifier 120, a list 200 entries, a citation list 50 — because a plan silently cut to 200 decisions reads as a complete plan.

Where it fits

Between seeing what exists and building anything: inspect the application, write the plan recording that report, run `solution check`, fix every problem before writing code, then run it again before the review. A stale plan is not a plan.

The three jobs it serves are all recorded as partially supported, not validated — turning an objective into a reviewable plan, building the solution as checked-in source, and verifying it against defined acceptance. The honest reason is that the contract, the validator and the binding are real and the goal-to-acceptance runner is not; the roadmap tracks it as DX10 and it does not exist.

The evidence this page rests on

Claims and limitations are printed from site/claims.json word for word. Job statuses come from docs/benchmarks/jobs.json; a job with no page of its own is listed with its status rather than linked.

Claims

  • C-15 A Solution Plan is a checked-in file with a contract and a canonical fingerprint, validated against a real inspection — so a plan written against a composition that has since moved reports itself stale.

    LimitA document contract, not a planner and not a runtime. Nothing executes a plan, and the validator refuses a plan that carries a command.

  • C-14 One command tells an agent what an application actually is — packages, capabilities, resources, actions, policies, providers — read from checked-in source, in a single deterministic JSON report.

    LimitSource-only and read-only. It never opens the database, contacts a provider, reads a secret, or reports runtime, CI or authorization state — and it lists those blind spots as machine-readable limitations in its own output.

  • C-17 Zero third-party runtime dependencies. Node 22 and a checkout — no build step, no bundler, no framework underneath your framework.

    LimitDevelopment dependencies and the eventual PostgreSQL adapter are separate questions. Having no runtime dependencies is a property of the framework, not of whatever you add on top of it.

Limitations

  • L-01 No authentication, tenancy or RBAC. The server is local-development-only. An actor header is an assertion, not an identity. Do not expose it to a network.
  • L-03 The build benchmark has not been run. The protocol is designed and published; no Successful Agent Build Rate exists yet. Any number you see quoted for this project is not ours.
  • L-04 No scheduler, no task engine, no reminders. One follow-up Task is created inside lead qualification. There is no recurring work, no delayed workflow, no queue — so nothing fires on a renewal notice period either.

Jobs it covers