Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,16 @@ document, or run staged critique -> defend -> tighten passes.
bash ./co-evolve-bouncer.sh --vanilla "What is the strongest version of this argument?"
bash ./co-evolve-bouncer.sh --vanilla --bounce-only docs/plan.md
bash ./co-evolve-bouncer.sh --vanilla --chain "Should we ship this migration?"
bash ./co-evolve-bouncer.sh --vanilla --adversarial --bounce-only docs/plan.md
bash ./co-evolve-bouncer.sh --vanilla --adversarial --agents claude,claude "Same-model adversarial review"
```

`--adversarial` swaps the reviewer's 1-line role for a structured falsification
persona (vendored from the compound-engineering adversarial-document-reviewer;
templates/co-evolve/role-reviewer-adversarial.md). Cross-AI by default; with
`--agents claude,claude` it is an internal same-model adversarial review. Pair
with `--chain` or `--bounces 3` on dense documents (marker-flooding risk).

### Agent Bouncer (`agent-bouncer/`)

Legacy runner (still used by tests/experiments) that bounces any markdown
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,17 @@ existing document, or run staged critique -> defend -> tighten passes.
```bash
bash ./co-evolve-bouncer.sh --vanilla "What is the strongest version of this argument?"
bash ./co-evolve-bouncer.sh --vanilla --chain "Should we ship this migration?"
bash ./co-evolve-bouncer.sh --vanilla --adversarial --bounce-only docs/plan.md
bash ./co-evolve-bouncer.sh --vanilla --adversarial --agents claude,claude "Same-model adversarial review"
```

`--adversarial` swaps the reviewer's 1-line role for a structured falsification
persona (premises, assumptions, decisions, complexity, alternatives). It rides
the normal cross-AI bounce, or runs single-vendor with `--agents claude,claude`
when you want an internal same-model review. An aggressive persona can leave
markers open at the default 2 passes; pair it with `--chain` or `--bounces 3`
on dense documents.

### [Agent Bouncer](agent-bouncer/)

A legacy runner (still used by tests/experiments) that bounces any markdown
Expand Down
53 changes: 50 additions & 3 deletions co-evolve-bouncer.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ EXOCORTEX_QUERY=""
CONTEXT_FILE=""
AUDIENCE=""
LENS=""
# Adversarial reviewer persona (falsification method, vendored from the
# compound-engineering adversarial-document-reviewer). Default off so runs
# without the flag are byte-identical to the pre-persona bouncer.
ADVERSARIAL=false
CHAIN=false
MAX_BOUNCES=2
AGENT_A="claude"
Expand Down Expand Up @@ -67,7 +71,9 @@ PROTOCOL_TEMPLATE="$SCRIPT_DIR/agent-bouncer/templates/bounce-protocol.md"

# Validate templates exist
for _tmpl in "$TEMPLATE_DIR/role-reviewer-light.md" "$TEMPLATE_DIR/role-composer-light.md" \
"$TEMPLATE_DIR/role-reviewer-adversarial.md" \
"$TEMPLATE_DIR/chain-critique.md" "$TEMPLATE_DIR/chain-defend.md" \
"$TEMPLATE_DIR/chain-critique-adversarial.md" \
"$TEMPLATE_DIR/chain-tighten.md" "$TEMPLATE_DIR/adjudicate.md" \
"$PROTOCOL_TEMPLATE"; do
[[ -f "$_tmpl" ]] || die "Missing template: $_tmpl"
Expand All @@ -89,6 +95,10 @@ Options:
--context FILE Include a file as background context (not bounced; one file, concatenate if needed)
--audience WHO Prime agents for a specific reader
--lens NAME Use a named adversarial lens (replaces auto-shaped roles)
--adversarial Structured adversarial reviewer persona (falsification
method: premises, assumptions, decisions, complexity,
alternatives). Composes with --lens (lens becomes the
focus) and --chain (swaps the critique stage).
--chain Use staged passes: critique -> defend -> tighten
--bounces N Max bounce passes (default: 2, ignored with --chain)
--agents A,B Agent pair (default: claude,codex)
Expand Down Expand Up @@ -143,6 +153,7 @@ while [[ $# -gt 0 ]]; do
--context) CONTEXT_FILE="$2"; shift 2 ;;
--audience) AUDIENCE="$2"; shift 2 ;;
--lens) LENS="$2"; shift 2 ;;
--adversarial) ADVERSARIAL=true; shift ;;
--chain) CHAIN=true; shift ;;
--bounces)
MAX_BOUNCES="$2"
Expand Down Expand Up @@ -460,7 +471,16 @@ fi
# improve the composed draft, so that draft is the comparison baseline.
BASELINE_FILE="original-input.md"
[[ "$RUN_MODE" == "compose" ]] && BASELINE_FILE="compose-output.md"
init_bounce_state "$STATE_FILE" "co-evolve-bouncer.sh" "$RUN_MODE" "$TASK" "$INPUT_TYPE" "$BASELINE_FILE" "working.md"
# Reviewer persona is orthogonal to RUN_MODE (the scorer's baseline logic keys
# off mode, so persona must never become a mode value). Precedence mirrors
# build_reviewer_preamble: adversarial > lens > light.
REVIEWER_PERSONA="light"
if [[ "$ADVERSARIAL" == "true" ]]; then
REVIEWER_PERSONA="adversarial"
elif [[ -n "$LENS" ]]; then
REVIEWER_PERSONA="lens"
fi
init_bounce_state "$STATE_FILE" "co-evolve-bouncer.sh" "$RUN_MODE" "$TASK" "$INPUT_TYPE" "$BASELINE_FILE" "working.md" "$REVIEWER_PERSONA"

# Any fatal exit (die, set -e, auth abort) marks the run aborted so the
# scorer never issues a quality verdict for a half-finished run.
Expand Down Expand Up @@ -548,7 +568,22 @@ fi

# --- Role Preamble Generation ---
build_reviewer_preamble() {
if [[ -n "$LENS" ]]; then
# --adversarial wins over --lens: adversarial is the METHOD, lens the FOCUS,
# so a lens given alongside it composes as a focus line instead of replacing
# the persona. Adversarial-off paths below are byte-identical to pre-persona.
if [[ "$ADVERSARIAL" == "true" ]]; then
local preamble
preamble=$(cat "$TEMPLATE_DIR/role-reviewer-adversarial.md")
if [[ -n "$LENS" ]]; then
preamble="${preamble}
Focus your adversarial review through this lens: ${LENS}."
fi
if [[ "$SKIP_INTERVIEW" != "true" && -n "$AUDIENCE" && "$AUDIENCE" != "general" && "$AUDIENCE" != "auto" ]]; then
preamble="${preamble}
Evaluate this as if you are a ${AUDIENCE} reading it. What would they find unconvincing, unclear, or missing?"
fi
echo "$preamble"
elif [[ -n "$LENS" ]]; then
echo "You are the ${LENS} reviewing this work. Be adversarial from that perspective. Every critique must include a concrete alternative."
elif [[ "$SKIP_INTERVIEW" == "true" ]]; then
cat "$TEMPLATE_DIR/role-reviewer-light.md"
Expand Down Expand Up @@ -780,7 +815,15 @@ run_bounce_phase() {
current_agent="$AGENT_A"
if [[ "$CHAIN" == "true" ]]; then
case "$pass" in
1) role_preamble=$(cat "$TEMPLATE_DIR/chain-critique.md") ;;
1)
# --adversarial swaps only the critique stage; defend/tighten keep
# their templates (the persona is a critique method, not a chain).
if [[ "$ADVERSARIAL" == "true" ]]; then
role_preamble=$(cat "$TEMPLATE_DIR/chain-critique-adversarial.md")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the lens focus in chain adversarial mode

When users combine --adversarial --chain --lens <name>, the chain critique prompt is built directly from chain-critique-adversarial.md, so the lens-specific focus line added by build_reviewer_preamble is skipped. That makes the documented composition silently ignore the requested lens in the high-stakes chain mode, e.g. --lens security auditor produces a generic falsification prompt instead of a security-focused review.

Useful? React with 👍 / 👎.

else
role_preamble=$(cat "$TEMPLATE_DIR/chain-critique.md")
fi
;;
3) role_preamble=$(cat "$TEMPLATE_DIR/chain-tighten.md") ;;
esac
role="critique"
Expand Down Expand Up @@ -1099,6 +1142,10 @@ log " Input: $INPUT_TYPE"
log " Task: $(echo "$TASK" | head -c 80)"
log " Compose: $AGENT_A"
log " Bounce: $AGENT_A / $AGENT_B"
log " Persona: $REVIEWER_PERSONA (reviewer)"
if [[ "$AGENT_A" == "$AGENT_B" ]]; then
log " NOTE: same-model bounce ($AGENT_A vs $AGENT_B) — no cross-vendor disagreement; persona and per-role seats are the only independence between passes."
fi
# v1.5 Phase 1 (A-4b): resolved per-role seats. Reviewer runs on AGENT_A (odd
# passes / critique+tighten); composer runs on AGENT_B (even passes / defend).
# The compose PHASE also runs the composer role, but on AGENT_A — its resolved
Expand Down
9 changes: 8 additions & 1 deletion evals/BOUNCE-RUNNER-CONTRACT.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ a pass artifact missing.
"input_type": "file | string | pipe",
"baseline_file": "original-input.md",
"final_file": "working.md",
"reviewer_persona": "light | adversarial | lens",
"status": "running | complete | aborted",
"convergence_status": "converged | adjudicated | stuck | null",
"started_at": "2026-06-10T22:00:00Z",
Expand Down Expand Up @@ -103,6 +104,12 @@ Field rules:
fail a gate on it. Only an explicit `stuck` blocks.
Only `co-evolve-bouncer.sh` writes this field today; `agent-bouncer.sh`
leaves it `null`.
- `reviewer_persona` — which reviewer persona shaped the critique passes:
`light` (default 1-line role), `adversarial` (falsification persona, the
`--adversarial` flag), or `lens` (`--lens` free-text override). Additive to
`1.1`: absent means `light` (pre-persona states, agent-bouncer). Consumers
MUST NOT fail on its absence and MUST NOT branch scoring on it — persona is
orthogonal to `mode` and to the baseline rules above.
- `passes[].contested` / `clarify` — marker counts of the **clean** output,
counted by `lib/co-evolution.sh::count_markers` (code-fence-aware). The
scorer reuses the same function; counts must match.
Expand All @@ -111,7 +118,7 @@ Field rules:

## Writer helpers (lib/co-evolution.sh)

- `init_bounce_state <state_file> <runner> <mode> <task> <input_type> <baseline_file> <final_file>`
- `init_bounce_state <state_file> <runner> <mode> <task> <input_type> <baseline_file> <final_file> [reviewer_persona]` — the optional 8th arg defaults to `light`
- `append_bounce_pass <state_file> <pass> <role> <agent> <raw_rel> <clean_rel> <contested> <clarify> <word_count>`
- `set_bounce_convergence_status <state_file> <converged|adjudicated|stuck>` — set the convergence outcome (co-evolve only; call before `finalize_bounce_state`).
- `finalize_bounce_state <state_file> <status>`
Expand Down
6 changes: 6 additions & 0 deletions lib/co-evolution.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1369,6 +1369,10 @@ init_bounce_state() {
local input_type="${5:-}"
local baseline_file="${6:?baseline file required}"
local final_file="${7:?final file required}"
# Optional: which reviewer persona shaped the critique passes
# (light|adversarial|lens). Additive to bounce-state/1.1 — callers that
# omit it (agent-bouncer) default to "light", the pre-persona behavior.
local reviewer_persona="${8:-light}"

if ! command -v jq >/dev/null 2>&1; then
log "WARNING: jq unavailable — bounce state.json will not be written (scorer falls back to artifact parsing)"
Expand All @@ -1382,6 +1386,7 @@ init_bounce_state() {
--arg input_type "$input_type" \
--arg baseline "$baseline_file" \
--arg final "$final_file" \
--arg persona "$reviewer_persona" \
--arg now "$(bounce_state_now_utc)" \
'{
schema: "bounce-state/1.1",
Expand All @@ -1391,6 +1396,7 @@ init_bounce_state() {
input_type: $input_type,
baseline_file: $baseline,
final_file: $final,
reviewer_persona: $persona,
status: "running",
convergence_status: null,
started_at: $now,
Expand Down
19 changes: 18 additions & 1 deletion skills/co-evolution/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ description: >
using [CONTESTED]/[CLARIFY] markers until it converges. Triggers on
"co-evolution", "co-evolve", "co evolve", "bounce", "bounce document",
"agent bouncer", "refine with another agent", "cross-AI refinement",
"stress test this", and "have two AIs review this".
"stress test this", "have two AIs review this", "adversarial review",
and "red team this".
allowed-tools: Bash, Read, Write, Glob, AskUserQuestion
---

Expand Down Expand Up @@ -77,13 +78,29 @@ repo=$(resolve_co_evolution_repo) || exit 1
bash -lc 'cd "$1" && bash ./co-evolve-bouncer.sh --vanilla --chain "$2"' bash "$repo" "argument or decision to stress test"
```

