This repository is an agent-native CRM framework. Preserve the separation between deterministic CRM state and AI-assisted development/orchestration.
- Read
PRODUCT.md,ARCHITECTURE.md,DECISIONS.mdand the relevant module files before changing code. Before product, positioning, roadmap or public-distribution decisions, readdocs/strategy/MASTER_PLAN.mdfirst; for implementation details,ARCHITECTURE.mdandDECISIONS.mdremain authoritative. - For a multi-file feature or significant refactor, create and maintain an ExecPlan under
docs/plans/following.agent/PLANS.md. - Use public module services and named workflows. Never mutate CRM tables from API, MCP or UI code.
- Any write operation must retain validation, audit and trace.
- Keep MCP write tools narrow; destructive or code-generating tools must default to dry-run or require an explicit apply flag.
- Do not add a production dependency unless it removes more complexity than it adds; record the reason in
DECISIONS.md. - Run
npm run verifybefore considering work complete. - Update
TASKS.mdand relevant docs when behavior changes. - Domain-package work requires the
build-custom-domain-packageskill (.claude/skills/build-custom-domain-package/SKILL.md, mirrored at.agents/skills/build-custom-domain-package/SKILL.md) anddocs/PACKAGE_AUTHORING.md. A package imports onlypackages/core/index.js, reaches another package only through a declared capability, and is registered by one static import inpackages/domains/generated/index.js. A single custom object is a module, not a package. - Follow
docs/QUALITY_GATES.mdfor every feature PR, and use theadversarial-reviewskill for any milestone review or pre-merge review task (.claude/skills/adversarial-review/SKILL.md, mirrored at.agents/skills/adversarial-review/SKILL.md). A milestone that skipped the review is unreviewed, not finished. - Respect the core budget rule (ADR-018): new domain-specific business behavior does not go into
packages/coreunless it is first proven to be a reusable runtime capability. A PR that adds a domain concept to core must say which runtime capability it is and why a domain package cannot own it. - Read
docs/PROJECT_STATUS.mdfor what is true in the repository today — merged milestone, the commit the public numbers were measured at, open PRs, production blockers — and update it in the same PR as a milestone merge. Do not put volatile status inMASTER_PLAN.md. It carries no test count: a count is measured intosite/claims.jsonmeasuredAgainstbynode scripts/measure-suite.js --applyand cited from there (ADR-027). Typing one into any document underdocs/failsnpm run gtm:check. - To learn what an application actually has, run
npm run crm -- app inspect --jsonrather than assembling it from source and prose (docs/APPLICATION_INSPECTION.md). Readvalid, thenproblems[], thenlimitations[]— every limitation is a hard boundary on what you may claim. It reads checked-in source only: it opens no database, contacts no provider, and reports no runtime or authorization state. - Compatibility Backfill Rule. When you add or change a horizontal capability — one every domain could use, such as the package seam, a declared capability contract, module evolution, an evidence discipline or an agent-facing surface — record every existing domain's status against it in
docs/architecture/LEGACY_ALIGNMENT_MATRIX.mdin the same PR, usingaligned | partial | deferred | not_applicable | needs_extractionwith a one-line reason. Declaring the gap is required; closing it in the same PR is not. Do not refactor a legacy domain to close a row: extraction is sequenced work (docs/architecture/LEGACY_ALIGNMENT_MATRIX.md), not something a feature PR does on the way past. - A Solution Plan is a checked file with a contract, not prose with headings (
docs/SOLUTION_PLAN.md). Write it, record theapp inspectreport it was written against, and runnpm run crm -- solution check <plan.json>before writing code and again before the review — a plan bound to a composition that has since moved reportsPLAN_STALE. A plan never carries a command: nothing in this framework executes one, and the validator refuses it. - Parallel coding agents. Each agent works in its own sibling worktree outside the repository, owns exactly one branch, and one final integrator reconciles the shared truth. The three rules are in Parallel coding agents below.
- The Repository Truth Contract (ADR-039). A sentence in a current document that states what the framework does or does not do is bound to a fact generated from an executable authority, and cited by stable fact id —
<!-- truth: spine.managed_jobs_service.implemented=absent -->. Existing gates compare documents to documents, and that is exactly how a whole set of them stayed consistently wrong together after Production Spine v1.npm run repo:truth -- --checkruns on every push and pull request as its own step in thepublic-claimsCI job; run it locally when a PR moves a product boundary, a rail, a package contract or the spine, and if a fact moved, runnpm run repo:truthand commit the regenerateddocs/repository-truth.jsonin the same PR. It is a repository-maintenance script, not a rail and not a product command: it adds nothing to the surface budget and never leaves this repository. Rules and boundaries:docs/REPOSITORY_TRUTH.md,docs/QUALITY_GATES.md§6.1.
The application answers questions about itself through a small set of rails —
few tools, distinct jobs. When one of the questions below is the question in
front of you, run its rail rather than assembling the answer from find,
grep and source reading: hand-assembly is slower, and it tends to fail by
inventing a capability the application does not have
(docs/APPLICATION_INSPECTION.md).
| The question in front of you | Rail | Command |
|---|---|---|
| What has this project actually composed? | SEE | npm run crm -- app inspect --json |
| Is this plan valid, and still true of this application? | PLAN | npm run crm -- solution check <plan.json> |
| What is inconsistent or stale in this checkout? | CHECK | npm run crm -- project doctor --json |
| I need a minimal new package starting point. | BUILD | npm run crm -- package scaffold <name> |
| Does this one package conform to the framework? | CHECK | npm run crm -- package test <dir> --json |
| Is the whole project technically healthy? | PROVE | npm run crm -- project verify --json |
| Does this business journey actually work? | PROVE | npm run crm -- scenario run <scenario> --json |
| Is every requirement of the plan actually proven? | PROVE | npm run crm -- solution verify <plan.json> --evidence <evidence.json> |
| Will this refactor preserve behaviour? | PRESERVE | characterization — tests/characterization/, npm run characterize:intelligence |
The selection rule. Use the smallest rail that directly answers the current
question. Do not chain rails automatically, and no rail — app inspect
included — is an obligatory first step. Escalate only when the next question
needs a stronger kind of evidence: what exists → inspect · internally
consistent → doctor · technical health proven → project verify · this journey
proven → scenario run · the plan proven complete → solution verify.
The boundaries between neighbouring rails:
app inspectdescribes what exists — composition, capabilities, records, actions, policies, providers — never health, domain correctness or runtime state.project doctordiagnoses source consistency and drift; it makes no claim about business behaviour.solution checkasks whether the plan still matches the application (PLAN_STALE), not whether it is implemented: it can exit 0 on a plan nobody has built a line of.project verifyproves technical health by orchestrating existing authorities — conformance, the doctor, the project's declared scripts; it runs no business scenario and maps no requirement to proof.scenario runproves one named business journey with linked evidence; it is not whole-project health, and it promotes no JTBD row.solution verifymaps every plan requirement to machine-checked proof and may honestly exit 1 with work unproven; it executes no plan and writes nothing.package scaffoldwrites a minimal conforming skeleton with no invented domain semantics — dry-run by default,--applyto write.package testproves framework conformance by composing the package into a real application, never domain correctness;package validatechecks only that the declaration is structurally valid, so a conformance question ends attest.- characterization freezes a domain's externally observable behaviour before a boundary-preserving refactor, and replays it after.
SEE, PLAN, BUILD, CHECK, PROVE and PRESERVE are the agent's internal labels for its own next action. A user states a goal and never needs to know a rail exists; for goal-shaped work, the Skills choose the rails.
This section appears verbatim in both AGENTS.md and CLAUDE.md, because
each is the file a different harness loads at session start. If the copies
disagree, AGENTS.md is canonical. Parity is kept by hand — diff the two
sections when editing either.
Several agents may work on one milestone at once. Three rules, because breaking any of them has already cost this repository a wave of published numbers:
- One worktree per agent, outside the repository.
git worktree add ../<repo>-worktrees/<name>— a sibling directory, never a path inside the checkout, so no agent's build output, temporary database or generated site lands in another agent's tree. - One branch owner per worktree. The agent that owns a branch is the only one that commits to it. An agent that needs another agent's change waits for the merge or rebases onto it; it does not reach into a worktree it does not own.
- One final integrator reconciles shared truth. Every wave ends with a
single pass over the files every branch touches —
docs/PROJECT_STATUS.md,site/claims.json, the JTBD matrix, the roadmaps — because a merge that resolves a conflict in a measured record silently discards a measurement. That is not hypothetical: a branch re-measuredsite/claims.json, the merge kept main's older block, and the ledger ran a whole wave behind the suite with every gate green.npm run gtm:checknow fails on that particular drift (scripts/measurement.js), and the integrator pass is what catches the rest.
Sequenced in docs/QUALITY_GATES.md §1.11.
- Node.js ESM and standard-library-first JavaScript.
- Use
// @ts-checkand JSDoc for public APIs. - Prefer small explicit functions over hidden metaprogramming.
- Return domain objects, not raw SQLite rows with encoded JSON.
- Use cents for monetary values and ISO 4217 currency codes.
- Use ISO-8601 UTC timestamps.
- Log MCP diagnostics only to stderr; stdout is reserved for JSON-RPC.
- behavior works end-to-end;
- tests cover happy path and policy boundary;
- trace and audit are visible;
- no direct table mutation outside module services;
- documentation is sufficient for another coding agent to continue;
- every claim in the docs, the ADR, the PR body and the JTBD matrix traces to a merged test — a capability and its limitation are stated in the same breath.
Before adding a new agent-facing command, tool, contract or namespace,
answer these in the PR. Canonical rule and full rationale:
docs/strategy/CODING_AGENT_DX_NORTH_STAR.md.
Goal-first outside, rigorous inside. New internal complexity is justified only if it reduces perceived user or agent complexity, or measurably improves reliability or evidence.
- name the concrete agent failure mode it prevents — the failure, not the capability;
- prove existing primitives are insufficient, having tried to extend one;
- minimise semantic overlap: two commands answering nearly the same question is worse than one that answers it completely;
- keep it deferred or on-demand unless every session needs it;
- preserve portability — behaviour belongs in the CLI, a JSON contract, the Package Contract, canonical Skill semantics or the Quality Gates, never in harness-specific logic;
- ship machine-readable evidence of its value: an exit code, a contract-versioned document, a fingerprint, a measured number;
- if the capability is horizontal, update the Compatibility Backfill Rule and the Legacy Alignment Matrix in the same PR;
- show the end-user goal flow gets simpler, not more manual. "The agent now has one more thing to run" fails the first bullet.
- Flag any API/MCP handler that executes SQL directly.
- Flag any mutation without actor context and audit event.
- Flag AI-generated business decisions that are not encoded as explicit policy or approval.
- Flag money represented as floating-point currency amounts.
- Flag domain-specific business behavior added to
packages/corewithout the ADR-018 justification. - Flag a JTBD row promoted without linked evidence, or a document claiming a capability the tests do not prove.
- Flag a new agent-facing command, tool or contract that does not clear the DX Simplicity Gate above.