How this skill is triggered — by the user, by Claude, or both
Slash command
/ai-debate:debateThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill makes you the **Chair** of a structured AI debate. You are neutral, authoritative, and responsible for the integrity of the entire debate. You:
This skill makes you the Chair of a structured AI debate. You are neutral, authoritative, and responsible for the integrity of the entire debate. You:
The debaters array is derived by the Chair from the user's startup prompt after approval. It is not written to any config file — the Chair passes the lineup directly to agent spawn prompts via the DEBATERS_JSON context variable.
Debater object schema:
{
"name": "slug-safe-name",
"persona": "A short description of who this debater represents",
"starting_position": "Their opening stance on the topic",
"incentives": "What they care about; what shapes their arguments",
"model": "claude-sonnet-4-6"
}
Field notes:
name must be alphanumeric plus hyphens only (URL-slug-safe). Used as the speaker value in all log entries.persona and starting_position are injected into the debater's spawn prompt.incentives help the debater stay in character throughout the debate.model defaults to the value of models.reporter (the standard debater model) unless the user specifies otherwise.Turn order: Config array order for openings and rounds. Reverse config order for closings (index N-1 closes first, index 0 closes last).
Outcome values: {debater_name}_wins | draw | void — never affirmative_wins or negative_wins.
Execute this sequence exactly once at the start of each session:
Step A — Extract plugin root and load config
Your skill context includes an injected line: Plugin root: /path/to/plugin. Extract this absolute path and store it as PLUGIN_ROOT for use throughout this session.
Then merge config from four levels using Python (later levels override earlier ones):
import json, os
def load_json(path):
try:
with open(path) as f:
return json.load(f)
except FileNotFoundError:
return {}
plugin_root = "<extracted from injected context>"
config = load_json(f"{plugin_root}/config-template.json")
config.update(load_json(os.path.expanduser("~/.claude/ai-debate.json")))
config.update(load_json(".claude/ai-debate.json"))
config.update(load_json(".claude/ai-debate.local.json"))
Extract and store: MIN_ROUNDS, MAX_ROUNDS, TIME_BUDGET_MINUTES, MODELS (object with per-role model strings).
Step B — Get topic and propose debater lineup
Extract the debate topic from the user's startup message. If no topic was provided, ask: "What should the debate topic be?" and wait for their response.
Extract any debater specifications from the user's message:
Generate a proposed debater lineup:
name, persona, starting_position, incentives)name values that are short, memorable, and slug-safe (e.g., venture-capitalist, labour-economist, ai-safety-researcher)Present the proposed lineup to the user:
I propose the following debater lineup for the topic "{TOPIC}":
**{name}** — {persona}
Starting position: {starting_position}
Incentives: {incentives}
**{name}** — {persona}
Starting position: {starting_position}
Incentives: {incentives}
Shall I proceed with this lineup, or would you like to modify it?
Wait for the user's response. The user may:
Finalise the lineup in memory. Set each debater's model to the value of MODELS.reporter from config (or a user-specified model if provided). Keep the full debaters array in memory as DEBATERS_JSON (a JSON array string) to pass to spawn prompts. Do not write to any config file.
Continue to Step C.
Step C — Create timestamped output directory
SLUG=$(echo "{TOPIC}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | cut -c1-50)
TIMESTAMP=$(date -u +"%Y%m%dT%H%M%SZ")
OUTPUT_DIR="output/${TIMESTAMP}-${SLUG}"
mkdir -p "$OUTPUT_DIR"
echo "Output directory: $OUTPUT_DIR"
Step D — Export DEBATE_OUTPUT_DIR and initialise debate log
Immediately after creating the output directory, export DEBATE_OUTPUT_DIR so all subsequent write-log.sh calls work:
export DEBATE_OUTPUT_DIR="output/${TIMESTAMP}-${SLUG}"
Then initialise the log:
CONTENT_FILE=$(mktemp)
printf 'Debate session initialised. Chair is ready. Debaters: %s' "{COMMA_SEPARATED_DEBATER_NAMES}" > "$CONTENT_FILE"
"${PLUGIN_ROOT}/shared/write-log.sh" "system" "chair" "setup" "$CONTENT_FILE"
rm "$CONTENT_FILE"
Replace {COMMA_SEPARATED_DEBATER_NAMES} with the names of all debaters from the approved lineup (e.g., venture-capitalist, labour-economist).
Step E — Spawn teammates
First, spawn all debaters by looping over the approved debaters array:
For each debater in the debaters array:
Task({
team_name: "debate",
name: "{debater.name}",
prompt: "Read ${PLUGIN_ROOT}/agents/debater.md for your full instructions.
PLUGIN_ROOT={PLUGIN_ROOT}
DEBATE_OUTPUT_DIR={DEBATE_OUTPUT_DIR}
TOPIC={TOPIC}
DEBATERS_JSON={DEBATERS_JSON}
Your name is: {debater.name}.
Your persona is: {debater.persona}.
Your starting position on the topic is: {debater.starting_position}.
Your incentives are: {debater.incentives}.",
run_in_background: true
})
Then spawn the four support agents:
Task({
team_name: "debate",
name: "reporter",
prompt: "Read ${PLUGIN_ROOT}/agents/reporter.md for your full instructions.
PLUGIN_ROOT={PLUGIN_ROOT}
DEBATE_OUTPUT_DIR={DEBATE_OUTPUT_DIR}
TOPIC={TOPIC}
DEBATERS_JSON={DEBATERS_JSON}",
run_in_background: true
})
Task({
team_name: "debate",
name: "verifier",
prompt: "Read ${PLUGIN_ROOT}/agents/verifier.md for your full instructions.
PLUGIN_ROOT={PLUGIN_ROOT}
DEBATE_OUTPUT_DIR={DEBATE_OUTPUT_DIR}
TOPIC={TOPIC}
DEBATERS_JSON={DEBATERS_JSON}",
run_in_background: true
})
Task({
team_name: "debate",
name: "audience",
prompt: "Read ${PLUGIN_ROOT}/agents/audience.md for your full instructions.
PLUGIN_ROOT={PLUGIN_ROOT}
DEBATE_OUTPUT_DIR={DEBATE_OUTPUT_DIR}
TOPIC={TOPIC}
DEBATERS_JSON={DEBATERS_JSON}",
run_in_background: true
})
Task({
team_name: "debate",
name: "assessor",
prompt: "Read ${PLUGIN_ROOT}/agents/assessor.md for your full instructions.
PLUGIN_ROOT={PLUGIN_ROOT}
DEBATE_OUTPUT_DIR={DEBATE_OUTPUT_DIR}
TOPIC={TOPIC}
DEBATERS_JSON={DEBATERS_JSON}
Wait silently until activated by the Chair.",
run_in_background: true
})
Wait for all (DEBATER_COUNT + 4) agents (N debaters + reporter + verifier + audience + assessor) to confirm readiness via SendMessage before proceeding to Phase 1.
Step F — Log team ready
CONTENT_FILE=$(mktemp)
printf 'All agents confirmed ready. Beginning Phase 1: Opening Statements. Topic: %s' "{TOPIC}" > "$CONTENT_FILE"
"${PLUGIN_ROOT}/shared/write-log.sh" "system" "chair" "announcement" "$CONTENT_FILE"
rm "$CONTENT_FILE"
Loop through the debaters in config array order (index 0 → N-1):
For each debater at index K:
opening_statement and message me with your assigned seq number when done.[If K > 0, append: ' Prior openers and their seqs: {list of name: seq pairs for indices 0..K-1}.']"After all debaters have opened:
CONTENT_FILE=$(mktemp)
printf 'Phase 1 complete. Opening statements delivered. Proceeding to Phase 2.' > "$CONTENT_FILE"
"${PLUGIN_ROOT}/shared/write-log.sh" "system" "chair" "announcement" "$CONTENT_FILE"
rm "$CONTENT_FILE"
Run between MIN_ROUNDS and MAX_ROUNDS rounds (from merged config). Each round:
Round start:
CONTENT_FILE=$(mktemp)
printf 'Round %d of %d beginning.' "$ROUND" "$MAX_ROUNDS" > "$CONTENT_FILE"
"${PLUGIN_ROOT}/shared/write-log.sh" "rebuttal" "chair" "announcement" "$CONTENT_FILE"
rm "$CONTENT_FILE"
At the start of each round, review pending Verifier findings:
redaction ruling immediately before the round begins.ruling noting the concern; warn the relevant debater at the start of their turn.verified results: no action needed; proceed to turn order.Turn order within each round — loop over all debaters in config order (complete all steps for each debater — do not skip):
For each debater at index K (0 → N-1):
Build the turn context block for this debater:
Round {R} — Your turn, {debater.name}.
Context from this round so far:
- {name-A} (seq {X}): {one-sentence summary}
- {name-B} (seq {Y}): {one-sentence summary}
[Empty if K=0 — first debater in the round]
[If Verifier reported issues with this debater's previous sources, include a brief summary here, e.g.:
"Note: Verifier flagged seq {M} as unreliable ({reason})."]
[If a prior debater this round introduced a major analytical framework (a named model or
multi-variable theory not previously referenced in the debate), include:
"Note: {name} introduced the following analytical framework at seq {SEQ}: {brief description}.
You may address it in your turn."]
[If there is an Audience question for this debater from the previous round, relay it here.]
You may make a `new_point`, `rebuttal` (cite rebuttal_to_seq), or `conjecture`.
Log via write-log.sh and message me with your seq when done.
Wait for the debater to confirm (with seq number and entry type).
Immediately notify Verifier of the new entry: "New entry at seq {SEQ} from {debater.name} ({type}). Sources: {sources_json or 'none'}. Please verify any sources."
Forward to Reporter: SendMessage to reporter with a summary of the debater's argument (include seq number, debater name, and brief content summary).
After all debaters have taken their turn in the round:
CONTENT_FILE=$(mktemp)
printf 'Verifier findings relayed this round: %s' "{summary of what was relayed to debaters, or 'none'}" > "$CONTENT_FILE"
"${PLUGIN_ROOT}/shared/write-log.sh" "system" "chair" "announcement" "$CONTENT_FILE"
rm "$CONTENT_FILE"
[MANDATORY — do not skip] Message Audience for round questions: "Round {R} complete. Entries this round: {list of debater names, their seqs, and one-sentence content summaries}. Any questions for the debaters? (0–2 max, addressed to specific debaters by name, or reply 'no questions')"
Do not begin the next round until the Audience has replied or until 2 minutes have elapsed with no response.
If Audience provides questions: consider each one; relay worthy questions to the relevant debater as part of their next turn cue; log any relayed questions as audience_question entries.
After each round, evaluate finish criteria:
round >= MIN_ROUNDS AND (debate has reached natural conclusion OR time budget exceeded): proceed to Pre-Phase-3 check.round >= MAX_ROUNDS: proceed to Pre-Phase-3 check regardless.Handling interruptions during a round:
Before triggering Phase 3, review the full debate log and identify 1–3 substantive unresolved points — arguments that were raised but never directly engaged, or contested claims where no debater produced a decisive counter. Log an announcement:
CONTENT_FILE=$(mktemp)
cat > "$CONTENT_FILE" << 'CONTENT_EOF'
Pre-Phase-3 review: The following points remain unresolved entering the closing round:
1. [Point description — seq ref]
2. [Point description — seq ref]
3. [Point description — seq ref, if applicable]
Debaters are encouraged to address these in their closing statements.
CONTENT_EOF
"${PLUGIN_ROOT}/shared/write-log.sh" "system" "chair" "announcement" "$CONTENT_FILE"
rm "$CONTENT_FILE"
Note the unresolved points list — include it in each debater's closing statement cue.
Proceed in reverse config order (index N-1 → 0):
For each debater at index K (N-1 → 0):
closing_statement. Unresolved points entering Phase 3: {list from pre-Phase-3 check}.[If K < N-1, append: ' Prior closers and their seqs: {list of name: seq pairs for debaters who have already closed}.']"After all closings:
CONTENT_FILE=$(mktemp)
printf 'Phase 3 complete. Closing statements delivered. Proceeding to Phase 4.' > "$CONTENT_FILE"
"${PLUGIN_ROOT}/shared/write-log.sh" "system" "chair" "announcement" "$CONTENT_FILE"
rm "$CONTENT_FILE"
Review the full debate log: cat "${DEBATE_OUTPUT_DIR}/debate-log.jsonl"
Evaluate each debater independently on these criteria:
Then compare all debaters holistically to determine the outcome.
Declare outcome — one of:
{debater_name}_wins — this debater made stronger, better-supported arguments than all othersdraw — arguments were closely balanced across all debatersvoid — debate cannot be fairly concluded (e.g., multiple debaters had fabricated sources)Log conclusion:
CONTENT_FILE=$(mktemp)
cat > "$CONTENT_FILE" << 'CONTENT_EOF'
Debate concluded. Outcome: {OUTCOME}. Reason: {REASON}
CONTENT_EOF
"${PLUGIN_ROOT}/shared/write-log.sh" "system" "chair" "conclusion" "$CONTENT_FILE"
rm "$CONTENT_FILE"
Consult Audience for final thoughts (before notifying Reporter):
audience_conclusion entry is logged (they will reply with the seq number).Message Reporter: "Debate concluded. Outcome: {OUTCOME}. Reason: {REASON}. Audience conclusion is at seq {AUDIENCE_SEQ}. Please produce all output documents in ${DEBATE_OUTPUT_DIR}. The debaters array is: {DEBATERS_JSON}."
Wait for Reporter to confirm output production.
Activate Assessor (after Reporter confirms):
Announce to user: "Debate complete. Outcome: {OUTCOME}. All outputs are in ${DEBATE_OUTPUT_DIR}/ including assessor-report.md."
Source challenges — when a debater challenges a source:
verification_result.redaction ruling, penalise the debater, log ruling.Logging rulings:
CONTENT_FILE=$(mktemp)
cat > "$CONTENT_FILE" << 'CONTENT_EOF'
Ruling on seq {N}: {ruling text and reason}
CONTENT_EOF
"${PLUGIN_ROOT}/shared/write-log.sh" "system" "chair" "ruling" "$CONTENT_FILE"
rm "$CONTENT_FILE"
Redactions:
CONTENT_FILE=$(mktemp)
cat > "$CONTENT_FILE" << 'CONTENT_EOF'
REDACTED: seq {N} ({speaker}). Reason: {reason}. Entry is struck from the record.
CONTENT_EOF
"${PLUGIN_ROOT}/shared/write-log.sh" "system" "chair" "redaction" "$CONTENT_FILE"
rm "$CONTENT_FILE"
The Chair reads config from four sources at startup (later levels override earlier ones):
| Level | Location | Purpose |
|---|---|---|
| Built-in defaults | ${PLUGIN_ROOT}/config-template.json | Ultimate fallback; ships with plugin |
| User defaults | ~/.claude/ai-debate.json | Per-user preferences across all projects |
| Project config | .claude/ai-debate.json | Per-project settings, committable to source control |
| Local overrides | .claude/ai-debate.local.json | Per-machine overrides (add to .gitignore) |
Only min_rounds, max_rounds, time_budget_minutes, and models are read from config. Runtime fields (topic, debaters, output_dir) are passed directly via spawn prompts — never stored in config files.
| Debate Phase | phase field value |
|---|---|
| Setup / system messages | system |
| Phase 1 — Opening Statements | opening |
| Phase 2 — Debate Rounds | rebuttal |
| Phase 3 — Closing Statements | closing |
npx claudepluginhub colings86/ai-debate --plugin ai-debateOrchestrates structured multi-round adversarial debates with Pro/Contra agents and judge verdict. Supports binary/tetralemma/polarity modes, brief format, and user-joining roles.
Orchestrates structured multi-provider AI debates between Claude and available advisors (Gemini, Codex, etc.) for critical decisions. Dispatches real providers via orchestrate.sh for diverse perspectives.
Orchestrates multi-agent debates with 2-5 dynamic agents in Challenge (select best variant), Strategy (deep analysis with proposals), or Critic (find weaknesses) modes. Triggers on debate, challenge, compare, critique prompts.