Your decisions, as an app
This recipe is what an agent made of one prompt, in a repository it had never seen. The architecture decision records: what each decided, what it superseded and which modules it affects, with the loose ends flagged.
Read https://graview.dev/start.md, then turn this repo's decisions into a Graview app.Paste it into Claude Code, Codex or Cursor at the root of your repository. start.md is the page the agent reads.
The app, running
This is the declaration below, compiled in your browser by the same compiler graview check uses, over the seed below. Press a district; open the problems; take a repair.
Your decisions, as an app, loading…
What the agent declared
Larkspur decisions: Larkspur's architecture decision records (docs/adr): each decision, its status and date, what superseded it, and the modules it affects. 2 kinds, 8 acts and 6 rules, each rule with the act that repairs it.
| Kind | Fields | Relations | Records in the seed |
|---|---|---|---|
decision | number, title, status, date, file, wholeRepository | supersededBy to decision; affects to module | 14 |
module | path, packageName, description | none | 16 |
The rules
- A superseded decision names what superseded it. Over each decision, when
status == 'superseded': requirespresent(supersededBy). Repaired by “Name what superseded it” (mark-superseded). - A decision something supersedes says so. Over each decision, when
present(supersededBy): requiresstatus == 'superseded'. Repaired by “Mark it superseded” (mark-superseded) or “It is not superseded” (unmark-superseded). - What supersedes a decision is accepted. Over each decision, when
present(supersededBy): requiressupersededBy.status == 'accepted'. Repaired by “It is not superseded” (unmark-superseded). - A decision is superseded only by a later one. Over each decision, when
present(supersededBy): requiressupersededBy.date >= date. Repaired by “It is not superseded” (unmark-superseded). - A proposal is decided within 90 days. Over each decision, when
status == 'proposed': requiresdays(date, today()) <= 90. Repaired by “Accept it” (accept-decision) or “Reject it” (reject-decision). - An accepted decision affects something. Over each decision, when
status == 'accepted': requireswholeRepository == true or exists(out('affects')). Repaired by “Name a module it affects” (affect-module).
What graview check says
Run on every push, against the committed file:
A line starting with a dot is a note, not a warning: advice the checker leaves for a person to weigh.
How it was made
An agent was given the prompt above and nothing else, at the root of Larkspur: a booking service for small clinics that does not exist, written as a TypeScript monorepo the size of a real one, with sixteen modules, guides and runbooks with gaps, a CODEOWNERS that misses some, fourteen decision records and pinned dependencies. It followed start.md, scaffolded, declared, ran graview check until it was clean, opened graview preview and reported back. The two files it wrote are committed as they came out of that run.
CI does not run an agent. On every push it checks the committed declaration with graview check --document, loads the seed into a store, and opens this page in a browser to see the app mount. To run the prompt again yourself:
node scripts/fixtures/recipes/larkspur.mjs larkspur
cd larkspur && git init -q && git add -A && git commit -qm larkspur
# then paste the prompt into your agentThe files: app.json and seed.json (30 records and 28 relations).
The declaration, in full
{
"format": "graview-document",
"formatVersion": 1,
"name": "Larkspur decisions",
"description": "Larkspur's architecture decision records (docs/adr): each decision, its status and date, what superseded it, and the modules it affects.",
"kinds": {
"decision": {
"noun": "decision",
"plural": "decisions",
"label": "ADR {number}: {title}",
"description": "One numbered record in docs/adr. Never edited after it is accepted; a changed mind is a new record that supersedes the old one.",
"fields": {
"number": { "type": "integer", "required": true, "min": 1, "description": "The record's number, from its file name and heading." },
"title": { "type": "string", "required": true, "description": "The record's heading, without its number." },
"status": { "type": "enum", "options": ["proposed", "accepted", "rejected", "superseded"], "required": true, "description": "The record's Status line." },
"date": { "type": "date", "required": true, "description": "The record's Date line." },
"file": { "type": "string", "required": true, "description": "Where the record lives in the repository." },
"wholeRepository": { "type": "boolean", "label": "Affects the whole repository", "description": "The record's Affects line says the whole repository rather than naming modules." }
},
"edges": {
"supersededBy": { "to": ["decision"], "cardinality": "one", "description": "the decision that superseded it", "inverse": "the decisions it supersedes" },
"affects": { "to": ["module"], "cardinality": "many", "description": "the modules it affects", "inverse": "the decisions that affect it" }
},
"fieldRoles": { "when": "date" },
"glance": ["status", "date", "wholeRepository"]
},
"module": {
"noun": "module",
"plural": "modules",
"label": "{path}",
"description": "A workspace package that pnpm-workspace.yaml takes in: a directory under services/, packages/ or tools/ with its own package.json.",
"fields": {
"path": { "type": "string", "required": true, "description": "The directory, from the repository root." },
"packageName": { "type": "string", "required": true, "label": "Package", "description": "The name in its package.json." },
"description": { "type": "string", "description": "The description in its package.json." }
}
}
},
"acts": {
"add-decision": { "creates": "decision", "title": "Record a decision", "description": "Add a decision record from docs/adr." },
"add-module": { "creates": "module", "title": "Add a module", "description": "Record a workspace package." },
"affect-module": { "on": "decision", "connects": "affects", "title": "Say it affects a module", "description": "Name a module this decision affects.", "fromTheOtherEnd": "Name a decision that affects it" },
"unaffect-module": { "on": "decision", "severs": "affects", "title": "Say it no longer affects a module", "description": "Take a module off this decision's Affects line.", "fromTheOtherEnd": "Take a decision off it" },
"mark-superseded": { "on": "decision", "connects": "supersededBy", "sets": { "status": "superseded" }, "title": "Name what superseded it", "description": "Name the decision that superseded this one, and mark it superseded.", "fromTheOtherEnd": "Name a decision it supersedes" },
"unmark-superseded": { "on": "decision", "severs": "supersededBy", "sets": { "status": "accepted" }, "title": "It is not superseded", "description": "Take back what superseded this decision, and mark it accepted again.", "fromTheOtherEnd": "Take back a decision it supersedes" },
"accept-decision": { "on": "decision", "sets": { "status": "accepted" }, "title": "Accept it", "description": "Mark the decision accepted." },
"reject-decision": { "on": "decision", "sets": { "status": "rejected" }, "title": "Reject it", "description": "Mark the decision rejected: it was considered and not taken." }
},
"rules": {
"superseded-names-successor": {
"title": "A superseded decision names what superseded it",
"over": "decision",
"when": "status == 'superseded'",
"require": "present(supersededBy)",
"says": "ADR {number} is superseded but does not say by what",
"repairs": [{ "act": "mark-superseded", "label": "Name what superseded it" }]
},
"successor-is-marked-superseded": {
"title": "A decision something supersedes says so",
"over": "decision",
"when": "present(supersededBy)",
"require": "status == 'superseded'",
"says": "ADR {number} has a successor but its status is {status}",
"repairs": [{ "act": "mark-superseded", "label": "Mark it superseded" }, { "act": "unmark-superseded", "label": "It is not superseded" }]
},
"successor-is-accepted": {
"title": "What supersedes a decision is accepted",
"over": "decision",
"when": "present(supersededBy)",
"require": "supersededBy.status == 'accepted'",
"says": "ADR {number} is superseded by a decision that is not accepted",
"repairs": [{ "act": "unmark-superseded", "label": "It is not superseded" }]
},
"successor-is-newer": {
"title": "A decision is superseded only by a later one",
"over": "decision",
"when": "present(supersededBy)",
"require": "supersededBy.date >= date",
"says": "ADR {number} is superseded by a decision dated before it",
"repairs": [{ "act": "unmark-superseded", "label": "It is not superseded" }]
},
"proposal-not-left-open": {
"title": "A proposal is decided within 90 days",
"over": "decision",
"when": "status == 'proposed'",
"require": "days(date, today()) <= 90",
"says": "ADR {number} has been proposed since {date} and is still open",
"repairs": [{ "act": "accept-decision", "label": "Accept it" }, { "act": "reject-decision", "label": "Reject it" }]
},
"accepted-affects-something": {
"title": "An accepted decision affects something",
"over": "decision",
"when": "status == 'accepted'",
"require": "wholeRepository == true or exists(out('affects'))",
"says": "ADR {number} is accepted but names no module it affects",
"repairs": [{ "act": "affect-module", "label": "Name a module it affects" }]
}
}
}