Run an adversarial review (structured falsification persona — premises,
assumptions, decisions, complexity, alternatives). Cross-AI by default; add
`--agents claude,claude` for an internal same-model review when the user wants
no Codex involvement:

```bash
repo=$(resolve_co_evolution_repo) || exit 1
bash -lc 'cd "$1" && bash ./co-evolve-bouncer.sh --vanilla --adversarial --bounce-only "$2"' bash "$repo" "path/to/document.md"
bash -lc 'cd "$1" && bash ./co-evolve-bouncer.sh --vanilla --adversarial --agents claude,claude --bounce-only "$2"' bash "$repo" "path/to/document.md"
```

On dense documents pair `--adversarial` with `--chain` or `--bounces 3` — an
aggressive critique pass can leave markers open at the default 2 passes.

## Routing

| User intent | Command |
|---|---|
| General question, idea, strategy, or draft | `bash ./co-evolve-bouncer.sh --vanilla "input"` |
| Existing markdown file needs refinement | `bash ./co-evolve-bouncer.sh --vanilla --bounce-only <file>` |
| High-stakes argument or decision needs adversarial passes | `bash ./co-evolve-bouncer.sh --vanilla --chain "input"` |
| Adversarial review of a document (cross-AI bounce) | `bash ./co-evolve-bouncer.sh --vanilla --adversarial --bounce-only <file>` |
| Internal adversarial review, same model, no Codex | `bash ./co-evolve-bouncer.sh --vanilla --adversarial --agents claude,claude --bounce-only <file>` |
| Real repo change with code execution | `/dev-review` or `dev-review/codex/dev-review.sh` |

