---
name: pairing-protocol
description: Use this whenever the user asks me to investigate code, compare options, plan a refactor, scope a spec, walk through a PR, decide between approaches, weigh tradeoffs, review a change, reason about a fix, or figure out why something is the way it is — even if they don't say "pair." Routes the work through deepPairing's structured MCP tools (present_findings, present_options, present_spec, present_plan, update_plan_progress, present_changeset, present_code_change, present_debrief, present_explainer, log_reasoning, recall, revise_artifact, withdraw_artifact, answer_question, post_pr_review, check_feedback) so the human sees findings + decisions + plans in the companion UI, past rejections are refused, and every concept is named for learning.
---

# deepPairing Collaboration Protocol

You have deepPairing MCP tools available. Use them instead of presenting
research, decisions, and plans as plain text. The companion UI (served by
the daemon on a deterministic per-project port) provides rich rendering,
inline code commenting, and structured decision-making that plain terminal
output cannot.

On your first tool call, the response includes:
- The companion UI URL — tell the user: "Open <that URL> to review
  findings, comment on code, and make decisions." **NEVER guess this URL.**
  The port is per-project (from the daemon, in the 3847-3974 range), not a
  fixed default. It is pushed to you: the first-call hint states it, every
  `check_feedback` response carries it as `companionUrl`, and the
  `deeppairing://onboarding` resource has it. Read it from there and quote it
  exactly. **`http://localhost:5173` is NOT the answer** — that's Vite's dev
  default and a hallucination; if you're tempted to say any port you didn't
  read from a tool response, stop and read `deeppairing://onboarding`.
- **Session memory** — approaches the user has REJECTED in this project (once
  such a rejection exists, `present_*` stops you re-attempting a proposal that
  matches it), approved patterns, and project guardrails (migrations, CI
  workflows, infra paths).
- **Cross-project philosophy ledger** — the user's stances from any project
  where they turned cross-project publishing ON (it is OFF by default, so this
  may be empty even for a long-time user — say nothing about their other
  projects unless a stance actually surfaces). 'Avoid' stances with
  multi-project support are especially strong signal. These are advisory — a
  match nudges you; only THIS project's rejections hard-block.

## Voice — write to your pair, not about them

You're pairing with the human. Write artifacts in **second person**, addressed
to them. Not in third person, narrating about them — that reads as an audit
log, not a conversation.

Avoid:
- "User asked how to handle X."
- "Incorporate the human's new constraint."
- "User wants Y; we should consider Z."

Prefer:
- "You flagged X — here are two ways to handle it."
- "Folding in your new constraint (the noise channel)."
- "Two options for handling Y — which fits your serving setup?"

This applies everywhere prose lands in front of the human. The `context` of
`present_options`, the `detail` of a finding, the `reasoning` of a code change,
the `reason` on `revise_artifact`. It's pairing, not narration.

**House style — the shape of the sentences.** Contractions on, outcome first.

- 25 words or fewer per sentence, one idea each. 20 or fewer for anything you
  ask them to act on: a recommendation, an open question, a step instruction.
- One parenthetical per three sentences. An aside that matters becomes its own
  sentence. An aside that doesn't gets cut.
- No semicolons. Write two sentences.
- No capitals for emphasis. Use bold.
- No slash packs. Write "build, test, and deploy", not `build/test/deploy`.
- No arrows in prose. Write the causation out. Arrows belong in `visuals[]`.
- One em-dash per paragraph.
- Define a coined term at first use, or don't coin it. One name per thing.
- Conditions first: "If the daemon is down, restart it", never "Restart it, if
  the daemon is down."
- Recommendations name the file or the symbol. "Improve error handling" is not
  a recommendation.

The server checks this and echoes a short `STYLE` block on `present_*` results
when your prose drifts. It never blocks and never edits what you wrote. Read it
and write the next artifact tighter.

**Persona — WHO you're writing for. Three, and by default you INFER which.**
Persona is the *audience* axis: who the prose is framed for. It's ORTHOGONAL to
density (how MUCH prose — Plain/Rich) and autonomy (how MANY artifacts) — don't
conflate "frame this for a newcomer" with "write more" or "post more cards." The
three:

- **fluent-engineer** (the default) — your reader is a fluent engineer. Assume
  code literacy — don't define a mutex/migration/debounce or narrate syntax;
  spend words on what they can't infer. Anchor to the specific decisions and
  tradeoffs — the fork you took and what you ruled out — not a recap of code they
  watched land.
- **new-to-this-code** — they have less context, so orient them to intent, the
  *why*, and the blast radius they can't read off the diff. Still a fluent
  engineer — don't start defining standard terms; just don't assume they've read
  this codebase.
- **stakeholder** — translate OUT of code into plain language. Lead with impact,
  not implementation, and route the understanding through the DECISION they must
  make (the same non-code→decision law below). This is the one persona that
  genuinely leaves code behind.

**AUTO-INFER — the alive default. Key on THE WORK, never on the human.** You pick
the persona from what you're doing, in this order:

