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:

Draft → Ready → In Progress → Review → Done

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:

## State Mapping
 
| Board State | Macrostate  |
| ------------ | ----------- |
| Refined      | Ready       |
  • 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 Refined column to Ready, do that and skip the ## State Mapping entry 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 Refined column plus a separate Approved signoff column). Add both rows under ## State Mapping: the n-m schema allows several board states pointing at one macrostate, just never the reverse:

    | Board State | Macrostate  |
    | ------------ | ----------- |
    | Refined      | Ready       |
    | Approved     | Ready       |

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 the context-map-template.md in the KB (.pair/knowledge/guidelines/collaboration/templates/).
  • .pair/working/: the operational area (checkpoints, reports, PR analyses). It is excluded from every pair-cli registry, 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, merge and the card filter. Defaults keep a human in the loop (until: pr, gates always).
  • Legacy ## Eligibility and ## Auto-Advance: still honoured. They are translated to filter: and merge: at read time; you may rewrite them as ## Autonomy but nothing breaks if you do not.
  • ## Cycle Hooks: shell commands at stage boundaries (pre-<stage>, post-<stage>, on-halt).
  • ## Blocking Severities and max-dispatches: the severity floor (default Minor) and a ceiling on handoffs per run.

pair.config.json keys (optional)

  • workflowProfiles: engine, model and effort per stage (Configuration).
  • skipRegistries: registries install and update leave alone, for example agents to keep your own AGENTS.md and CLAUDE.md. update --skip-registries writes 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:

TreeRegistryWhat 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:

⚠️ Mirror: removed .pair/knowledge/how-to/04-how-to-define-subdomains.md (not in the source; customize via .pair/adoption/)

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.

You are migrating this project's `.pair/` structure to pair's canonical-states
release (v0.4 → v0.5). Work only inside `.pair/adoption/`. Do not edit
`.pair/knowledge/`, any skill file, or application code. Perform each step
only if not already done, and report what you skipped.

1. Open `.pair/adoption/tech/way-of-working.md`. Determine whether your PM
   board's state names already match the canonical set (Draft, Ready,
   In Progress, Review, Done):
   - If they match (or you have no board yet), do nothing - canonical names
     are the default and no `## State Mapping` section is needed.
   - If they differ, add a `## State Mapping` section with a
     `Board State | Macrostate` table listing each of your board's state
     names next to the canonical macrostate it maps to. Multiple board
     states may map to the same macrostate (first-listed wins on write);
     states outside the mapping are allowed and left unmapped.
   Skip this step entirely if a `## State Mapping` section already exists.

2. Search your own `.pair/adoption/` files (way-of-working.md, any custom
   guidelines you authored) for literal references to `/pair-process-map-subdomains`,
   `/pair-process-map-contexts`, or the path `.skills/process/map-subdomains`
   or `.skills/process/map-contexts`.
   - If found, update them to `/pair-capability-map-subdomains`,
     `/pair-capability-map-contexts`, and `.skills/capability/map-*`
     respectively.
   - If none found, do nothing - this is the common case, since the rename
     is picked up automatically on `pair-cli update`.

3. (Optional - classification tags) pair now scores a risk matrix on every
   story and PR automatically; no file is required. If you want chromatic
   risk tags (`risk:green|yellow|red`) applied to your cards/PRs right away,
   create `.pair/adoption/tech/risk-matrix.md` with a `## Tag Projection`
   section marking `risk` as Active. If you'd rather not, skip this - the
   `/classify` skill proposes the same declaration the first time it runs, and
   until then the matrix is written without tags. Skip if
   `tech/risk-matrix.md` already exists.

4. (Working area) Make sure `.pair/working/` is ignored by version control, before
   anything is written into it: if `.gitignore` has no entry covering
   `.pair/working`, append `.pair/working`; if it does, skip. Never register it
   as an asset target.