## Output
Expand Down
2 changes: 2 additions & 0 deletions templates/co-evolve/chain-critique-adversarial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Your job this pass: CRITIQUE by falsification. Do not fix anything — only identify problems, marking each with [CONTESTED] or [CLARIFY]. Attack on five fronts: (1) premises — is the stated problem the real problem, and would meeting every success criterion actually solve it; (2) unstated assumptions — environment, user behavior, scale, ordering; state what breaks if each is wrong; (3) decisions — for each major choice, construct the conditions under which it becomes the wrong choice, weighing reversal cost against evidence quality; (4) complexity — apply the subtraction test: anything whose removal costs nothing gets challenged; (5) alternatives — for every "we chose X", ask why not Y, including the do-nothing baseline. Every critique must include a concrete alternative. Suppress hunches you could not defend; mark at most the 10 most material findings.

30 changes: 30 additions & 0 deletions templates/co-evolve/role-reviewer-adversarial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!-- Adapted from the compound-engineering adversarial-document-reviewer persona;
vendored here because pipeline scripts must not depend on plugins at runtime. -->
Your job: try to falsify this document, not polish it. Where an ordinary reviewer asks whether it is clear and consistent, you ask whether it is *right* — whether the premises hold, the assumptions are warranted, and the decisions would survive contact with reality. Construct counterarguments, not checklists. Every critique must include a concrete alternative.

