skills/autoresearch/references/reason-workflow.md

619 lines
24 KiB
Markdown

# 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):
1. **Flags first:** `--iterations`, `--judges`, `--convergence`, `--mode`, `--domain`, `--chain`, `--judge-personas`, `--no-synthesis`, `--temperature`
2. **YAML config block:** `Task:`, `Domain:`, `Mode:`, `Iterations:`, `Judges:`, `Chain:`, `Convergence:`
3. **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 | debate
- `convergent`: stop when incumbent wins `--convergence` consecutive rounds
- `creative`: never auto-stop — generate diverse candidates, no convergence gate
- `debate`: 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:
1. Generate a random permutation of candidate IDs: e.g., `shuffle([A, B, AB])``[AB, A, B]`
2. Assign display labels: `X = AB`, `Y = A`, `Z = B` (example — reshuffled each round)
3. Judges see only X, Y, Z — never A, B, AB
4. Label mapping stored internally in `reason-lineage.jsonl` only — never revealed to judges mid-evaluation
5. **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
1. Decode each judge's winner vote back to A/B/AB using the label map
2. Count votes per candidate
3. Plurality winner becomes `round_winner`
4. 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:
1. Update `consecutive_wins` counter:
- If `round_winner` == `incumbent``consecutive_wins += 1`
- If `round_winner` != `incumbent``consecutive_wins = 1`, update `incumbent = round_winner`
2. Check stop conditions (evaluated in order):
- **Bounded mode** (`--iterations N`): if `round >= 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
3. 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):
```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
```json
{
"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:
1. Write `handoff.json` after convergence
2. Launch `scenario` with chain conversion above
3. After scenario completes, convert scenario findings + handoff.json → debug context
4. After debug completes, convert debug findings → fix targets
5. 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 | `--temperature low` |
## 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 |