06 · The canon, file by file
What the agency decided, in one standard shape.
A repository, not an agent. People write it by pull request; every agent that needs it clones it when it starts and reads it before it acts. No agent ever edits it. It is one shape for every company: Ability's own fleet canon is the standard, and Keymaker's is an instance of it, cut to five agents. Public: Abilityai/keymaker-canon, a GitHub template you can copy.
keymaker-canon/
├── domains.yaml THE MAP: kind of work → owner agent → role
├── domains/ shared content no agent owns, kept by the steward
│ ├── pricing/pricing.md the price list
│ ├── approvals/approvals.yaml who decides what, up to what limit
│ ├── org-context/ORGANISATION.md who fills each role
│ └── decisions/NNNN-slug.md why - append-only
├── roles/ one file per seat of work - never a person
├── objectives/ what the quarter drives at, owned by a role
├── protocols/ information-routing (the flows) · playbook-call
├── agents/<name>/ each agent's own record - the only place it writes
├── tools/canon-lint/ the linter, identical to the fleet's
└── CONVENTIONS.md seven rules; the first: people write, agents read
How the map is written: domains.yaml
One entry per kind of work. The orchestrator matches a request to a domain id, hands it to that owner agent, and knows which role stands behind it. Change a line here and routing changes everywhere.
- id: deals
description: A named company we are selling to, from Discovery Call Booked to Won
owner: sales-agent
role: sales-rep
path: agents/sales-agent/facts.yaml
consumers: [orchestrator, delivery-agent, marketing-agent]
playbooks: [deal, draft-outreach]
hands_to: client-projects # on Won, Sales writes the handoff
- id: pricing
owner: steward # no agent writes prices
role: principal
path: domains/pricing/pricing.md
unmatched: ask the principal # never invent an owner
How the flows are defined: protocols/information-routing.md
Five flows. Each one says where information comes from, where it goes, what it carries, how it travels, and the gate it passes. The gate vocabulary is fixed - log (write, and leave a receipt) or human-approval (a person says yes first) - so an agent can read it as data, not prose: the protocol ends in a machine-readable block. The orchestrator carries all five and owns none.
| Flow | From → to | Carries | Gate | Never |
| decisions down | people → every agent | the routing map, the limits, the price list, the operators | human-approval a PR, approved by a named person | an agent editing the canon; an agent quoting it from memory |
| facts up | the desks → their own files → the orchestrator's ledger → a person in the morning brief | pipeline state, client health, leads, notes | log | a second agent writing a desk's file; a number typed by hand |
| lessons through the brain | the desks → Cornelius → back as judgment | post-mortems and outcomes up; advice with its sources and labels down | human-approval a person graduates a note | the brain commanding a desk; its inference reported as the agency's view |
| requests across | the orchestrator → the one owner the map names | one request, as a one-line playbook call | log the execution id is the receipt | the orchestrator doing the work; two owners; a re-send on silence |
| escalations | any agent → the person the operators file names | one decision, the options, the cost of waiting, a deadline | human-approval | an ask with no named person; no expiry; the same ask twice |
How a gate is written: domains/approvals/approvals.yaml
Who may decide alone, up to which limit, and who decides above it. Roles, never people: who fills a seat is a Trinity assignment, restated in ORGANISATION.md. The orchestrator reads this before it raises an approval, so every ask names a role and an expiry.
- action: discount on a Pilot or a Build
decides_alone: sales-rep # a role in roles/, never a person
limit: 10% of the list price, as an invoice credit, never a rate cut
above_limit: principal
expires_after_hours: 72
- action: a new price, or a change to pricing.md
decides_alone: null
above_limit: principal # by PR to this repo; the orchestrator only prepares it
Set one up for your agency
Make the repo
Use this template on Abilityai/keymaker-canon. Public is simplest: agents clone it with no token.
Fill the map and the seats
domains.yaml (one owner per kind of work - two is one too many), roles/ (one file per seat), ORGANISATION.md (who fills each seat), approvals.yaml (real limits), pricing.md. Run the linter. Leave the protocols alone until you have a reason to change a gate.
Give the agents the canon
Each agent that reads it carries a tracked .trinity/setup.sh that clones the repo into canon/ on every container start. The orchestrator template has one; copy it. Nothing is read from a copy inside an agent's own repo.
Change it by pull request
A person edits and opens a PR; the role approvals.yaml names approves and merges; a line in domains/decisions/ says why. An agent that wants a change writes a proposal and raises an approval to that role. It never commits.
The rule under all of itThe canon holds what was decided. The brain holds what was learned. The orchestrator's ledger holds what is in flight. Three stores, three owners, and an agent reads the first two fresh every time instead of remembering them.