{"slug":"canonical-model","name":"canonical-model","category":"Architecture","description":"Writes down how your whole system works, and how it should, in one place.","quality":90,"ev":88,"depth":88,"requirements":"None","difficulty":"Advanced","use_when":"Projects too big for anyone to hold in their head.","skip_when":"Small scripts and one-offs.","version":"Nov 2026","license":"MIT","bytes":9021,"zipBytes":4542,"sha256":"18dcd8d5eb6dface0a141236102418f375bf61cf8a8d8d507773aaf857236baf","files":[{"path":"SKILL.md","size":7958},{"path":"LICENSE","size":1063}],"overview":"<p>The code is evidence. The <strong>current model</strong> is the best explanation of that evidence. The <strong>goal model</strong> is the system being built. Development is reconciling the three: code ↔ current → goal.</p>\n<p>A canonical model is not a plan, a summary or a README. Reading it alone must give a full understanding of the existing or intended system: where everything comes from, how it is processed and stored, how it is served, what it costs, what breaks, and what users see. Compress away implementation noise and keep the causal structure. If the last incident could not have been predicted from the model, the model is not deep enough.</p>\n<h2>Contents</h2>\n<p>Current and goal use the same section numbers, so each section can be compared side by side. Scale the sections to the project; coverage matters more than section count.</p>\n<ul>\n<li><strong>00 system:</strong> layers, organizing rules, machines, stores, identities, the truth order (which source wins), dependency direction.</li>\n<li><strong>Domain sections, one per domain:</strong> for each fact, <code>source → transform (path:function) → store → publication → surface that shows it</code>. Name where truth lives and what is derived from what.</li>\n<li><strong>Surfaces:</strong> everything served and shown, including pages, tools, APIs, CLIs, bots and jobs, with the data each reads. The model covers the frontend and features, not only the backend.</li>\n<li><strong>Runtime:</strong> for every request path, the calls, rows and bytes it uses against each quota; whether it is cached; whether cost grows with traffic, table size or the product of two tables; what happens when a dependency or quota runs out; abuse protection on reads and writes; privacy, retention and backups.</li>\n<li><strong>Operations:</strong> workflows, schedules, runners, secrets, deploy, rollback.</li>\n<li><strong>Code:</strong> repo layout, languages, conventions, module boundaries.</li>\n<li><strong>Design</strong> (if there is a UI): the design thesis (who it is for, how it should feel, its signature), then tokens, components, templates.</li>\n<li><strong>Invariants and contracts:</strong> what must always hold, and what enforces it.</li>\n<li><strong>Problems</strong> (current only): everything wrong, slow, duplicated or contradictory, each with evidence.</li>\n<li><strong>Goal only:</strong> resolutions (one per current problem), migration (ordered phases, each with an exit check), how the team works.</li>\n<li><strong>Glossary:</strong> one name per concept in every layer. See \"Sharpen language\".</li>\n<li><strong>Decisions:</strong> short records for choices that are hard to reverse, surprising later, and a real trade-off. Skip the rest.</li>\n</ul>\n<h2>Layout</h2>\n<p>Default to <code>docs/model/</code>. Keep an existing model's names (for example <code>v1/</code> and <code>v2/</code>) instead of renaming.</p>\n<pre><code>docs/model/\n  README.md            index table (section, what it covers, current link, goal link) and notation\n  STATUS.md            inspected commit, date, what was verified and how, what is pending;\n                       committed, built, deployed and observed are separate states\n  SUMMARY-current.md   the whole current system on one page\n  SUMMARY-goal.md      the whole goal system on one page\n  GLOSSARY.md\n  current/NN-name.md\n  goal/NN-name.md\n  decisions/NNNN-slug.md\n</code></pre>\n<p>The repo copy is authoritative. Any other copy (Desktop, wiki) is generated from it. Point <code>AGENTS.md</code> / <code>CLAUDE.md</code> at <code>docs/model/</code>.</p>\n<h2>Rules for every claim</h2>\n<ul>\n<li><strong>Derive from code and observed behavior,</strong> not from docs, comments, commit messages or what anyone said. When the user states how something works, check the code and surface a contradiction immediately.</li>\n<li><strong>Label each claim</strong> measured, inferred or guess, and cite <code>path:function</code>, a command or its output.</li>\n<li><strong>Keep uncertainty explicit.</strong> Record exceptions and unknowns instead of drawing a clean architecture that does not exist:\n  <code>Project.owner: Organization (high confidence, measured in src/projects/model.ts:owner)\n  Exception: legacy personal projects. Unknown: whether they can still be created.</code></li>\n<li><strong>Treat contradictions as findings.</strong> Say which it is: the model is wrong, the code is wrong, there are two systems, or a transition is half done.</li>\n<li><strong>Derive costs from code.</strong> Run every SQL statement through the query planner, map every client fetch to the pages that call it, read the cache headers, and compute headroom per quota. Check platform limits and billing in the provider's docs before using them in a budget.</li>\n</ul>\n<h2>Modes</h2>\n<h3>Build</h3>\n<ol>\n<li><strong>Inventory</strong> everything that exists: routes, pages, tools, endpoints, jobs and workflows, tables and stores, external sources and services, scripts. This list is the coverage checklist. For a large repo, give one read-only subagent each domain on a cheap model, and do the synthesis yourself.</li>\n<li><strong>Trace</strong> each item end to end and write the sections.</li>\n<li><strong>Check coverage.</strong> Every inventory item appears in the model. Add whatever is missing; never leave it out quietly.</li>\n<li><strong>Write the problems</strong> with evidence.</li>\n<li><strong>Teach-back test.</strong> From the model alone, answer three concrete questions (where does X come from, what happens when Y runs out, what does page Z cost), then check each answer against the code. A wrong answer means the model is too shallow. Deepen it and repeat.</li>\n<li><strong>Write the summaries and STATUS</strong> last.</li>\n</ol>\n<h3>Goal</h3>\n<ul>\n<li>Start from the current problems, measured pain, and the real cadence and scale. Do not start from an ideal architecture. Each new component names the measured problem it fixes and why the cheapest fix within the current stack is not enough.</li>\n<li>Aim for smart, simple and easy to extend, good enough for real use, not perfect. Mark aims as aims.</li>\n<li><strong>One canonical source, many projections.</strong> The same model and data serve runtime behavior, documentation, wikis and generated tables. Projections are generated, never hand-copied. No competing schemas, duplicate parsers or docs-only copies of rules.</li>\n<li>Every current problem gets a resolution. The migration is ordered, and each phase ends in a check.</li>\n</ul>\n<h3>Update</h3>\n<p>Any change that alters a flow, store, cost, surface, invariant or term updates the model in the same commit, plus STATUS. Code and model disagreeing is a bug in one of them.</p>\n<h3>Audit</h3>\n<p>Compare the model against the current code for drift. Then report strengths, weaknesses, opportunities and coverage gaps, and say what the most likely next incident is and whether the model would have predicted it.</p>\n<h3>Sharpen language (during any conversation)</h3>\n<ul>\n<li>When the user uses a term that conflicts with the glossary, say so: \"The glossary defines cancellation as X, but you seem to mean Y. Which is it?\"</li>\n<li>When a term is vague or overloaded, propose a precise one: \"By 'account', do you mean Customer or User?\"</li>\n<li>Stress-test relationships with concrete edge-case scenarios.</li>\n<li>When a term is settled, update <code>GLOSSARY.md</code> right away. It holds project-specific terms only, with no implementation details:\n  <code>**Invoice**: a request for payment sent to a customer after delivery.\n  _Avoid_: bill, payment request</code></li>\n<li>A decision record has five parts: title, context, decision, alternatives rejected and why, consequences.</li>\n</ul>\n<h2>Using the model</h2>\n<p>Before a significant change, read the summaries and the affected sections, then ask:</p>\n<ul>\n<li>Does this move the current model toward the goal?</li>\n<li>Does it add a concept we will later have to remove?</li>\n<li>Does it break an invariant?</li>\n<li>Is it fixing the structure or patching a symptom?</li>\n</ul>\n<p>Glossary and decision-record practice adapted from Matt Pocock's <code>domain-modeling</code> (MIT).</p>"}