v0.4 → v0.5: Canonical States + Domain Modeling
Migration prompt for pair's canonical backlog states, n-m state-mapping schema, the map-subdomains/map-contexts process-to-capability rename, the classification / risk-matrix capability, and mirror cleanup on pair-cli update.
This page covers every adoption and config change in the v0.4 → v0.5 jump that needs your action or offers an option: canonical states, the domain context map and .pair/working/, the domain-modeling rename, classification, mirror cleanup on pair-cli update, the delivery cycle's policy sections, and pair.config.json keys. Each change below says whether it is required or optional.
Structural background: Canonical states (#202) · map-subdomains/map-contexts reclassification (#246) · Versioning & migration epic (#214) · Migration note: legacy Refined boards (#243) · Classification & risk matrix (#233) · Mirror cleanup on the CLI path (#393)
Changed
Canonical backlog states
Skills used to read a literal board-state name (Refined, Todo) baked into their instructions. From this release, pair resolves backlog state through five canonical macrostates:
Your board can keep any naming. .pair/adoption/tech/way-of-working.md gains an optional ## State Mapping section: a Board State | Macrostate table, n-to-m (multiple board states may map to one macrostate; first-listed wins on write). Omit it and pair assumes your board already uses the canonical names.
Legacy Refined state → Ready
If your board already has a literal Refined column (as pair's own recommended GitHub Projects board does) you don't need to rename anything. Add one row mapping it to the canonical Ready macrostate:
-
Keep the name, add the map (above): the board keeps working with zero renames; this is the common path for an existing project.
-
Rename instead: if you'd rather rename the
Refinedcolumn toReady, do that and skip the## State Mappingentry entirely. An omitted mapping resolves by canonical name, so nothing else changes. -
Two Ready-like columns: some boards split "refined" across two columns (e.g. a
Refinedcolumn plus a separateApprovedsignoff column). Add both rows under## State Mapping: the n-m schema allows several board states pointing at one macrostate, just never the reverse:
Full schema and the worked n-m example (Example 2b): .pair/knowledge/guidelines/collaboration/project-management-tool/canonical-states.md in your installed Knowledge Base.
Domain context map and the working area
Two structures arrive that need no file from you but that the prompt confirms (and, if you keep a canonical-terms list, backfills, pair's own dogfood run found 9 of its 15 terms missing from the map and added them by hand, which is why step 6 compares your list against the map instead of saying "leave it as is"):
.pair/adoption/product/context-map.md: optional. Created inline the first time a brainstorm or refine session sharpens a domain term; absent is a valid steady state. Projects that want their ubiquitous language up front can create it from thecontext-map-template.mdin the KB (.pair/knowledge/guidelines/collaboration/templates/)..pair/working/: the operational area (checkpoints, reports, PR analyses). It is excluded from everypair-cliregistry, so install/update never write or delete it, and it should be ignored by version control. Skills create it on first use; you only need to make sure it is ignored.
Check the installed KB version
pair-cli kb-info (no package path) compares the KB version recorded by your last install/update with the current one and prints the migration-page pointer on drift. Run it after the migration: a project that has never recorded a version reports unknown until pair-cli update has run once (it writes the gitignored .pair/.kb-version.json); after that it reports Up to date.
Skill renames: map-subdomains, map-contexts (process → capability)
/map-subdomains and /map-contexts move from .skills/process/ to .skills/capability/. Installed command names change accordingly: /pair-process-map-subdomains → /pair-capability-map-subdomains, /pair-process-map-contexts → /pair-capability-map-contexts (unprefixed dataset names /map-subdomains//map-contexts are unchanged). This is a knowledge-base change, pair-cli update picks it up automatically, no .pair/adoption/ edit needed for the rename itself. The only thing worth checking is whether your own adoption docs (way-of-working.md, custom guidelines) reference the old prefixed command names or the old .skills/process/map-* paths literally.
Existing adoption/product/subdomain/*.md and adoption/tech/boundedcontext/*.md files created under the old process-skill flow remain valid as-is: no forced migration. A Volatility field (subdomains) or relationship-strength assessment (bounded contexts) is added lazily, the next time that entry falls inside a future scoped run, never backfilled in bulk.
Classification & risk matrix
pair now builds a classification matrix on every story and every PR: /refine-story composes /classify to score the story context, and /review re-scores from the diff (a review can raise a tier, never lower it). This is automatic and needs no setup, with no adoption file, classify applies the Knowledge Base defaults and writes the matrix only (no tags, nothing fails).
To turn the matrix into chromatic tags on your cards and PRs (risk:green|yellow|red), add an optional .pair/adoption/tech/risk-matrix.md with a ## Tag Projection section. You don't have to write it by hand: the first time /classify runs it proposes this declaration and writes it once you confirm. The same file optionally holds a service/domain criticality table and overrides (threshold tweaks, per-tier reviewer count / SLA). risk is the only tag family enabled by default; cost, security, business impact and coupling are computed too but projected as tags only if you add them.
Full model (dimensions, tiers, tag projection, and the tech/risk-matrix.md schema) in Quality Model.
Delivery policy sections (optional)
All in .pair/adoption/tech/automation.md; every one is optional and absent means the default (Adoption settings).
## Autonomy:until,prepare,mergeand the card filter. Defaults keep a human in the loop (until: pr, gatesalways).- Legacy
## Eligibilityand## Auto-Advance: still honoured. They are translated tofilter:andmerge:at read time; you may rewrite them as## Autonomybut nothing breaks if you do not. ## Cycle Hooks: shell commands at stage boundaries (pre-<stage>,post-<stage>,on-halt).## Blocking Severitiesandmax-dispatches: the severity floor (defaultMinor) and a ceiling on handoffs per run.
pair.config.json keys (optional)
workflowProfiles: engine, model and effort per stage (Configuration).skipRegistries: registriesinstallandupdateleave alone, for exampleagentsto keep your ownAGENTS.mdandCLAUDE.md.update --skip-registrieswrites it; removing the entry opts back in. See Quickstart.
Process Profile, code host, review identity (optional)
In tech/way-of-working.md: ## Process Profile (default, poc or custom, which steps the project runs), the code-host override under ## Git Workflow, and review identity (none, app, bot-user; default none).
State Mapping gains n-m, unmapped and Control states
## State Mapping is n-to-m (several board states to one macrostate). A board state you leave out is ignored, and a closure without completion (Not planned) is never Done. If your board has a state that is a gate rather than work, it stays unmapped. See Canonical states.
Package-local adoption and template overrides (optional)
A ## Package-Local Adoption router in a central tech/*.md points to per-package rules (Package-local adoption); .pair/adoption/tech/templates/<name>-template.md overrides a KB template whole (Customize templates).
pair-cli update now deletes what the Knowledge Base no longer ships
This is the only change in this jump that removes files. Read it before your next update.
Until v0.4, pair-cli update only ever wrote: it copied the Knowledge Base over your project and left everything else where it was. A file the KB had retired upstream stayed installed forever. pair's own repository carried two how-to guides for ~5 months after they were dropped from the dataset, still listed in .pair/llms.txt, so agents kept being pointed at guidance the KB no longer shipped.
From v0.5, the registries declared as mirrors clean up after themselves, at every depth of the tree:
| Tree | Registry | What update does now |
|---|---|---|
.pair/knowledge/** | knowledge (mirror) | copies the KB, then removes any installed file the dataset does not contain |
.github/agents/** | github (mirror) | same, for that subdirectory only |
Every removal is announced on stderr: a deletion you cannot see in the output is indistinguishable from data loss:
Nothing outside those two trees is touched. .pair/adoption/ is an add registry, your decisions there are never overwritten and never deleted. The rest of .github/ (your workflows, your issue templates), .pair/working/, and your application code are outside every mirror and are not candidates for removal.
If you have hand-edited files under .pair/knowledge/
Two cases, and only the second one is new:
- You edited a file that still exists upstream: unchanged from v0.4: the copy overwrites it and your edit is lost.
- You added a file there, or edited one that has since been retired upstream: it is now deleted, where in v0.4 it survived indefinitely. This is the case to handle before you update.
.pair/knowledge/ in a consuming project is installed output, not source: it belongs to the registry, and every update reasserts that. Project-specific standards belong in .pair/adoption/ (Customize the Knowledge Base for your team, Customize templates); organization-wide standards belong in the central KB repository you package from (Quickstart: Organization), where .pair/knowledge/ is authored source. Step 5 of the prompt below snapshots the mirror trees into .pair/working/ before you update, so nothing is lost while you re-home it.
Prompt
Copy-paste this into any AI coding agent (Claude Code, Cursor, Copilot, Codex, or similar) with write access to your project. It only touches files under .pair/adoption/ and .pair/working/ (plus one .gitignore line), never .pair/knowledge/, skill files, or application code. Safe to re-run.
Verify
-
.pair/adoption/tech/way-of-working.mdeither has a## State Mappingsection matching your board, or your board already uses canonical names (Draft/Ready/In Progress/Review/Done) - If your board has a legacy
Refinedcolumn, you either mapped it toReady(kept the name) or renamed the column toReady(and left it out of the mapping), not both, not neither - Your own
.pair/adoption/docs have no remaining literal references to/pair-process-map-subdomains,/pair-process-map-contexts, or.skills/process/map-*, updated to the-capability-/capability/equivalents if any were found - Classification needs no action to work (it runs on KB defaults); if you want risk tags,
.pair/adoption/tech/risk-matrix.mdhas a## Tag Projectionsection, or you've chosen to let/classifypropose it on its first run -
.pair/working/pre-v0.5-mirror-snapshot/holds the pre-update copy of.pair/knowledge/(and.github/agents/, if you have it), and itsREPORT.mdaccounts for every file the update removed - Each ⚠️
Mirror: removed …line in the update output matches a line inREPORT.md, one that doesn't means something you own was living inside a mirror tree - Nothing this project authored is left under
.pair/knowledge/, project standards live in.pair/adoption/, organization standards in your central KB repository -
.pair/working/is ignored by version control and was not added to any registry;context-map.mdexists only if you chose to create it -
pair-cli kb-inforeports clean (no drift), or its drift/unknown output was acted on - If you opted into unattended delivery,
tech/automation.mdhas an## Autonomysection andnode .claude/skills/pair-workflow-cycle/scripts/autonomy-policy.mjs resolveprints the effective gates; legacy## Eligibility/## Auto-Advanceleft as they were are fine - Any
## Cycle Hooksor## Blocking Severitiesyou added load without a HALT (cycle-hooks.mjs load,blocking-severities.mjs read) -
pair.config.jsonkeeps itsworkflowProfiles,skipRegistriesandengineentries untouched, and an ownAGENTS.md/CLAUDE.mdyou wanted to keep is still yours - Unmapped board states stay unmapped in
## State Mapping -
git status(or equivalent) shows changes only under.pair/adoption/,.pair/working/and.gitignore - Re-running the prompt makes no further changes: a second run reports each step as skipped
If you're several versions behind, run the earlier pages in the Migrations index first, then this one.
Related
- Migrations index: all published version jumps
- Writing Migration Pages: the pattern this page follows
- Canonical States & State Mapping: full concept explainer
- Quality Model: classification dimensions, tiers, tags, and the
tech/risk-matrix.mdadoption delta - KB Structure Reference: current
.pair/directory layout