Planning
The SPDD cycle and the identifiers that hold it together — R-*, N-* and OP-* ids, what declares each one, and the exact shape the execution graph is parsed from.
/ivar-plan <feature-name>Planning turns a discovery brief into artifacts an execution run can be held
against. It needs a feature session — IVAR_FEATURE set — and a feature that
already exists. Start a fresh cycle with ivar plan create <feature>.
Four artifacts, four gates
Requirements → [approve] → Analysis → [approve] → Plan → [approve] → Graph → [approve] → ExecutionEach phase stops and waits. The agent writes the artifact, shows it to you, and records the approval only after you have said yes.
They live committed under the hall and are projected into the view directory at
plans/<feature>/, so edits there land in the hall's committed copy.
The reference system
Four namespaces. Each is declared in exactly one place and cited everywhere else — that is what makes an approved plan checkable rather than merely agreed.
| Id | Declared in | Cited by | Means |
|---|---|---|---|
R-* | requirements.md | analysis, plan, code comments | a functional requirement |
N-* | requirements.md | plan ## Norms, code comments | a norm — a convention the work must hold to |
OP-* | plan.md ## Operation details | plan ## Operations, execution-graph.json | one unit of implementation |
| workstream id | plan.md ### <id> | execution-graph.json id | a unit of parallel work |
Real examples from this site's own feature: R-QUICKSTART-PAGE,
R-SHARED-COMPONENT, N-VOICE, N-MOBILE, OP-DOCS-CONFIG, workstream
docs-route.
Why the ids earn their keep
A norm cited as N-MOTION in a stylesheet comment points back at the
requirement that asked for it. Six months later the comment still explains
why, and the requirement is still findable — which is the part prose alone
never survives.
Phase 1 — Requirements
Functional requirements with stable R-* ids, non-functional requirements and
norms as N-*, plus constraints. The ids are the contract: everything
downstream cites them, and renaming one silently orphans every citation.
Phase 2 — Analysis
Read the relations in HALL.md first — select the ones involving potentially
affected repos, follow only the linked topics, and record what is relevant in
analysis.md. This checkpoint never edits HALL.md;
/ivar-relations is the only writer of that region.
Then, with approved requirements as context: affected modules (repo, path, impact level), trade-offs between approaches, risks and mitigations, and a recommendation.
Phase 3 — Plan
The plan is the REASONS canvas:
| Section | Holds |
|---|---|
| Requirements | a reference to the approved artifact |
| Entities | the domain model, delta only |
| Approach | the chosen design |
| Structure | file and module organisation |
| Operations | which workstream owns which OP-* ids |
| Operation details | what each OP-* id means |
| Norms | the N-* conventions to follow |
| Safeguards | what to watch out for |
Two sections are parsed, not read
Every other section is prose for a human. ## Operations and
## Operation details are the input ivar feature execute tick parses to build
each executor's prompt: the graph names the OP-* ids a workstream owns, and
the plan is where the executor is told what those ids mean.
## Operations
### checkout-api
- OP-API-CONTRACT
- OP-API-HANDLER
write_contract:
- src/api/checkout.rs
- src/api/checkout_test.rs
## Operation details
**OP-API-CONTRACT** — Define the request and response types for `POST
/checkout`, including the `410` a closed cart answers with.
- `touches`: src/api/checkout.rs
- `tests`: a closed cart answers `410`; an open one answers `200`
- `doneWhen`: the contract compiles and both tests pass
**OP-API-HANDLER** — Implement the handler against that contract, rejecting a
cart the session does not own before any pricing runs.
- `dependsOn`: OP-API-CONTRACT
- `tests`: a foreign cart is rejected before pricing; an owned cart prices once
- `doneWhen`: a foreign cart can no longer reach the pricerThe rules behind that shape:
### <id>is a workstream id, matching the execution graph byte for byte. Not a phase, not a cluster, not a title.### Fase 1or### Cluster 2 — Reportproduces workstreams no graph refers to, and every operation the graph claims is then missing from the plan.- The bullets under it are operation ids and nothing else —
- OP-SLUG, one per line, followingOP-<SLUG>. write_contract:switches the bullets that follow to the paths that workstream may write.execute replancompares this list to decide which workstreams a revision affects, so it is load-bearing.- Every id needs a
**OP-SLUG**entry under## Operation details. The entry's text reaches the executor verbatim and runs until the next declared**OP-***marker or the next heading — a blank line is a paragraph break inside the entry, not its end. ## Operationsis parsed to the end of the file: every later heading opens another workstream named after it. Harmless for## Normsand## Safeguards, but a workstream id must never collide with a section heading.
Getting the shape wrong fails late
A mis-shaped ## Operations section is not caught at approval. The tick
refuses with execute.operation_missing_from_plan — after the graph has been
approved, with nothing launched.
Phase 4 — Execution graph
The graph is approved separately from the plan:
ivar feature execute prepare <feature> --graph-json <path>
ivar feature execute approve <feature>prepare persists the resolved targeting into plan.md, computes the plan
fingerprint over that persisted form, and validates the graph. Between the two
commands the board sits at AwaitingApproval for you to read.
Where a feature actually is
ivar plan status plans/<feature>/plan.mdReports each gate as approved, pending or needs-revision. At the start of a session this is how you re-derive the state: continue from the first gate that is not approved.
Changing an approved artifact
Approval is not a freeze — it is a record of what was agreed, and changing an
upstream artifact marks the downstream gates needs_revision automatically.
Behaviour-changing plan edits — anything in Operations or Approach — require
re-approval of the affected gates.
Never hand-edit approvals
The records under .ivar/features/<feature>/planning/ are written by
ivar plan approve. Editing them by hand desynchronises the gates from the
artifacts they were computed against.
Once execution is in flight, revisions go through the board instead — see Execution.
Features and scope
Create the feature a change belongs to, see which repos are writable, and promote another one the moment the work reaches further than you thought.
Execution
Running an approved plan as parallel workstreams — the graph schema, how targeting is pinned, how write contracts are enforced, and the three ways reality is allowed to diverge.