pair-agent-harness — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited pair-agent-harness (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
A coordination harness for two AI agents working in complementary roles on a shared markdown file. The two canonical roles are:
The roles swap per topic — when Claude opens the thread with findings + questions for Codex, Claude is the Implementor / Codex is the Reviewer. When Codex opens the thread asking for review of a Codex-generated patch, the roles flip. The harness doesn't pin roles; it pins the discipline: one agent appends at a time, each side reads the whole file before responding, the markdown thread is the single source of truth.
This decouples the two agents from each other's runtime: neither has to be online at the same time. The Implementor can land code changes between rounds; the Reviewer can take a day to think; the file persists across both sessions.
Fire on:
*-review-thread.md / *-dialogue-thread.md and says "respond" / "continue" / "monitor".Do NOT fire on:
Default location, in order:
<repo>/.dialogue/<topic>-review-thread.md. Create the .dialogue/ directory if missing; add it to .gitignore if the user prefers ephemeral threads, or commit it if the user wants the audit trail.project-management/, docs/design/, or similar design-docs folder already exists in the repo, prefer <that-folder>/<topic>-review-thread.md.~/.claude/review-threads/<topic>-review-thread.md.If the file does not exist and the user wants Claude to open the thread, write the seed template:
# <Topic> Review Thread
Purpose: <one-line problem statement / what's being reviewed>.
## Claude - Findings - <YYYY-MM-DD>
<Claude's opening take. Lead with the recommendation in 2-3 sentences (pyramid
principle). Then justify with the relevant code references, file:line citations,
and tradeoffs. End with 2-3 specific questions for the reviewer.>
## Peer Response
<Peer agent (Codex / another Claude / reviewer): please respond here. In particular:>
- <question 1>
- <question 2>
- <question 3>
## Claude Follow-Up
(Claude appends here after reading the peer's response.)If the file already exists and contains a peer-opened section (e.g. ## Codex (OpenAI) - Findings - <date>) with an empty ## Claude Response placeholder, do not rewrite the file — append Claude's response under that header.
Print the absolute file path back to the user once seeded so they can hand it to the peer agent.
Always read the whole file before drafting. Stale assumptions about earlier sections are the most common pair-thread bug.
Pick your role for this round:
Drafting rules (apply in either role):
## Claude * heading; the new one uses the next numbered slot:## Claude Response - <YYYY-MM-DD>## Claude Follow-Up - <YYYY-MM-DD>## Claude Follow-Up 2, ## Claude Follow-Up 3, …## Claude Final ACK - <YYYY-MM-DD> (only when nothing more to add and the peer has also closed).Append using Edit against the file's last line (or a stable trailing anchor). Never overwrite an existing peer section.
After writing the response, arm a file-mtime watcher so each peer append fires a notification. Reference pattern (works on macOS + Linux):
FILE=/abs/path/<topic>-review-thread.md
last=$(stat -f %m "$FILE" 2>/dev/null || stat -c %Y "$FILE")
echo "monitoring $FILE (last mtime=$last)"
while true; do
sleep 3
cur=$(stat -f %m "$FILE" 2>/dev/null || stat -c %Y "$FILE" 2>/dev/null || echo "$last")
if [ "$cur" != "$last" ]; then
echo "CHANGED at $(date -u +%H:%M:%SZ) mtime=$cur"
last=$cur
fi
doneRun this in a long-lived background task (Claude Code's Monitor tool, a tmux/screen session, or whatever the runtime offers). Save the task / process ID — you'll need it to stop the monitor at the end.
When a CHANGED event arrives:
Claude Code's Monitor tool fires notifications as real conversation messages — the runtime auto-wakes Claude on each file change without the user having to prompt. Codex's runtime does not work the same way: its background watcher's stdout only reaches Codex while a turn is open or when the user types something. If the peer agent is Codex (or another tool with the same constraint), set the user's expectation explicitly when handing off:
claude replied or check file to wake them after they post a final answer."This asymmetry is benign — both sides land replies eventually — but the user shouldn't be surprised when one side appears silent until they ping it.
When the thread converges on a code change — both sides agree on a specific edit, with file path + value or shape — implement it BEFORE the next response:
quality-gates subagent (delegate to it with the touched scope).CLAUDE.md, README.md, or CONTRIBUTING.md).pnpm lint && pnpm typecheck && pnpm test for TS/JS).| Item | Status |
|---|---|
| <change>: <before> → <after> | **Landed** in `<path>:<line>` |
| Quality gates | **All pass.** N tests pass. |
| <follow-up scope> | **Queued.** Not in this PR. |Never claim "landed" without running the gates. If gates fail, fix the underlying issue (no --no-verify, no rule loosening) before reporting.
Respect the active collaboration mode and user instructions. If mutation is forbidden — Plan Mode is active, an ExitPlanMode contract hasn't been approved, the user said "don't edit anything", or the sandbox is read-only — write the agreed plan/status into the thread instead of editing files. Append a Status row marking the change as Queued — blocked by <mode> rather than Landed. The thread is the record either way; the file edit is the optional output that depends on permission.
The thread is converged when EITHER:
## Claude Final ACK - <date> (one paragraph) and inform the user the thread is closed.Stop the monitor with the saved task / process ID. Do NOT leave a monitor running after the user signals close — that burns context on no-op touches.
If the peer keeps posting after your Final ACK with substantive disagreement, treat that as the loop reopening. Otherwise, the thread is closed.
YYYY-MM-DD (no timezone). Multiple same-day follow-ups use the number suffix, not a time..dialogue/cancel-event-review-thread.md (or wherever the repo's convention puts design threads).## Claude Follow-Up <N> - <date> with pyramid-shape response.<hash>, branch pushed, monitor stopped.Monitor fires on a touch with no new content. Editor save or formatter run produced the mtime bump. Read the file, confirm no new section, reply briefly that no action is needed. Don't append a new Claude section just because mtime changed.
Peer's section uses an unexpected header pattern. Stay flexible — match the header shape they use (e.g. ## Codex (OpenAI) - Findings - <date> vs ## Codex - Initial Take). Use your own consistent pattern for Claude headers.
Two agents diverge in opinion. Don't try to force a single answer. State the disagreement explicitly in your section, list the tradeoffs in a table, and ask the user to break the tie if both peers stay deadlocked after two rounds.
File has hundreds of lines and is hard to scan. Append a status table to your latest Claude section that summarizes where every thread item stands (Landed / Queued / Disputed / Resolved). This is what convergence looks like in long threads.
Quality gates fail after the agreed change. Treat the fail as a re-opener of the thread, not a private problem. Append a section explaining what broke, what the fix is, and whether the original consensus still holds.
A tangential bug surfaces inside the thread. Don't fold it into the current decision — spin a separate <other-topic>-review-thread.md so each thread converges on a single decision instead of dragging.
Roles are blurring (same agent reviewing + implementing in one round). That's normal at convergence — the Implementor finishes the change, runs gates, and ratifies their own status table. But if it's happening every round, the harness has degraded into a monologue; ask the user whether the peer is actually engaged.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.