## Depth calibration

Estimate the document's size and stakes before reviewing, then pick a depth:

- **Quick** (under ~1000 words, no risk signals): run assumption surfacing and decision stress-testing only. Mark at most 3 findings — the most material ones.
- **Standard** (medium size or moderate complexity): add premise challenging and simplification pressure. Mark findings in proportion to the document's decision density, not its word count.
- **Deep** (over ~3000 words, more than 10 requirements, or a high-stakes domain — authentication, payments, data migration, compliance, external APIs, personal data, cryptography): run all five techniques including alternative blindness, and trace assumption chains across sections.

At any depth, mark at most the 10 most material findings per pass. A flooded document converges on nothing.

## Techniques

1. **Premise challenging** — Is the stated problem the real problem? Would meeting every stated success criterion actually solve it, or could all criteria pass while the problem remains? Is the framing artificially narrowing the solution space?
2. **Assumption surfacing** — Find claims that depend on conditions never stated or verified: environment (a service or capability works a certain way), user behavior, scale (what happens at 10x or 0.1x), and ordering/timeline. For each, state the assumed condition and what breaks if it is wrong.
3. **Decision stress-testing** — For each major decision, construct the conditions under which it becomes the wrong choice. What evidence would prove it wrong, and did anyone look? Weigh reversal cost against evidence quality; give the most scrutiny to load-bearing decisions that other decisions depend on.
4. **Simplification pressure** — Apply the subtraction test: for each component or requirement, what happens if it is removed? Challenge abstractions with a single consumer and plans that build the final version before validating the approach.
5. **Alternative blindness** — For every "we chose X", ask why not Y — including existing solutions (build vs. use) and the do-nothing baseline. If no alternative is ever mentioned, the choice may be path-dependent rather than deliberate.

## Confidence discipline

Only mark what you can defend. A strong finding quotes the document's own text, constructs a concrete failure scenario or counterargument, and traces the consequence. If confirming a suspicion would need information not in the document, say so in the marker. Suppress hunches you would not bet on — treat these thresholds as directional guidance, not a scoring exercise.

## Output

Express every finding as a [CONTESTED] or [CLARIFY] marker per the protocol below — inline in the document, never as JSON or a separate findings list.

Loading
Loading