5. (Mirror cleanup) From v0.5, `pair-cli update` DELETES files under
   `.pair/knowledge/` and `.github/agents/` that the Knowledge Base no longer
   ships - including files this project added there itself. Do the snapshot
   BEFORE the next update runs.
   a. If `.pair/working/pre-v0.5-mirror-snapshot/REPORT.md` already exists, this
      step is complete - skip it entirely and report it as skipped.
   b. If `.pair/working/pre-v0.5-mirror-snapshot/` does not exist, create it and
      COPY into it (copy, never move) whichever of `.pair/knowledge/` and
      `.github/agents/` exist, preserving relative paths. If the directory
      already exists, leave its contents exactly as they are - it is the
      pre-update state, and re-copying after an update would overwrite the only
      evidence of what was removed.
   c. Ask the operator to run their usual `pair-cli update` and to tell you when
      it has finished. Do not install or invoke pair yourself if it is not
      already available, and do not delete anything under `.pair/knowledge/` or
      `.github/agents/` on your own.
   d. Once the update has run, list every file that exists in the snapshot and
      no longer exists in the live tree - those are the removals. For each,
      classify it with the operator: retired upstream (nothing to do), or
      authored by this project (re-home its content under `.pair/adoption/` for
      a project-specific standard, or into the organization's central KB
      repository for an org-wide one).
   e. Write `.pair/working/pre-v0.5-mirror-snapshot/REPORT.md`: one line per
      removed file - path, verdict, and where it was re-homed. This file is the
      marker that makes step 5 idempotent, so write it only when (d) is done.

6. (Context map) Do not create `.pair/adoption/product/context-map.md` unless the
   project wants it now: it is created inline by later brainstorm/refine
   sessions. If it exists, leave its existing rows as they are - but if the
   project keeps a list of canonical domain terms it expects the map to carry
   (pair's own list: Macrostato, State mapping, DoR/DoS, Risk Tier, Risk Matrix,
   DDR, Context Map, Checkpoint/Handoff, Macro-fase, Supervisore, Working area,
   Report consolidato, Marketplace, Quickstart, Process profile), compare it with
   the map and its co-located `subdomain/*.context.md` files and add a row for
   each missing term. Skip if none is missing.

7. (Version check) Ask the operator to run `pair-cli kb-info` and report its
   output. Do not install or invoke pair yourself if it is not already available.
   "Unknown installed version" is expected until the operator has run
   `pair-cli update` once; record whatever it reports and skip if already done.

9. (Optional, delivery policy) Ask the operator whether the project wants
   unattended delivery. If not, skip. If yes, and `tech/automation.md` has no
   `## Autonomy`, propose one from the KB template (`until`, `prepare`, `merge`),
   show it, and write it only on a yes. If it still has legacy `## Eligibility` or
   `## Auto-Advance`, leave them: they are translated at read time.

10. (Optional, cycle hooks and severities) Only if the operator asks for hooks or
    a blocking floor, add `## Cycle Hooks` or `## Blocking Severities` to
    `tech/automation.md`. Skip if the section exists or nothing was asked.

11. (Optional, `pair.config.json`) Leave `workflowProfiles`, `skipRegistries` and
    `engine` as they are. If the project has its own `AGENTS.md` or `CLAUDE.md`
    and wants to keep it, tell the operator to run
    `pair-cli update --skip-registries agents`; never edit the file yourself.

12. (Optional, other adoption) If `tech/way-of-working.md` lacks a
    `## Process Profile`, a `code-host`, or a review identity, ask whether the
    project needs one; skip when none is wanted or the entry exists. If the board
    has a state with no macrostate (a gate, Removed, Not planned), leave it
    unmapped in `## State Mapping`; do not invent a mapping.

13. (Optional, package-local adoption and templates) Skip unless the project is a
    monorepo that wants per-package rules or custom templates; then add the router
    or the override file the operator names, and skip any that exists.

14. Summarize what you created or changed versus what was already in place, and
   confirm with `git status` (or equivalent) that only files under
   `.pair/adoption/`, `.pair/working/` and `.gitignore` were touched.

Verify

  • .pair/adoption/tech/way-of-working.md either has a ## State Mapping section matching your board, or your board already uses canonical names (Draft/Ready/In Progress/Review/Done)
  • If your board has a legacy Refined column, you either mapped it to Ready (kept the name) or renamed the column to Ready (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.md has a ## Tag Projection section, or you've chosen to let /classify propose 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 its REPORT.md accounts for every file the update removed
  • Each ⚠️ Mirror: removed … line in the update output matches a line in REPORT.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.md exists only if you chose to create it
  • pair-cli kb-info reports clean (no drift), or its drift/unknown output was acted on
  • If you opted into unattended delivery, tech/automation.md has an ## Autonomy section and node .claude/skills/pair-workflow-cycle/scripts/autonomy-policy.mjs resolve prints the effective gates; legacy ## Eligibility/## Auto-Advance left as they were are fine
  • Any ## Cycle Hooks or ## Blocking Severities you added load without a HALT (cycle-hooks.mjs load, blocking-severities.mjs read)
  • pair.config.json keeps its workflowProfiles, skipRegistries and engine entries untouched, and an own AGENTS.md/CLAUDE.md you 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.