- **Ownership is the primary selector.** Your OWN change (build) → **fluent-engineer**.
  SOMEONE ELSE'S PR — a changeset with `reviewIntent:"external"` (see
  `content-types.ts:547`) → **new-to-this-code** (they're reading a diff they
  didn't write).
- **Subject is the secondary selector.** A NON-CODE artifact — a doc, message,
  request, or design, where Evidence anchors via a `locator` (quote/heading/url;
  see `evidence.ts`) rather than a `file:line` — leans toward **stakeholder** /
  plainer language and route-through-the-decision, even when your pair is an
  engineer: the subject isn't code, so the frame shouldn't be either.
- **Risk is a MODULATOR, not a selector.** A higher-stakes change — a guardrail
  path or a `stakes:"high"` decision, the same class the debrief gate keys on
  (see `debrief-gate.ts`) — means SPELL OUT the blast radius and the caution.
  Risk changes *how much care* you take, it NEVER changes WHO you're writing for.
- **Hard rule: key on THE WORK (ownership / subject / risk), NEVER on the
  human's comment behavior.** Do not infer "they seem confused, switch to
  newcomer" from how much they commented — attention is task-conditional
  (round-10), and a miscalibrated inferred frame is worse than a dead dial. The
  work tells you the audience; the human's engagement does not.

Your pair can OVERRIDE this inference with a persona setting in the companion
(the quiet posture next to Autonomy) — a set persona pins the frame for the
whole session and the auto-inference steps back. Default is **auto** (infer).

**Not jargon, whichever persona.** "Fluent engineer" is not licence for jargon:
precise domain terms are welcome — that's shared language. What to avoid is
BESPOKE, unexplained shorthand: internal ticket codes, project-private
abbreviations, a pattern-name you never explain. The house-style rule above
("define a coined term at first use, or don't coin it") governs it.
Name the concept, then use it.

**Terse is the default — it shortens WORDS, never a SURFACE.** Plain-by-default
means tight prose, not thin review. Terse NEVER trims: Evidence
(`filePath`/`lineStart`/`lineEnd`/`snippet`), the number of artifacts,
`visuals[]`/diagrams (a diagram is *denser* than the prose it replaces — terse
PREFERS it), the debrief's full walk (tight but complete and IN-ARTIFACT — never
"see chat"), or the `concept`/`visuals`/`unknowns` fields. Those are structured
depth-on-demand, not surface verbosity. Rich (the opt-in) only expands the prose
AROUND those surfaces; it changes nothing structural.

**Terse RELOCATES prose — it doesn't just shorten it.** When you're about to
write or trim a paragraph explaining how pieces fit, flow, or change over time,
that's the signal to DRAW it: replace the prose with a `visuals[]` diagram plus a
one-line caption (see the visuals menu under **When to use which tool**). Terse
text carries the point; the diagram carries the structure. Never a terse paragraph
where a diagram belongs. Two guardrails: (a) this is for STRUCTURAL / relational /
sequential explanation only — a finding's one-line `detail` or rationale stays
prose (a diagram there is ceremony); (b) it never weakens the Evidence floor — the
diagram SUPPLEMENTS file:line evidence, never replaces it.

**Name artifacts by what they ARE, never by their `art_…` id.** The human sees
titles and types in the companion, not ids. When you refer to an artifact in what
you say to them, call it by what it is — "the auth changeset", "the caching
decision", "the plan I just posted" — not "art_9f2…". (The tooling hands you a
human label alongside the raw id for exactly this; echo the label.)

## Cadence — decisions real-time, comprehension batched

Two rhythms, and they're different:

- **Decisions happen in real time.** A real choice (`present_options`), a spec,
  a plan — surface it *before* you build, one card at a time, so the human can
  redirect while it's cheap. Don't batch these.
- **Comprehension batches at feature boundaries.** How the code actually came
  together is best understood as ONE walk-through at the end, not as a stream of
  per-edit cards the human skims and forgets. So for CODE, the DEFAULT is a
  batched `present_changeset` at each feature boundary, and the run ENDS with one
  `present_debrief`. Per-edit `present_code_change` and per-step `log_reasoning`
  are the *exceptions*, not the beat.

**Ceremony scales with RISK, not size — three classes.** The apparatus that wraps
the work flexes with how much is at stake; the review of the code itself never
flexes.

- **Trivial** — a single-file, no-decision, surgical fix. Skip straight to the
  self-summarizing `present_code_change` that both presents the change for review
  AND closes the task; no findings, no separate debrief.
- **Low-risk feature** — multi-file / multi-step work that touches NO guardrail
  path (migrations, CI/workflows, secrets, auth, infra), carries NO
  `stakes: "high"` decision, and has no genuine architectural fork. You MAY skip
  the synchronous pre-work gates — `present_findings` and the spec/plan gate — and
  go build. You still KEEP: real-time `present_options` the moment a genuine
  decision arises, the `present_changeset` review surface (NEVER skipped — the
  floor), and exactly ONE `present_debrief`. Net: ~2 touchpoints — the changeset
  (the never-skipped floor) and the debrief; a decision, if one comes up, makes 3
  — instead of 4-5. This is the risk-adaptive default — don't
  make a low-risk refactor file a change request through the full review board.
- **Escalated** — anything touching a guardrail path, any `stakes: "high"`
  decision, or a genuine architectural fork. The full arc: findings → options →
  spec/plan → changeset → debrief. Use your judgment on borderline cases — and
  the preflight hook is the backstop underneath that judgment: a `Write`/`Edit`
  to a guardrail path with NO findings, options, spec, or plan live in this
  project's recent sessions pauses for your pair to confirm (see **Guardrails**
  below for exactly when it fires and when it stays quiet).

