pi-pair
Pair decision audit for pi coding agent: fresh-spawn pair auditor, real-artifact gating, delivery gate, decision chain capture (English README + 中文文档)
Package details
Install pi-pair from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-pair- Package
pi-pair- Version
1.0.77- Published
- Aug 15, 2026
- Downloads
- 6,385/mo · 23/wk
- Author
- nuctori
- License
- MIT
- Types
- extension, skill, prompt
- Size
- 506.4 KB
- Dependencies
- 0 dependencies · 2 peers
Pi manifest JSON
{
"extensions": [
"./extensions"
],
"skills": [
"./skills"
],
"prompts": [
"./prompts"
],
"subagents": {
"agents": [
"./agents"
]
},
"image": "https://raw.githubusercontent.com/Nuctori/pi-pair/master/assets/pi-pair.png"
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-pair
Pair decision audit for pi coding agent · 结对决策审计插件
A fresh-spawn "pair auditor" (举灯人 / holder of the lamp) for every pi session. It captures decisions into a decision chain, cross-audits each round's artifacts against it, and delivers any blocker immediately for fixing — the user sees the fixed result, not the audit process. Delivery rounds gate on the audit signature; normal rounds run async without blocking.

Why
A single agent's thinking and output have limited precision — and two failure modes in particular:
- Intention-execution instability: the agent drifts from what you actually asked, or silently reinterprets the goal.
- Reasoning instability: it fabricates numbers, over-engineers, or confidently ships wrong logic.
A second agent ("pair") cleans up after it. But an independently-invoked audit has its own cost — time and tokens. pi-pair is built around one question:
Under tight time/cost control, can a pair auditor measurably raise output precision?
Core premise: the main agent is not reliable. Decisions aren't recorded by its initiative (the auditor extracts them from the conversation log), and audit judgement doesn't trust its self-description (it trusts the conversation record and repository facts).
Design philosophy
pi-pair makes deliberate trade-offs. Read these before deciding whether to adopt it:
- The main agent is not reliable — build around that, not against it. Decisions are extracted by the auditor (never by the main agent's initiative), facts are verified against the repository (never trusted from self-description), and audit judgement trusts the conversation record and repo state — not the main agent's summary of what it did.
- Adversarial, not polite. Artifacts are guilty until proven innocent: the auditor actively tries to break each dimension. A review that finds nothing to attack is a weak review, not a good one.
- Simplicity is a feature, not a shortcut. One audit layer, fresh-spawn runs, no resident process, no negotiation windows — each mechanism that survives earns its keep, each that fails is deleted rather than patched. The cost is fewer knobs; the payoff is a system you can reason about.
- Value is observable, process is hidden. The user sees the fixed result — blockers delivered and repaired — not the audit machinery (counts, timeouts, negotiations). Audit findings are injected user-visible; process noise never is.
- Audit only what is real. The auditor spawns only when real work exists: git artifacts (uncommitted changes or new commits) always spawn; conversation alone spawns only when this round used
decision_add(an objective decision signal). Pure-chat rounds never spawn — no background task, no completion notification noise (the zero-noise promise upgraded from zero-injection to zero-spawn). Plan decisions made withoutdecision_addare not lost: the convlog cursor stays put, so the next artifact round's auditor extracts them along with its own window. Auditing empty rounds would be theater, and theater teaches the auditor to rubber-stamp. - Gate at delivery, not every round. Normal rounds run async — the auditor works in the background and you're never blocked. The gate tightens only when it matters: this round has a git HEAD change (an objective commit signal). The gate itself is non-blocking — background polling (2s interval, 300s cap) with a user-message escape hatch.
- Interim results over final ceremony. The auditor writes findings continuously (
auditFindings), so being killed mid-audit still delivers value. A finished signature is a formality, not the point. - Stop when done. After signing, the auditor stops — no scope creep, no "just one more check". Open questions go to the next round, where the next agent has full context.
What this means for you: pi-pair raises output precision by (a) catching drift and fabricated reasoning before they ship, and (b) making the fixes cheap by surfacing them immediately. What it does not do: it does not guarantee correctness (same-model blind spots exist), chat-only rounds get a quick-exit verdict instead of an audit, and its value is proportional to how much real code/decision work your sessions produce.
Quick start
pi install npm:pi-pair
That's it. Start working normally — pi-pair hooks in automatically:
- Each round with real artifacts is audited (goal derivation → adversarial 5-dimension attack → signature): async in normal rounds (no blocking); delivery rounds gate on the signature via non-blocking background polling (2s interval, 300s cap; a new user message releases the wait early, the verdict is still delivered). Blockers are delivered immediately for fixing, re-audited until clean.
- Your decisions are captured into
.pi/decision-auditor/chain.md(append-only, auto-numbered) — extracted from the conversation log, not from your initiative. - On a git HEAD change this round (an objective commit signal, no keyword matching), 1 fresh reviewer does a full-dimension deep cross-check (correctness / goal-alignment / security-robustness).
Requires pi-subagents (spawns the auditor). See Installation.
Table of contents
- Why
- Design philosophy
- Quick start
- How it works
- Capabilities
- Installation
- Components
- Audit protocol
- Tools
- Full flow (decisions → proof → gaps)
- Proof chain & generalization discovery
- Environment
- Decision chain format
- Design notes
- Known limitations
- Roadmap
- License
How it works
each agent_end (when real work exists)
└─ real work? git artifacts (uncommitted changes / new commits) → always spawn;
conversation alone → spawn only when this round called decision_add (pure chat: never spawn — zero noise)
└─ normal rounds: async — agent_end does NOT block
· fresh spawn auditor (context:"fork" — inherits this session's context)
· one task = capture decisions into chain + audit artifacts + sign
· interim results written to state.json as auditFindings — killed mid-audit still delivers value
· plan decisions without decision_add are picked up by the next artifact round's auditor (cursor stays put)
└─ delivery rounds (this round has a git HEAD change — objective commit signal): spawn,
then poll signature in background (2s interval, 300s cap) — agent_end does NOT block
· adversarial 5-dimension attack on artifacts (guilty until proven innocent)
· independently verify Context facts vs repository
· continuous delivery: any blocker found → immediately notify main agent (fix → re-audit until clean)
· passed → end ✓
· 3× still blocked → passed-with-warning release (end is end)
· timeout → release with warning + findings injected next round (no negotiate blackhole)
· new user message → gate wait released (verdict still delivered via followUp)
L2 — delivery review (same git HEAD change signal)
└─ same trigger as the L1 gate: this round has a git HEAD change (no commit, no spawn — no empty review)
└─ 1 fresh reviewer, full-dimension deep review (correctness / goal-alignment / security-robustness)
Fresh-spawn pairing: every audit spawns a fresh auditor run (context:"fork" — it inherits this session's conversation context, so it understands what "this session" is doing without a persistent run). The run ends when the audit ends — no resident process, no lifecycle bookkeeping, no residue. Normal rounds are async (no blocking, findings injected without user-visible noise); delivery rounds gate on the signature via non-blocking background polling (2s interval, 300s cap; a new user message releases the wait early, the verdict is still delivered). Any blocker found at any stage is delivered to the main agent immediately for fixing, re-audited until clean — the user sees the fixed result, not the audit process. Findings are value points: blockers / interim auditFindings are injected user-visible (display:true); only internal hints stay hidden.
Layered cost control: L1 (the single audit) runs per round with real artifacts; L2 runs once per delivery, gated on real deliverables. A high-signal process log (decision-intent summaries, ≤200 chars each, roll-trimmed) lets the auditor check artifacts against your reasoning trajectory instead of reverse-engineering it — CI bench confirms zero measurable time cost for this communication channel.
Capabilities
| Capability | Description |
|---|---|
| Artifacts must be cross-audited | agent_end audits real artifacts; blocked artifacts trigger immediate delivery to the main agent (fix → re-audit), release-with-warning after 3× |
| Single-layer pairing | one audit per round — capture decisions into chain + audit artifacts + sign, in a single fresh-spawn run (context:"fork" inherits session context) |
| Not dependent on main agent | decisions extracted from convlog, facts verified from repo, by an independent agent |
| Decision chain | default .pi/decision-auditor/chain.md (private, no git pollution); PI_PAIR_CHAIN_PUBLIC=1 → docs/decisions/chain.md (team-visible) |
| Fresh-spawn lifecycle | audit run ends when the audit ends — no resident process, no residue after session shutdown; pure-chat rounds never spawn (zero noise — no background task, no completion notification) |
| Adversarial, calibrated | 7-dimension attack (5 elegance + mechanism integrity + runtime-mode behavior), calibrated on real defects the same-model auditor missed |
| Cost control | real-artifact gating (no empty audits) + once-per-delivery L2 + process-log intent channel; CI bench regression guard on wall time |
| Cost control | real-artifact gating (no empty audits) + once-per-delivery L2 + process-log intent channel; CI bench regression guard on wall time |
| Proof chain | every real audit appends a report to audit-log.md (same dir policy as chain); proof gaps (unreviewed decisions / holes / unclosed blockers / unaudited artifacts) queryable via pair_gaps |
| Generalization discovery (pair's multi-head attention) | divergent-verification path findings sink into the report's ### 泛化发现 section; end-of-audit review flags recurrence / frequently-unadopted paths; main agent greps before starting work |
| cwd adaptive | finds the real project root from any start dir (Cargo.toml/package.json/.git etc) |
Installation
pi install npm:pi-pair # npm dist
pi install ./pi-pair # local dev
pi install git:github.com/Nuctori/pi-pair # git source
Requires: pi-subagents (spawns / resumes the auditor).
Local-path note: pi-subagents usually auto-discovers agents in local-path package roots. If
agents/decision-auditor.mdisn't found, copy it manually:mkdir -p ~/.pi/agent/agents && cp agents/decision-auditor.md ~/.pi/agent/agents/
Components
| Component | Path | Role |
|---|---|---|
| Extension | extensions/decision-chain.ts |
hooks (session_start / agent_end / message_end) + tools (decision_add decision_list decision_signoff) + /pair-audit command |
| Storage | lib/chain-store.ts |
decision chain read/write (append-only, auto-numbering, supersede) + audit state (.pi/decision-auditor/state.json) + convlog + process log + project-root resolution |
| Auditor | agents/decision-auditor.md |
pairing audit protocol: goal derivation, capture, adversarial cross-audit, signoff |
| Discipline | skills/decision-chain/SKILL.md |
writer-side rules: when to record decisions, audit phases, signoff semantics |
Audit protocol
Each round the auditor:
- Derive goal: read the conversation log (
convlog.md), derive the task goal from user prompts — main agent's self-description is untrusted, user's words win - Read the process log (
process.md): the main agent's intent trajectory (decision-signal summaries) — verify artifacts against it instead of reverse-engineering intent - Audit: adversarial attack in 7 dimensions — atomicity / correctness / consistency / cohesion / completeness + mechanism integrity (trigger chains have live call sites) + runtime behavior vs claim (blocking/async claims hold across print/TUI/RPC, or mode differences are flagged)
- Sign: artifacts pass →
signature=passed; findings →signature=blockedwith actionable blockers (the main agent fixes them immediately)
Lifecycle rules: every audit is a fresh-spawn run (context:"fork" inheriting this session's context). Normal rounds run async after agent_end (the agent does not block); delivery rounds (a git HEAD change this round — an objective signal, no keyword matching for "done") gate on the signature via non-blocking background polling (2s interval, 300s cap — on timeout, release with warning and inject findings next round; no negotiate blackhole; a new user message releases the wait early, the verdict is still delivered). The auditor may contact_supervisor for clarification during its run (60s cap — otherwise decide from evidence). Interim findings are written continuously to auditFindings; the run stops immediately after signing (完成即停).
Tools
| Tool | Role |
|---|---|
decision_add |
main agent proactively records a key decision (auto-numbered D-00X, append-only, supersede) — optional; auditor also auto-captures |
decision_list |
read the decision chain |
decision_signoff |
sign after audit passes (use the tool, avoid hand-writing state.json) |
decision_signoff |
sign after audit passes (use the tool, avoid hand-writing state.json) |
pair_gaps |
query proof gaps (deterministic reconciliation: unreviewed decisions / interrupted holes / unclosed blockers / unaudited artifacts) and generalization gaps (recent N findings + frequent-path stats; semantic matching left to the caller) — shared by auditor and main session, read-only, no spawn |
/pair-audit |
manual full/targeted/--diff audit |
Full flow (decisions → proof → gaps)
User decision chain (user_decision_add, the requirement root — your decisions/corrections,
injected across sessions, propagated to subagents)
│ adopted as
▼
Agent decision chain (chain.md, append-only D-NNN: Context/Decision/Rationale/Alternatives/Supersedes)
│ captured by the auditor (independently from convlog, not from main-agent self-report)
│ + adversarial multi-dimensional audit
▼
Proof chain (audit-log.md, AUDIT-<epoch> entries: Verdict/Head/Window/Blockers/RunId/Date —
report before signature; the extension appends `interrupted` on gate timeout; Head = git artifact baseline)
▼
Proof gaps (mechanical reconciliation) Generalization findings (divergent-verification
unreviewed decisions / interrupted holes path findings sink into `### 泛化发现`:
unclosed blockers / unaudited artifacts scene | path | source)
│ pair_gaps query │ review (last 10, semantic match)
▼ ▼
fix-loop closure (blockers → fix → re-audit) Generalization gaps = accountable objects
│ after sink: recurrence / frequently-unadopted (≥2×)
│ — mechanically decidable
│ │ reuse (main agent greps before work)
│ │ → adopt → back-reference
└────────────────┬────────────────────────┘
▼
new chain entry (D-NNN+1) → next proof round
The core unification: generalization problems become proof problems. A generalization gap is semantic by nature ("the main agent never considered path P for this scene" — not mechanically decidable); but once it sinks into a generalization-finding entry (scene | path | source), it becomes an accountable object — whether the path was adopted (any chain reference), whether it recurred (artifact evidence), whether it is frequent (≥2× count) are all mechanically decidable. Sinking is the mechanism that converts semantic gaps into proof gaps: you cannot prove "the main agent never thought of it", but you can prove "the path was given, adopted or not, hit or not".
Proof chain & generalization discovery
- Audit report log (
audit-log.md, same dir policy as chain: default.pi/decision-auditor/,docs/decisions/withPI_PAIR_CHAIN_PUBLIC=1): every real audit appends anAUDIT-<epoch>entry (Verdict/Head/Window/Blockers/RunId/Date + report body) — report before signature (survives being killed); the extension appends aninterruptedentry on delivery-gate timeout (no holes in the proof chain) - Proof-gap self-check: the auditor reconciles at signoff — unreviewed decisions (chain entries newer than the latest audit) / interrupted holes / unclosed blockers;
pair_gapsqueries them anytime - Generalization discovery (pair's multi-head attention): path findings the main agent never considered (better alternatives / cross-domain patterns / edge-case generalizations) sink into the report's
### 泛化发现section (one line: scene | path | source); end-of-audit review of the last 10 findings — recurrence escalates to blocker, paths unadopted ≥2× get a distillation hint; the main agent greps before making trade-offs (SKILL discipline)
Environment
| Var | Default | Description |
|---|---|---|
PI_PAIR_CHAIN_PUBLIC=1 |
off | write chain to docs/decisions/chain.md (team-visible); default is .pi/decision-auditor/chain.md (private) |
PI_PAIR_PROCESS_LOG=0 |
on | disable intent-signal process log (CI bench baseline) |
PI_PAIR_PROJECT_ROOT |
— | explicit single authoritative project root (cross-drive / complex setups); default auto-detects upward from cwd |
PI_PAIR_LANG=en |
zh | TUI audit status language: en for English, default Chinese (matches existing UI copy) |
PI_PAIR_AUDITOR_MODEL |
— | model override for auditor runs (e.g. deepseek-v4-pro / glm-5.2). Avoids provider stream interrupts that mark complete audits as "failed" (v1.0.44); unset = inherit the main session model |
Decision chain format
## D-001: 采用 Redis 做读缓存 [Accepted]
- Context: QPS 峰值 2k;PG 读路径 60ms ← verifiable facts (with numbers/source)
- Decision: 引入 Redis 缓存读路径
- Rationale: 缓存命中 <5ms;写路径失效策略 ← reasoning derived from Context
- Alternatives: Memcached(否决:功能少) ← rejected options + reason
- Confidence: high ← calibration: don't say high without data
- Supersedes: D-00X ← revising an old decision = new entry declares it
Design notes
- Main agent unreliable: decisions recorded by the auditor, facts verified by the auditor, judgement independent of main-agent self-description
- Fresh-spawn + context-forked: every audit spawns a fresh auditor run (
context:"fork") — inherits this session's context, no resident process, no lifecycle bookkeeping - Append-only + tamper-proof: old decisions never edited; revision = supersede
- Context is fact, Rationale is reasoning: the auditor checks "does the reasoning derive from the facts", catching fabricated numbers and over-engineering
- End is end: the audit gate exits deterministically — pass, fix-loop (max 3×), or release-with-warning. No deadlock, no out-of-window wake-ups
- Generalization = multi-head attention, no second model. The industry reflex is "a stronger model reviews the small model"; pi-pair inverts it: the auditor's adversarial multi-dimensional attack (5 dimensions + empirical blind spots + divergent verification) IS multi-head attention — each dimension is an independent viewpoint hunting reasoning paths the main agent's single head missed (better alternatives / cross-domain patterns / edge-case generalizations). Multi-head comes from viewpoint diversity, not model scale: zero extra cost, and one model's multiple viewpoints beat cross-model comparison (no model-difference noise). Cross-round accumulation sinks into the generalization-primitive library (the
### 泛化发现section of audit-log) — the generalization boundary is set by the accumulated library at constant cost; the semi-parametric analog of a Generalization-Gap-Tree (GGT) scheme, with every primitive empirically sourced from this project. - Information before frequency: strengthen communication density (process log), not audit frequency — zero measurable cost, same trigger points
Known limitations
pi -p(print mode):agent_endaudit does not block — pi drops the extension handler at the spawn await; the auditor completes in the background and still signs, but the gate's blocking semantics are fully effective only in interactive mode (TUI / RPC).- Same-model auditor: the auditor uses the main agent's model by default — the adversarial stance mitigates groupthink, but shared blind spots (both miss the same thing) are still possible. Cross-model comparison is rejected by design: pair's multi-dimensional attention (divergent verification / cross-domain transfer) IS the multi-head; blind spots are compensated by cross-round accumulation into the generalization-discovery log.
- CI E2E uses a free no-key model (opencode CLI); audit verdicts are model-dependent by nature — the CI asserts mechanisms (capture / signature / lock), not verdict quality.
- Multi-instance same-cwd: the conversation log is keyed by cwd and shared by any pi instance running there. Since v1.0.14 every log line carries a per-instance
<!--run:<id>-->tag and auditors only extract decisions from the tagged lines of the spawning session; untagged legacy lines count as context only. When another instance's real conversation is detected, automatic audits are skipped with a warning instead of silently mis-attributing decisions. SetPI_PAIR_PROJECT_ROOTto a single authoritative project root (or run from different cwds) to keep instances apart.
Roadmap
- Model override (
PI_PAIR_AUDITOR_MODEL) — configurable auditor model (avoids stream interrupts; cross-model comparison is rejected: pair's own multi-dimensional attention IS the "multi-head", no second model) - Generalization-path distillation — frequently-unadopted paths auto-harden into audit dimensions (empirical calibration mechanism)
- Benefit measurement — audit records defect categories caught; recall/false-positive stats make "precision gain" quantitative
- L1 tiering — lightweight fast audit for routine rounds, deep audit for high-risk rounds
License
MIT © Nuctori