24 KiB
Reason Workflow — $autoresearch reason
Isolated multi-agent adversarial refinement for subjective domains. Generates, critiques, synthesizes, and judges outputs through repeated rounds until convergence — producing a lineage of evolving candidates with documented decision rationale.
Core idea: Generate-A → Critic attacks A → Generate-B from task+A+critique → Synthesize-AB → Blind judge panel picks winner → winner becomes new A → repeat until convergence. Every agent is cold-start fresh with no shared session — prevents sycophancy. Judges receive randomized candidate labels and must compare, not praise.
Trigger
- User invokes
$autoresearch reason - User says "reason through this", "adversarial refinement", "debate and converge", "iterative argument", "multi-agent critique", "blind judging"
- User wants subjective quality improvement with documented rationale (architecture proposals, argument quality, content polish, design decisions, research hypotheses)
- Chained from another autoresearch tool via
--chain reason
Loop Support
# Unlimited — keep refining until convergence or interrupted
$autoresearch reason
# Bounded — exactly N refinement rounds
$autoresearch reason
Iterations: 10
# With task
$autoresearch reason
Task: Should we use event sourcing for our order management system?
Domain: software
PREREQUISITE: Interactive Setup (when invoked without full context)
CRITICAL — BLOCKING PREREQUISITE: If $autoresearch reason is invoked without task, domain, and mode all provided, you MUST use direct prompting to gather context BEFORE proceeding to Phase 1. DO NOT skip this step.
TOOL AVAILABILITY: direct prompting may be a deferred tool. If calling it fails, use ToolSearch to fetch the schema first, then retry.
Adaptive question selection rules:
- No input at all → ask all 5 questions
- Task provided but no domain → ask questions 2, 3, 4, 5
- Task + domain provided but no convergence/mode → ask questions 3, 4, 5
- Task + domain + mode + convergence all provided → skip setup entirely
Batch ALL selected questions into a SINGLE direct prompting call:
| # | Header | Question | When to Ask | Options |
|---|---|---|---|---|
| 1 | Task |
"What should be reasoned about? (a question, proposal, design, argument, or claim)" | If no task provided | Open text |
| 2 | Domain |
"What domain is this in?" | If no --domain |
"Software architecture", "Product strategy", "Business decision", "Security approach", "Research hypothesis", "Content/writing", "Other" |
| 3 | Mode |
"What refinement mode?" | If no --mode |
"Convergent (default) — stop when winner repeats N times", "Creative — keep exploring, never auto-stop", "Debate — pure argument quality, no synthesis" |
| 4 | Judges |
"How many blind judges?" | If no --judges |
"3 judges (default)", "5 judges (thorough)", "7 judges (deep)" |
| 5 | Chain |
"Chain to another tool after convergence?" | If no --chain |
"debug", "plan", "fix", "scenario", "predict", "ship", "learn", "No chain — report only" |
Skip setup entirely when: Task + Domain + Mode all provided inline or via flags. Proceed to Phase 1.
Inline Context Parsing
Parse in this order (flags take precedence):
- Flags first:
--iterations,--judges,--convergence,--mode,--domain,--chain,--judge-personas,--no-synthesis,--temperature - YAML config block:
Task:,Domain:,Mode:,Iterations:,Judges:,Chain:,Convergence: - Remaining text: treat as the task description if not matched to a flag
Architecture
$autoresearch reason
├── Phase 1: Setup — Interactive gate + config validation
├── Phase 2: Generate-A — Author-A produces first candidate
├── Phase 3: Critic — Adversarial attack on A (forced weaknesses)
├── Phase 4: Generate-B — Author-B sees task+A+critique, produces B
├── Phase 5: Synthesize-AB — Synthesizer produces AB from task+A+B
├── Phase 6: Judge Panel — N blind judges pick winner (randomized labels)
├── Phase 7: Convergence Check — stop if incumbent wins N consecutive rounds
└── Phase 8: Handoff — write lineage files, optional --chain
Phase 1: Setup — Configuration
STOP: Have you completed the Interactive Setup above? Complete direct prompting before entering this phase.
Parse and validate:
--iterations N: bounded mode — run exactly N rounds then stop (overrides convergence)--judges N: judge count. Default: 3. Range: 3-7. Odd numbers preferred (majority vote)--convergence N: consecutive rounds incumbent must win to stop. Default: 3. Range: 2-5--mode: convergent (default) | creative | debateconvergent: stop when incumbent wins--convergenceconsecutive roundscreative: never auto-stop — generate diverse candidates, no convergence gatedebate: no synthesis step, judges evaluate A vs B directly
--domain: shapes judge persona expertise (software, product, business, security, research, content)--chain: validate targets. Supports comma-separated multi-chain. Known targets: debug, plan, fix, security, scenario, predict, ship, learn--no-synthesis: skip Phase 5, judge A vs B only (equivalent to--mode debate)--judge-personas <list>: override default judge personas with custom list
Create output directory: reason/{YYMMDD}-{HHMM}-{slug}/
Initialize state:
incumbent = null (no winner yet — first round has no incumbent)
round = 0
consecutive_wins = 0
lineage = []
Output: ✓ Phase 1: Setup — task defined, [N] judges, convergence=[K], mode=[mode]
Phase 2: Generate-A — First Candidate
Round 1 (no incumbent)
Author-A receives only the task. No prior candidates. No history. Cold-start context.
Author-A prompt template:
Task: {task_description}
Domain: {domain}
Produce a high-quality response to this task. Be thorough, concrete, and well-reasoned.
Do NOT hold back — this is your best attempt.
CONSTRAINTS:
- No hedging language ("perhaps", "maybe", "it depends") unless genuinely uncertain
- Every claim must be supported by reasoning or evidence
- If this is a design/architecture task: specify components, interfaces, and tradeoffs explicitly
- If this is an argument/decision task: state your position clearly, then defend it
- Length: appropriate for depth of task — not artificially long or short
Round 2+ (incumbent exists)
Author-A receives the current incumbent (the winner of the previous round). Author-A's role is to BUILD ON and IMPROVE the incumbent, not reproduce it.
Task: {task_description}
Domain: {domain}
Current best candidate (do not reproduce verbatim — build on it):
---
{incumbent_text}
---
Your role: Improve this candidate. Identify its weaknesses (from prior critique context if relevant)
and produce a version that addresses them. You may restructure, extend, prune, or reframe.
Do NOT simply paraphrase. Produce a genuinely better version.
Output: ✓ Phase 2: Generate-A — candidate A produced ([word_count] words)
Phase 3: Critic — Adversarial Attack
The Critic receives only candidate A. No task description to prevent task-anchoring. No incumbent history. Cold-start context.
Context isolation invariant: Critic MUST NOT see previous rounds, Author-B's outputs, or judge transcripts. Fresh context only.
Critic prompt template:
You are an adversarial critic. Your job is to ATTACK the following candidate ruthlessly.
Candidate:
---
{candidate_A}
---
RULES:
1. Find MINIMUM 3 distinct weaknesses (more is better)
2. Each weakness must be SPECIFIC — quote or reference the exact claim, section, or reasoning you're attacking
3. Weaknesses must be SUBSTANTIVE — not stylistic nitpicks unless the style undermines comprehension
4. Do NOT offer fixes — only attack. The Author-B role will respond to your critique
5. Rate each weakness by impact: FATAL (invalidates the argument), MAJOR (significant gap), MINOR (improvable)
6. End with a one-line "Verdict" sentence summarizing the weakest point overall
Output format:
WEAKNESS-1 [FATAL|MAJOR|MINOR]: {specific claim or section} — {critique}
WEAKNESS-2 [FATAL|MAJOR|MINOR]: ...
...
WEAKNESS-N [FATAL|MAJOR|MINOR]: ...
VERDICT: {one-line summary of the most critical weakness}
Output: ✓ Phase 3: Critic — [N] weaknesses found ([fatal], [major], [minor])
Phase 4: Generate-B — Challenger Candidate
Author-B receives the task AND candidate A AND the critique. Author-B's role is to produce a BETTER candidate by learning from the critique without being told what the "right answer" is.
Context isolation invariant: Author-B does NOT see prior rounds. Fresh context with task + A + critique only.
Author-B prompt template:
Task: {task_description}
Domain: {domain}
Here is a previous attempt at this task:
---
CANDIDATE A:
{candidate_A}
---
Here is an adversarial critique of Candidate A:
---
CRITIQUE:
{critique}
---
Your role: Produce a BETTER candidate (Candidate B) that addresses the critique's weaknesses
while preserving what Candidate A did well.
CONSTRAINTS:
- Address at least the FATAL and MAJOR weaknesses from the critique
- Do NOT simply patch A — rethink structure and reasoning where the critique reveals deeper issues
- Do NOT reference the critique explicitly ("as the critique noted...") — integrate the improvements naturally
- Do NOT reproduce A verbatim — your candidate must be substantively different
- Every claim must be supported by reasoning or evidence
- Avoid over-correcting: if a MINOR weakness was stylistic, don't restructure the entire response for it
Output: ✓ Phase 4: Generate-B — candidate B produced ([word_count] words)
Phase 5: Synthesize-AB — Composite Candidate
The Synthesizer receives the task AND both A and B. It produces a third candidate (AB) that is BETTER than either by combining the best elements of both.
This phase is skipped when: --mode debate or --no-synthesis flag.
Context isolation invariant: Synthesizer MUST NOT see the critique or judge history. Receives task + A + B only.
Synthesizer prompt template:
Task: {task_description}
Domain: {domain}
You have two candidate responses to this task:
---
CANDIDATE A:
{candidate_A}
---
CANDIDATE B:
{candidate_B}
---
Your role: Produce CANDIDATE AB — a synthesis that is superior to both A and B.
CONSTRAINTS:
1. Identify what A does better than B (specific strengths)
2. Identify what B does better than A (specific strengths)
3. Combine the strongest elements — do NOT average them into mediocrity
4. Resolve any direct contradictions by reasoning through which position is better supported
5. The result must be COHERENT — not a patchwork. It should read as a single unified response
6. Do NOT invent new claims that neither A nor B supports — synthesize only from what exists
7. Do NOT hedge contradictions — pick a position and defend it
Begin with a 2-3 sentence internal monologue (in [brackets]) explaining what you're taking from each,
then produce the full synthesized candidate.
Output: ✓ Phase 5: Synthesize-AB — candidate AB produced ([word_count] words)
Phase 6: Judge Panel — Blind Evaluation
N judges evaluate candidates using randomized labels. Judges never know which label maps to which candidate.
Label Randomization Protocol
Before dispatching judges:
- Generate a random permutation of candidate IDs: e.g.,
shuffle([A, B, AB])→[AB, A, B] - Assign display labels:
X = AB,Y = A,Z = B(example — reshuffled each round) - Judges see only X, Y, Z — never A, B, AB
- Label mapping stored internally in
reason-lineage.jsonlonly — never revealed to judges mid-evaluation - Why: Prevents judges from anchoring on "the synthesis is always better" — forces genuine comparative evaluation
Judge Count by Mode
--judges |
Judges Dispatched | Majority Threshold |
|---|---|---|
| 3 (default) | 3 | ≥2 votes |
| 5 | 5 | ≥3 votes |
| 7 | 7 | ≥4 votes |
In --mode debate (no AB): judges evaluate X vs Y only (A vs B under randomized labels).
Judge Prompt Template
You are an expert evaluator in {domain}.
Task: {task_description}
Below are {N} candidate responses. Labels are arbitrary — do NOT assume ordering implies quality.
---
CANDIDATE X:
{candidate_X_text}
---
CANDIDATE Y:
{candidate_Y_text}
---
{if not debate mode}
CANDIDATE Z:
{candidate_Z_text}
{/if}
---
EVALUATION RULES:
1. You MUST pick a winner. "Tie" is not acceptable — force-rank if close
2. Evaluate on: accuracy/correctness, completeness, reasoning quality, practical applicability
3. Domain-specific criteria apply: {domain_criteria}
4. Your reasoning must cite SPECIFIC text from the candidates (quote or reference)
5. DO NOT pick based on length — longer is not better
6. DO NOT pick based on style — substance wins
Output format:
WINNER: X | Y | Z
RUNNER-UP: X | Y | Z
REASONING: {2-4 sentences citing specific evidence}
WINNING_STRENGTH: {the single strongest element of the winner}
RUNNER_UP_GAP: {the specific gap that prevented runner-up from winning}
Domain Criteria Injection
| Domain | Criteria |
|---|---|
software |
Correctness, feasibility, edge case coverage, maintainability tradeoffs |
product |
User value clarity, feasibility, prioritization rationale, metrics |
business |
ROI reasoning, risk awareness, stakeholder consideration, actionability |
security |
Threat coverage, defense-in-depth, real attack scenario validity |
research |
Hypothesis clarity, falsifiability, methodology soundness, novelty |
content |
Clarity, audience fit, argument strength, factual accuracy |
Vote Tallying
- Decode each judge's winner vote back to A/B/AB using the label map
- Count votes per candidate
- Plurality winner becomes
round_winner - If tie (only possible with even N — discourage even N):
- Tiebreak by "runner-up" second-choice votes
- If still tied: incumbent wins (status quo bias — challenger must clearly win)
Reasoning Aggregation
Collect all WINNING_STRENGTH and RUNNER_UP_GAP entries per candidate. Used for:
- Author-A context in next round (what did winner do well?)
- Lineage documentation
- Chain handoff quality signal
Output: ✓ Phase 6: Judge Panel — winner: [A|B|AB], votes [N]-[M]-[K], round [R]
Phase 7: Convergence Check
After each judge round:
-
Update
consecutive_winscounter:- If
round_winner==incumbent→consecutive_wins += 1 - If
round_winner!=incumbent→consecutive_wins = 1, updateincumbent = round_winner
- If
-
Check stop conditions (evaluated in order):
- Bounded mode (
--iterations N): ifround >= N→ STOP - Convergence (convergent mode): if
consecutive_wins >= convergence_threshold→ STOP - Creative mode: never auto-stop — only stops on user interrupt or
--iterations N - Max oscillation guard: if incumbent has changed 5+ times with no consecutive wins → STOP and flag oscillation
- Bounded mode (
-
If continuing: advance to Phase 2 (Generate-A) with current incumbent as base
Convergence Report (printed when stopping)
✓ Converged after [N] rounds
Final winner: [A|B|AB], round [R], [consecutive_wins] consecutive wins
Total candidates evaluated: [N*3 or N*2 in debate mode]
Lineage: [brief trace of who won each round]
Oscillation Detection
If the winner alternates without achieving consecutive wins (e.g., round pattern: A→B→A→B→A):
- After 5 oscillations:
OSCILLATION WARNING— forced stop - Log in overview.md:
⚠️ Convergence failed: oscillation detected. The task may be genuinely ambiguous or the candidates may be at parity. - Surface all three candidates from final round in report — present as "equivalent alternatives"
Output: ✓ Phase 7: Convergence — [continuing|converged|oscillation_stop|bounded_stop]
Phase 8: Handoff — Output Files and Optional Chain
reason-lineage.jsonl
Append one record per round (newline-delimited JSON):
{
"round": 1,
"timestamp": "2026-03-31T14:22:00Z",
"task_hash": "sha256_of_task_text",
"candidate_A_words": 312,
"candidate_B_words": 287,
"candidate_AB_words": 298,
"label_map": {"X": "AB", "Y": "A", "Z": "B"},
"judge_votes": [
{"judge": 1, "winner_label": "X", "winner_decoded": "AB", "runner_up": "Y"},
{"judge": 2, "winner_label": "X", "winner_decoded": "AB", "runner_up": "Z"},
{"judge": 3, "winner_label": "Y", "winner_decoded": "A", "runner_up": "X"}
],
"round_winner": "AB",
"vote_tally": {"A": 1, "B": 0, "AB": 2},
"incumbent_before": "A",
"incumbent_after": "AB",
"consecutive_wins": 1,
"critic_weaknesses": ["FATAL: no tradeoff analysis", "MAJOR: missing failure modes"],
"winning_strength": "Synthesized version explicitly addresses both scalability and consistency tradeoffs",
"runner_up_gap": "Candidate A lacked concrete failure mode analysis despite stronger initial structure"
}
handoff.json Schema
{
"version": "1.0",
"tool": "reason",
"generated_at": "2026-03-31T14:30:00Z",
"task": "Should we use event sourcing for our order management system?",
"domain": "software",
"mode": "convergent",
"summary": {
"rounds_run": 6,
"converged": true,
"consecutive_wins": 3,
"oscillation_detected": false,
"final_winner": "AB",
"reason_score": 187
},
"converged_candidate": {
"text": "{full text of the winning candidate}",
"word_count": 312,
"won_in_round": 6,
"vote_margin": "3-0"
},
"lineage_path": "reason/{slug}/reason-lineage.jsonl",
"critique_themes": [
"Missing failure mode analysis",
"No concrete rollback strategy",
"Event ordering assumptions under concurrent writes"
],
"quality_signals": {
"critic_fatals_addressed": 3,
"judge_consensus_final_round": 1.0,
"quality_delta": 0.42
}
}
Chain Conversion
--chain debug
The converged candidate (if technical: architecture, design, algorithm) becomes a hypothesis context for the debug loop. Critique themes become suspect areas.
$autoresearch debug
Scope: {files relevant to task domain}
Symptom: Implementing {task} — authoritative design from reason loop
Context: {converged_candidate_text truncated to 500 chars}
Hypotheses:
{critique_theme_1 mapped to file scope if determinable}
{critique_theme_2}
--chain plan
The converged candidate becomes the basis for an autoresearch:plan configuration.
$autoresearch plan
Goal: {task_as_goal}
Context: Reasoned design from {N} rounds of adversarial refinement:
{converged_candidate_text}
--chain fix
If task involves existing code or errors, converged candidate becomes the authoritative fix target description.
$autoresearch fix
Target: {task_description}
Scope: {task-relevant file globs}
Fix-Rationale: {converged_candidate_text — the authoritative approach after N rounds}
--chain security
Critique themes that overlap with security concerns (threat modeling, auth, data handling) seed the security audit focus.
$autoresearch security
Scope: {files relevant to task domain}
Focus: Security aspects surfaced by adversarial reason loop:
{security-relevant critique themes}
--chain scenario
The converged candidate becomes the seed scenario. Critique themes become explicit dimensions to explore.
$autoresearch scenario
Scenario: {converged_candidate_text — the converged approach}
Domain: {domain}
Focus: {primary critique theme — e.g., "failure modes", "concurrency"}
Depth: standard
--chain predict
The converged candidate and lineage critique themes become the goal for multi-persona swarm analysis.
$autoresearch predict
Scope: {task-relevant file globs}
Goal: Validate and stress-test this design: {converged_candidate_text truncated to 300 chars}
Depth: standard
--chain ship
Converged candidate feeds directly to ship workflow as the artifact to ship.
$autoresearch ship
Target: {converged_candidate as content artifact or implementation spec}
Type: {auto-detect from domain}
--chain learn
The full reason lineage (all rounds, critique themes, candidate evolution) feeds to learn as documentation source.
$autoresearch learn
Mode: update
Context: Reason lineage from {N} rounds — {task_description}
Source: reason/{slug}/reason-lineage.jsonl
Multi-Chain Execution
--chain scenario,debug,fix executes sequentially:
- Write
handoff.jsonafter convergence - Launch
scenariowith chain conversion above - After scenario completes, convert scenario findings + handoff.json → debug context
- After debug completes, convert debug findings → fix targets
- Each stage's output feeds the next via updated handoff.json
Empirical evidence rule: Downstream loop results (debug, fix, security) ALWAYS override reason consensus. If debug disproves a design conclusion from the reason loop, log: Reason candidate's claim [X] DISPROVEN by empirical debug loop — [evidence]. Do NOT revert to reason consensus.
Output Files
Creates reason/{YYMMDD}-{HHMM}-{slug}/ with:
| File | Description |
|---|---|
overview.md |
Executive summary: task, rounds run, convergence result, final winner, quality delta, oscillation status |
lineage.md |
Human-readable round-by-round trace: who won, vote tally, key critique that drove change |
candidates.md |
Final round candidates A, B, AB in full — for manual review |
judge-transcripts.md |
Full judge reasoning per round (decoded — labels revealed post-evaluation) |
reason-results.tsv |
Per-round log: round, winner, votes, consecutive_wins, word_counts |
reason-lineage.jsonl |
Machine-readable full lineage (consumed by --chain tools) |
handoff.json |
Chain handoff schema |
Composite Metric
reason_score = quality_delta * 30
+ rounds_survived * 5
+ judge_consensus_final_round * 20
+ critic_fatals_addressed * 15
+ (convergence_achieved ? 10 : 0)
+ (no_oscillation ? 5 : 0)
Where:
quality_delta = (final_winner_word_count - A_round1_word_count) / A_round1_word_count
— normalized change in substance (not just length)
— capped at 1.0 to prevent inflation from padding
judge_consensus_final_round = winning_votes / total_judges (0.0 to 1.0)
critic_fatals_addressed = count of FATAL weaknesses that didn't recur in later rounds
Higher = more thorough + more decisive convergence. Incentivizes: substantial improvement over starting candidate, decisive judge consensus, critique responsiveness, and convergence over oscillation.
Flags
| Flag | Purpose | Example |
|---|---|---|
--iterations N |
Bounded mode — run exactly N rounds | --iterations 10 |
--judges N |
Judge count (3-7, odd preferred) | --judges 5 |
--convergence N |
Consecutive wins to declare convergence (2-5) | --convergence 3 |
--mode <mode> |
convergent (default), creative, debate | --mode creative |
--domain <type> |
Domain for judge personas | --domain software |
--chain <targets> |
Chain to downstream tool(s). Comma-separated for multi-chain | --chain scenario,debug |
--judge-personas <list> |
Override default judge personas | --judge-personas "DBA,Frontend,PM" |
--no-synthesis |
Skip synthesis step (A vs B only) | --no-synthesis |
| `--temperature low | high` | Low: forces decisive wins. High: allows closer votes |
What NOT to Do — Anti-Patterns
| Anti-Pattern | Why It Fails |
|---|---|
| Let judges see candidate labels (A/B/AB) | Judges will bias toward synthesis — randomized labels are the entire point |
| Pass critique to Synthesizer | Synthesizer produces a strawman fix, not a genuine synthesis — give it only A and B |
| Pass prior judge transcripts to Author-B | Author-B anchors on what judges liked rather than fixing critique weaknesses |
| Use even N for judges | Even judge counts can tie. Prefer 3, 5, 7 |
| Skip convergence check | Without convergence detection, creative mode runs forever on trivial tasks |
| Trust reason loop over empirical tests | Adversarial refinement produces better arguments, not necessarily better code — verify empirically |
Set --convergence 1 |
A single win doesn't indicate stable quality — use ≥2 |
| Chain without reviewing candidates.md | Chain handoff quality depends on the actual converged text — check it before trusting downstream |
Run unbounded on --mode creative without --iterations |
Creative mode never auto-stops — always pair with --iterations N unless you intend to run until interrupt |