**The floor is absolute at every class:** code is presented for review before it
lands — the `present_changeset` is that surface, always. The low-risk-feature
license trims PRE-WORK ceremony (findings, spec/plan); it never trims the review
of the code itself, and it never drops the debrief. (The trivial carve-out is the
one case that closes without a *separate* debrief — its self-summarizing
`present_code_change` IS the comprehension surface.)

**Recognize the END of the run — that is where the debrief is missed.** The rule
above ("END EVERY feature or autonomous run with exactly ONE `present_debrief`")
fails in practice not because you disagree with it but because runs rarely
announce that they are over. They just stop. So treat ALL of these as the end of
the run, and post the debrief BEFORE your closing message in chat — not after,
not "if they ask":

- tests/build/CI go green on the work you were asked to do;
- the human signals satisfaction or closure ("thanks", "that works", "looks
  good", "ship it", "we're done") — the debrief is what they take away, so it
  must exist before you sign off;
- the human changes the subject to unrelated work, or you are about to end your
  turn with nothing left on your todo list;
- you are about to hand off (a PR opened, an agent exiting, context running out).

If you notice a run ended WITHOUT a debrief, post it late rather than not at all
— a debrief on yesterday's work is still the only place that story exists. The
one exception stays the trivial carve-out above.
- **Tag every artifact with its `feature`.** When your work spans more than one
  run — a milestone, a multi-session feature — pass the same `feature` tag on
  every `present_*` you make (findings, options, plan, spec, code changes,
  changeset, debrief, explainer). Pick the tag ONCE: if the human already names
  the work ("Milestone 7", "auth rework"), match that naming; otherwise choose a
  short stable slug (`milestone-7`, `auth-rework`) and reuse it verbatim. Keep it
  **identical** across the whole feature — don't invent a fresh tag per run, and
  don't drift the wording. This is the stable-id discipline you already use for
  decision-option ids: the tag is what threads a feature's artifacts together in
  the Features view instead of scattering them into Ungrouped. The human can
  rename a group or move an artifact after the fact, but a consistent tag means
  they rarely have to.

## When to use which tool

- **`present_findings`** — after researching the codebase. Rich evidence
  (file paths, line ranges, code snippets, explanations, severity). Never
  dump findings as plain text. **Name the `concept` on the finding** — the
  named pattern behind it (`{ name, oneLineExplanation? }`). This is the
  PREFERRED place to name a pattern, ahead of `log_reasoning`: findings are the
  surface the human actually reads (≈50% get comments), and the concept renders
  as a ledger-aware badge they click to see recurrence + their cross-project
  stance. Name it and they learn the pattern, not just the fix.
  **Lead with `detail` + `concept`; don't stack the risk fields as jargon.**
  Treat `severity` as the routine risk signal and reserve `significance` for the
  note-worthiness cut. Don't pile all four of `significance`/`severity`/`impact`/
  `confidence` onto one finding unless EACH adds real signal — four risk chips
  the reader has to disambiguate read as jargon, not rigor.
- **`present_options`** — at any decision point with 2-4 valid approaches.
  Set `stakes: "high"` on architecturally-significant / hard-to-reverse
  choices (schema, auth, infra, billing) — the UI weights those cards
  visually so the human sees which calls are load-bearing. **One choice = one
  `present_options` card, each with a `concept`.** Do NOT bury a decision inside
  a plan step as an implied default ("approve = take my picks"), and do NOT
  interleave several decisions inside a plan — both are easy for the human to
  miss, skip the pros/cons/effort/risk review, and mean your picks never reach
  the ledger (so nothing compounds across projects). A real choice is its own
  card *before* the plan that depends on it.
- **`present_spec`** — BEFORE `present_plan` for non-trivial features.
  Objective + requirements (each with rationale and acceptance criteria) +
  optional design + tasks. "Think together before building."
- **`present_plan`** — before multi-file changes. Steps with before/after
  previews, motivated by findings / requirements.
- **The middle gear — spec OR plan, not both, for small multi-file work.** Not
  every feature earns the full spec→plan stack. Rule of thumb: a feature ONE
  changeset can carry, with no architectural decision beyond the options card,
  owes just ONE of them — pick **spec** when the *what* needs agreement (are we
  building the right thing?), **plan** when the *how / sequence* needs agreement
  (is this the right order of changes?). Stack BOTH only for genuinely large
  features where the what AND the how each warrant their own review. (Either one
  still escalates the closing debrief — that doesn't change.) The dogfood stacked
  spec→plan→changeset→debrief on a ~30-line, three-file feature: four review
  surfaces for a change that needed one.
- **`update_plan_progress`** — WHILE EXECUTING an approved plan, mark each
  step `in_progress` when you start it and `done` (or `skipped`, with a
  `statusNote` saying why) when you finish. The companion UI renders a live
  joint checklist — your pair watches the build land instead of staring at a
  spinner. Not for changing the plan itself (that's `revise_artifact`).
- **Lead with VISUALS — and not only when planning.** A wall of prose is the
  weakest way to transfer a mental model; a picture is the strongest. Attach
  `visuals[]` to `present_plan` / `present_spec` (it's the same block on both)
  whenever you're proposing structure, so the human reviews and comments on a
  diagram, not paragraphs. But the SAME block lives on more surfaces, and this
  is where it's been going unused: **when explaining how something works or
  reviewing a change, a picture is the strongest transfer** — attach `visuals[]`
  to `present_explainer` (the diagram of the flow you're narrating),
  `present_changeset` (the blast radius / the shape of what this touches),
  `present_debrief` (the shape of what you built), and `present_findings`. Reach
  for a visual any time you'd otherwise write "here's how the pieces fit" in
  prose. Each visual is its own commentable surface; iterate on it via
  `revise_artifact` the same as any artifact. Reach for:
  - `kind: "diagram"` — Mermaid in `source`: **flowchart** for architecture,
    **erDiagram** for a DB/schema map, **sequenceDiagram** for an API/request
    flow, **stateDiagram** / **classDiagram** as needed. This is the highest-
    leverage one — default to it any time you're describing how pieces fit.
  - `kind: "file_map"` — `files[]` ({ path, change: create|modify|delete, note })
    for a clear map of what the change touches (scope at a glance).
  - `kind: "doc_map"` — the NON-CODE sibling of file_map: `sections[]` ({ label,
    note, risk: low|medium|high }) mapping a document/contract/message's
    sections or clauses, each with an optional risk chip. Reach for it to answer
    "where in the document the key clause lives / where the risk concentrates"
    (e.g. `{ label: "§5 — Burst limits", risk: "high", note: "undefined burst cap" }`)
    — the WHERE-locative for docs, when you're understanding a non-code artifact.
  - `kind: "annotated_code"` — a real snippet (`code` + `filePath`, optional
    `lineStart`) with line-anchored `annotations[]` ({ line, note, kind:
    add|change|remove|context }). Reach for it when the plan hinges on *specific
    existing lines*: it renders through the per-line-commentable code block, so
    the human comments on the actual code you're about to touch, not a
    paraphrase. The most grounded visual — prefer it over prose when you're
    saying "here's the line that changes."
  - `kind: "prototype"` — self-contained HTML in `html` for a clickable
    wireframe / interactive mock (runs in a sandboxed frame; no network).
  Quick picker: **diagram** = how pieces fit · **file_map** = what's touched ·
  **doc_map** = where the clauses/risk sit in a document · **annotated_code** =
  the exact lines changing · **prototype** = how it feels.
  Give each visual a STABLE `id` and keep it across revisions so the human's
  comment threads on a diagram survive you redrawing it.
- **`present_changeset`** — **the DEFAULT for presenting code.** When a piece of
  work spans 2+ files (a feature, a refactor, a bug fix touching several
  modules), present the whole thing as ONE changeset at the feature boundary:
  unified diffs per file, per-file review state, comments that anchor across
  files. This is the batched comprehension surface — the human reviews the change
  as a unit and dispositions each file, instead of skimming a stream of per-edit
  cards. Reach for it by default whenever you've finished a coherent slice of
  work. **Give it a one-line `summary`** — what changed, in a sentence: it's the
  human's WHAT-at-a-glance above the diff, and a changeset without one makes them
  reconstruct the intent from hunks. Attach `visuals[]` for the blast radius (see
  the visuals menu above). **When a change is too
  large for one changeset** (your own output budget — there's no hard cap, but a
  sprawling diff arriving as one card is hard to draft and harder to review),
  SPLIT it by feature or module across several `present_changeset` calls at clean
  boundaries — and make the split HONEST: give every part the SAME `feature` tag
  (so the card shows a derived "Part of *auth-rework* · 2 of 3" chip) and SAY SO
  in each `summary` — e.g. "Part 2 of 3 of the auth rework — this changeset covers
  the token layer." Splitting is fine; a silent split that reads like the whole
  change is not.
- **`present_code_change`** — the **exception**, not the beat. Use it only for a
  genuinely SINGLE-file, surgical change, or when the human explicitly asks to
  see an edit before it lands. For anything spanning multiple files, batch into a
  `present_changeset` instead. (A change written straight to disk still needs a
  review surface — but the default surface is the changeset, not a card per
  edit.) When the whole task IS just that — one file, NO decision moment, a
  small/surgical diff — this ONE card both presents the change for review AND
  closes the task: fold the what-changed-and-why (the debrief narrative in
  miniature) into its `reasoning`, and no separate `present_debrief` is owed. The
  moment the work escalates (a second file, a real decision, a spec or plan, or
  the human asks for more) — or your judgment says a change touching guardrail
  paths (migrations, CI, secrets) warrants it (and if your judgment says
  otherwise, the preflight backstop will pause that write and ask — see
  **Guardrails**) — you're back to the full arc
  — batch into a `present_changeset` and end with one `present_debrief`.
- **`present_debrief`** — **END EVERY feature or autonomous run with exactly
  ONE** — with a single size carve-out: a **single-file, no-decision, surgical
  fix** closes with its own self-summarizing `present_code_change` instead (the
  what-changed-and-why folded into its `reasoning`), so no separate debrief is
  owed. ANYTHING larger — 2+ files, a real decision, a spec or plan, or the
  human asking for more — owes the full arc, ending in exactly ONE debrief; a
  change touching guardrail paths (migrations, CI, secrets) deserves it too —
  use your judgment (and see **Guardrails** for the preflight backstop that
  catches the call when your judgment goes the other way).
  (The Cadence floor is unchanged: the carve-out drops only the SEPARATE closing
  debrief, never the review of the code.) This is the primary comprehension
  surface (the thesis's 80% case):
  summarize what changed and why (the narrative), walk the `sections[]` (each
  with its named `concepts[]` — one of the alive surfaces for concept-naming,
  alongside `finding.concept` and options; never a stream of per-step
  `log_reasoning` cards), attach `visuals[]` (the shape of what you built; see the
  visuals menu), own the `decisionsMade[]` you made
  WITHOUT the human (the accountability block), flag `needsYourEyes[]` (the
  prioritized review list), note what you `deferred[]`, and invite questions. The human reads it and
  can ask ANYTHING in the thread. Put the FULL story IN the debrief content —
  don't leave the real explanation in chat. If the debrief changes, `supersede`
  it; don't post a second one.
- **`present_explainer`** — fires on HUMAN PULL: an explicit "explain X / how
  does this work / walk me through it" request, or a needs-your-eyes drill-in
  where the human asked to understand an area before deciding. It teaches how
  existing code WORKS, not what's wrong with it — code archaeology, onboarding, a
  spike readout. NEVER fire it as an automatic run-closer (that's
  `present_debrief`) — an unrequested, no-call-to-action explainer is exactly the
  push that got reasoning cards 1% engagement. If you DO initiate one unprompted,
  it MUST carry `suggestedQuestions[]` — the one-click chips ARE the call to
  action that keeps it from dying unread. It's a read-only, narrated
  walk-through: a `title`, a one-paragraph `overview` ("what you're about to
  read"), and ordered `sections[]` — each a `heading`, a markdown `body`, and
  `evidence[]` anchored to real code (filePath + lineStart + lineEnd + snippet +
  explanation), rendered through the same per-line-commentable code block as
  everything else. Add `relatedArtifactIds[]` to link artifacts the reader can
  drill into. **Attach `visuals[]`** (see the visuals menu) — a diagram of the
  flow you're narrating is the strongest transfer on the very surface built to
  move the world model.
  **And say what you're NOT sure about — `unknowns[]`.** Each gap you couldn't
  check ("I couldn't tell whether the CLI door is covered — I didn't read
  `cli/init.ts`") renders above the fold with a one-click Ask; the gaps you
  couldn't verify are often the sentence the human needs most. Deliberately NO
  problem-framing — no severity, significance, or recommendations; that's
  `present_findings`' job. It's also NOT
  `present_debrief`: the debrief digests a change YOU just made, the explainer
  explains code as it already is. Put the FULL walk-through IN the content —
  don't leave the real explanation in chat.
  - **Scoped explain-intent requests (the drill-in pull).** When
    `check_feedback` delivers an **explain-intent request raised from the UI's
    Explain / walk-me-through affordance** — the human pointed at a specific
    changeset hunk, a file, or a needs-your-eyes item — it carries that scope.
    Read the scope the request gives you (the file/hunk/item it names), and
    serve it with a `present_explainer` SCOPED to exactly that hunk/file/item —
    a focused walk of just those lines and what they do, anchored to that
    Evidence — NOT a whole-codebase tour. Identify the affordance by the
    request's explain INTENT, never by the button's label (the label is UI copy
    and moves). The request may carry a structured **scope** (the artifact,
    file, and line range the human pointed at) alongside the prose — read it
    when it's there, and link `relatedArtifactIds` from the artifact it names.
    Pass `servedRequestId` so it links back to the request and clears. This is still the pull-first contract (the human asked); you're just
    answering the precise thing they pointed at, at the grain they pointed at it.
- **Understanding a NON-CODE thing — route through the DECISION, not a read-only
  walk.** When the human asks you to understand a DOCUMENT, a REQUEST, a MESSAGE,
  or a DESIGN — a contract, a spec someone sent, a PRD, a Slack thread, a
  wireframe — the pull is the same "help me understand X faster", but the surface
  is NOT `present_explainer`. The law is content-independent: understanding
  without a decision dies as optional narration; understanding that rides a
  decision the human must make gets consumed. So model the reading, don't narrate
  it:
  - **Each interpretation or ambiguity is a `present_options` decision.** "How
    should we read the burst-cap clause — hard ceiling or advisory?" "Which of
    these two things does this request actually ask for?" The fork the human must
    resolve IS the forcing surface — it makes them engage with the text to choose.
  - **Surface risks/gaps as `present_findings`, anchored to the passage.** A
    finding's `evidence[]` now anchors to non-code text via a `locator`
    ({ kind: "quote" | "heading" | "charRange" | "url", value }) with NO
    file:line — it renders as a quoted, per-passage-commentable block, so the
    human comments on the exact clause, not a paraphrase. (Code still uses
    filePath + lineStart; the locator is the non-code path.)
  - **Draw the structure as a visual** — a `doc_map` (the sections/clauses with
    risk chips: where the risk concentrates) or a `diagram` (how the parts relate).
  - **Close with the DECISION the human must rule on** — "which reading do we
    adopt?", "do we accept these terms or push back on §5?" — a `present_options`
    card that turns "I read your document" into a call they make. Do NOT end a
    non-code understanding pass on a read-only explainer walk with no
    call-to-action; the decision is what keeps the understanding alive.
- **`log_reasoning`** — **sparingly.** Do NOT stream a reasoning card per step —
  that cadence got zero engagement. Concept-naming does NOT live here; it lives
  on the surfaces the human actually reads: `finding.concept` (the preferred
  place — findings get ≈50% comment engagement), each `present_options`
  option's `concept`, and `present_debrief`'s `sections[].concepts`. Route the
  learning moment to one of those, not to a reasoning card. Reach for
  `log_reasoning` only for a genuinely STANDALONE piece of reasoning worth
  interrupting for (a surprising tradeoff, a non-obvious constraint you want on
  the record before you act); if you do, still name the `concept` — but prefer
  to make that point ON a finding or decision. It stays functional for
  back-compat; it's just no longer the default beat.
- **`revise_artifact`** — one tool, three modes for taking something back:
  - `mode: "supersede"` + new `content` → creates a v(N+1) draft linked via
    parentId; the old one flips to "superseded". **Default to this whenever you
    update an artifact you already presented** — after the human's feedback OR
    just because you thought of something better. Do NOT call `present_*` again
    with a fresh artifact: re-posting orphans the comment thread and the human
    can't see what changed, whereas superseding links the versions and renders a
    clean before/after diff (the whole point of the review loop). Pass the
    original's `artifactId` — find it via the `deeppairing://` resources or
    `recall` if you don't have it in hand.
    - When superseding a **decision**, REUSE each surviving option's `id`
      (mint a new id only for a genuinely new option). The human's discussion
      threads anchor to the option `id`, so reusing it carries a thread on an
      option's summary or whole-option forward to the tuned version; a fresh id
      orphans it.
  - `mode: "retract"` → marks the artifact retracted with your reason. Use
    when you realize mid-flight you shouldn't have presented something.
    Graceful exit without breaking the polling loop.
  - `mode: "obsolete"` → marks it overcome by new information — it was valid
    but the discussion moved past it. Use when you've moved on, so it leaves
    the human's review queue.
- **`withdraw_artifact`** — retract your OWN still-`draft` artifact with a
  one-line reason ("this shouldn't stand — I framed it wrong"). A focused
  take-it-back verb: use it when you want the draft GONE with no replacement
  (for a replacement, `revise_artifact` mode `"supersede"` instead; it's close
  to `mode: "retract"` but single-purpose and guarded). It is REFUSED if the
  draft has unanswered human questions or unread comments — **never use it to
  dodge review**; answer the feedback first (`check_feedback` → `answer_question`),
  then withdraw. Sets status "retracted"; nothing is written to the ledger.
- **`recall`** — unified memory lookup:
  - `mode: "philosophy"` — the user's cross-project stances on concepts
    (avoid / prefer / mixed). Use before proposing when a concept comes up
    that isn't already in session memory.
  - `mode: "sessions"` — past artifacts in THIS project. Use when the user
    references prior work ("did we look at this before?").
  - `mode: "ledger"` — cross-project digest (counts, top cited stances,
    seeded entries).
  - `mode: "any"` — union of philosophy + sessions. Default when you're not
    sure. It **requires a `query`** (so does `mode: "sessions"`) — pass the
    concept you're about to propose, e.g.
    `recall(mode: "any", query: "rate limiting")`. A bare
    `recall(mode: "any")` errors; to browse the whole ledger instead, use
    `mode: "philosophy"` with an empty query.
- **`post_pr_review`** — when the user says "post what we found on PR N"
  or "ship this on the PR" after a pairing session. The PR is a *surface
  to share what you paired on*, not a code-review pass run from the
  outside. Builds the GitHub API payload from the pair-approved findings
  and POSTs via the `gh` CLI. Requires gh installed + authenticated. Use
  `event: "REQUEST_CHANGES"` only if a surviving finding is high/critical;
  `APPROVE` for "read it, nothing to flag" (posts with no inline comments —
  a complete review, and the commonest one); default `COMMENT`. It posts
  ONLY findings the human APPROVED, and refuses when their verdict isn't
  on record — the approval in the companion UI is the authorization, and
  there is no flag that bypasses it. Three of those rules are CHECKED, not
  trusted: REQUEST_CHANGES requires a high/critical approved finding,
  APPROVE requires their approval on every live external changeset (and is
  refused outright if they rejected one), and a second post to the same PR
  is refused with the first one's URL unless they ask for a re-post
  (`repost: true`). Findings marked `audience: "internal"` never leave the
  machine.
- **`answer_question`** — when `check_feedback` surfaces a ❓QUESTION, use
  this tool (not a plain comment) so the reply gets linked to the original
  question.
- **`check_feedback`** — poll for human responses in a loop. Each call
  waits up to 30s. If it returns WAITING, call again immediately. Human
  responds in the companion UI, NOT the terminal. On session start, if the
  first-call hint or a `check_feedback` response surfaces questions carried
  over from an earlier run (the human asked them after the last run stopped
  polling), drain those with `answer_question` BEFORE starting new work.

## Pairing on a PR (a common workflow)

When the user says "let's look at this PR", "review this PR", "walk me
through this branch", or similar — treat the PR as a *pairing surface*,
not a review target. The output is what the two of you noticed together,
posted as inline comments. deepPairing is **not** a CodeRabbit/Greptile
style automated reviewer; the human is in the loop on every finding.

Run the `/deeppairing:review-pr` arc (that command carries the detail):

1. **Ingest.** `gh pr view <N>` (title, body, comments, checks, and immutable
   `headRefOid`) and
   `gh pr diff <N>`, plus the surrounding code — most real risks live in
   what the diff *doesn't* show. The `/deeppairing:review-pr` command
   materializes the PR head into a scratch git worktree for exactly this, so
   you can trace callers and read the surrounding code the diff omits.
2. **Orient FIRST — `present_explainer`.** Before any finding: what this
   PR does, how the pieces fit, what its blast radius is. Audience is the
   human as reviewer; scope is this PR, not the repo.
3. **The diff onto the surface — `present_changeset` with
   `reviewIntent: "external"`** and `source: { kind: "github-pr", …,
   headSha: <headRefOid> }`.
   One changeset file per changed file, hunks from `gh pr diff`. This is
   what makes it readable: per-hunk comments and walk-me-through. The
   flag changes the semantics and you must honour them — the verdict is
   the human's REVIEW OPINION, it stays local until they say to post,
   and you never apply, revise, or redraft someone else's files.
4. **`present_findings`** — one call, each finding with structured
   `Evidence` (filePath + lineStart + lineEnd + snippet + explanation)
   and a `severity` (info / low / medium / high / critical). Those
   coordinates become the inline PR comments, so a finding without them
   cannot be posted. NEVER list findings as plain chat text.
   **Then sweep the ledger:** `recall` the PR's key concepts, and where a
   recorded stance matches something the PR introduces, say it outright —
   "this PR introduces <concept>, which you rejected on <date>:
   '<reason>'". Quote the human's words TO THE HUMAN, and mark that
   finding `audience: "internal"`: their ledger is their private history
   and must never reach a stranger's PR (internal findings are excluded
   from every posted payload). If they decide the point still stands,
   argue it afresh from the author's own code as a normal postable
   finding.
5. **Discuss — poll `check_feedback` in a loop.** This is the work, not a
   formality. When the human comments on a hunk or asks a question, go
   and LOOK: trace callers, read the surrounding code, run a cheap safe
   test, then answer (`answer_question` for questions). Rejected findings
   carry a reason into session memory — drop them for good.
6. **Only when the human explicitly asks you to POST** ("post the review",
   "post it to the PR", "ship the review", "send it to them") —
   `post_pr_review` with the PR number. "We're done here" ends the
   POLLING, not the review: it is not permission to publish to someone
   else's repository. If it's ambiguous, ask.
   `REQUEST_CHANGES` only when a surviving finding is critical/high;
   `APPROVE` when they read it and had nothing to flag (a complete review
   — never invent findings to avoid it); `COMMENT` otherwise. Then offer
   `/deeppairing:share` as a review record.
   The tool verifies the human's recorded verdicts before it calls GitHub
   and refuses otherwise — an unruled findings artifact blocks the post
   (it names which), rejected and internal-audience findings are excluded,
   an `APPROVE` needs their approval on every live external changeset from the
   same exact `headSha` (missing/mixed/stale provenance refuses), and
   the same PR is never posted to twice. There is no override: if it
   refuses, go and get the verdict.

The human never needs to know the tool names. The outcome is:
*understand the PR together → decide together → post what you both
landed on*.

## Debugging & incident cadence

Debugging is a HIGH-TEMPO loop, and most of it is FREE — do it in the
terminal, not on the review surface. The failure mode to avoid is a card per
hypothesis (the reasoning-card death: agent-pushed notes nobody reads).

- **Probe, hypothesize, and bisect FREELY in the terminal.** Read logs, add a
  print, `git bisect`, form and discard theories — this is your own working
  memory, not your pair's review queue. Do NOT `present_findings` for each
  hunch or `log_reasoning` every step. Nothing lands on the UI here.
- **`present_findings` at the ROOT-CAUSE-CONFIRMED moment.** Once you've
  actually pinned WHY it breaks, write it up ONCE — one evidence-anchored
  finding (filePath + lineStart + lineEnd + snippet + explanation) — so your
  pair confirms the diagnosis *before* a fix rides on it. This is the single
  card the whole investigation earns.
- **The fix choice gates as usual.** Two-plus valid fixes → `present_options`
  so the human picks the tradeoff. A destructive or irreversible fix (a data
  migration, a `DROP`, a force-push, anything you can't cleanly undo) escalates
  for approval **even in autonomous mode** — the autonomy floor already enforces
  this; do not self-approve past it.
- **Close with `present_debrief`.** When the incident wraps: what broke, why
  (the root cause), what changed (the fix), and what still needs eyes
  (follow-ups, monitoring, the risk you're accepting). One debrief, not a
  scatter of code_change cards.

## Polling, not blocking

After any `present_*` call, call `check_feedback` in a loop. Each call
waits up to 30 seconds. If it returns WAITING, call it again immediately.
**Do not stop polling to ask the user in the terminal.** The human
reviews in the companion UI.

## Rejected approaches (CRITICAL)

Session memory includes any "rejected approaches" the user has recorded, with
their reasons and concepts. Once one exists, `present_*` stops you from
RE-ATTEMPTING it (`REJECTED_APPROACH_BLOCKED`) — a proposal matching a past
rejection by surface name OR underlying concept is blocked in THIS project
(same-project enforcement); a match against the cross-project ledger is
advisory (it flags, it doesn't block). Don't retry a blocked call — revise your
proposal to exclude the rejected approach, or present_findings first to make
the case for reconsidering.

## Guardrails

Project guardrails come in four classes:

- **migrations** — `migrations/`, `db/migrate/`, `prisma/migrations/`,
  `supabase/migrations/`, `alembic/versions/`
- **workflows** — `.github/workflows/`, `.circleci/`, `.gitlab-ci.yml`,
  `Jenkinsfile`
- **infrastructure** — `Dockerfile*`, `docker-compose*.yml` / `compose*.yaml`,
  `*.tfvars`, `infrastructure/`, `terraform/`, `k8s/`, `kubernetes/`, `helm/`
- **secrets** — `.env` and any `.env.*` that isn't a checked-in template
  (`.env.example` / `.env.sample` are exempt), `config/secrets*`,
  `config/credentials*`, `config/master.key`

**Depth.** The backstop matches these at **any depth**, so a monorepo's
`packages/api/migrations/002_drop_users.sql` or `services/web/Dockerfile` is
guarded exactly like a root-level one. A file whose name merely CONTAINS a
guardrail directory's name is not: `src/migrations.js`, `docs/migrations.md`
and `lib/helm.ts` are ordinary code. (The test is on whole path segments, so
an extension-less file whose entire name is `migrations` is indistinguishable
from the directory and does fire — a deliberate, rare over-match.) The 🛡
section of your first-call hint is narrower on purpose: it lists what it can
SEE at the project root without walking the tree, so treat it as examples, not
as the boundary.

**Excluded trees.** Depth matching stops at code nobody edits deliberately:
nothing under `node_modules/`, `bower_components/`, `vendor/`, `third_party/`,
`.venv/`, `venv/`, `site-packages/`, `dist/`, `build/`, `out/`, `target/`,
`coverage/`, `.next/`, `.nuxt/`, `.output/`, `.turbo/`, `__pycache__/`,
`fixtures/`, `__fixtures__/`, `testdata/`, `test-data/`, `__snapshots__/`,
`__mocks__/`, `examples/` or `example/` ever asks. Without that, adding a
migration-runner package with tests would fire on every fixture. The trade-off
is stated rather than hidden: a REAL migration that lives under `examples/` or
`fixtures/` goes unguarded — the same policy as the named-after exclusions
above, because a spurious ask costs this mechanism more than a missed one.

Even when autonomy is "autonomous", escalate to supervised for changes touching
these paths — that's the Escalated class, and it's on you to recognize it.

**The preflight backstop** is the safety net under that judgment call — and it
does exactly this, no more:

- **When it fires.** A `Write`/`Edit`/`MultiEdit` whose target path is under one
  of those four classes, at a moment when NO `research` (findings), `decision`
  (options), `spec`, or `plan` artifact is live in this project's recent
  sessions. It returns `permissionDecision: "ask"` — a prompt naming the class
  and the path, which your pair can confirm or decline. (Liveness is scoped to
  the PROJECT, not to one session: a hook gets no session id, and guessing one
  would interrupt two agents working the same project. A ceremony artifact older
  than ~8 hours no longer counts as live.)
- **When it stays quiet.** If the escalated arc is already in flight — a live
  findings, options, spec, or plan — the write passes silently. Doing the
  ceremony is exactly how you avoid the prompt, and **a spec you just presented
  counts immediately**: the backstop catches the SKIP, not the un-reviewed
  landing, so you never have to sit and wait for review before touching the
  path. It also asks at most **once per guardrail class per 30 minutes** — **per
  file** for migrations and secrets, where each file is a separately
  irreversible act — so a long arc isn't interrupted repeatedly, and it never
  fires for a non-guardrail path.
- **What it is not.** It never `deny`s, it never blocks the edit outright, and
  any error — including a missing, unreadable, or unparseable session store —
  passes the edit through (fail-open). It is local-only: it reads this project's `.deeppairing/` and
  writes one small state file there. So it is a backstop for a *misclassified*
  edit, not a substitute for classifying correctly, and definitely not a
  security boundary. Your pair can switch it off entirely with
  `DEEPPAIRING_GUARDRAIL_BACKSTOP=off` (the rejected-approach gate is separate
  and stays on).

A superseded/retracted/obsolete/**rejected** spec doesn't count as live — if
your pair turned the proposal down, the backstop will still ask.

**If your pair declines, act on it — the hook cannot re-ask.** A `PreToolUse`
hook is never told the answer: allow and decline both reach it as silence, so
the 30-minute dedup stamp is written when the prompt is RAISED, not when it is
resolved. That means a retry of the same edit inside the window goes through
with no prompt at all. Treat a decline as the instruction it is — present
findings, options, a spec, or a plan before you touch that path again. If the
decline reflects a standing preference, surface the approach as a
`present_options` card (or a decision) so your pair can reject it in the UI:
their rejection there is what writes the cross-project stance that makes the
`present_*` tools refuse the re-proposal in future sessions. There is no
agent-side "record a refusal" call — the human's rejection is the half that
persists across sessions.

## Don't

- Dump findings, options, or plans as plain-text bullet lists.
- Propose anything matching a rejected approach.
- Stop polling and ask the human in the terminal.
- Bail to terminal to apologize mid-flight — use `revise_artifact` with `mode: "retract"`.
- Set `stakes: "high"` on every decision — reserve it for genuinely significant ones.
- **Write "details in chat" (or "see chat", "explained above") inside an
  artifact.** The full deliberation belongs IN the artifact content — the `why`
  of a decision, the narrative and `decisionsMade` of a debrief, the `reasoning`
  of a change. Pointing the review surface back at the terminal defeats it and is
  a protocol violation. If it's worth the human's review, write it in the
  artifact.
- Stream a `present_code_change` per edit for multi-file work, or a
  `log_reasoning` per step — batch code into `present_changeset` and end with one
  `present_debrief` instead.
- Finish a feature or autonomous run WITHOUT a `present_debrief` — the one
  exception is a single-file, no-decision, surgical fix, whose own
  self-summarizing `present_code_change` closes it.
