# CURI-O: The Iterative Research Loop

**Document type:** Architecture Design  
**Author:** Benjamin Booth  •  **Status:** Draft  •  **Last updated:** 2026-04-13

---

## Table of Contents

- [1. The Core Insight](#1-the-core-insight)
- [2. The Loop](#2-the-loop)
- [3. Loop State](#3-loop-state)
- [4. Convergence](#4-convergence)
- [5. Federation: Distributed Convergent Research](#5-federation-distributed-convergent-research)
- [6. Applications](#6-applications)
- [7. Implementation Architecture](#7-implementation-architecture)
- [8. Eval Integration](#8-eval-integration)

---

## 1. The Core Insight

Andrej Karpathy's key observation: the basic ML training loop — generate, evaluate, refine, repeat — is a universal optimization pattern that applies far beyond gradient descent. CURI-O applies it to knowledge research.

**The ML training loop:**
```
for epoch in range(N):
    prediction = model.forward(input)      # generate
    loss = loss_fn(prediction, target)      # evaluate
    gradients = loss.backward()             # compute direction of improvement
    model.update(gradients)                 # refine
```

**CURI-O's research loop:**
```
for iteration in range(until_converged):
    hypothesis = formulate(prior_knowledge, gaps)   # generate
    evidence = search(hypothesis, corpora)           # search
    assessment = evaluate(evidence, hypothesis)      # evaluate
    refined = refine(hypothesis, assessment)          # refine
    corpus.update(validated_findings)                 # learn
```

The parallel is exact:
- **Forward pass → Formulate hypothesis.** Given what you know (prior knowledge) and what you don't (gaps), generate a research direction.
- **Loss function → Evaluate evidence.** How well does the evidence support or contradict the hypothesis? Where are the disagreements? What's still missing?
- **Backward pass → Compute research direction.** The evaluation produces "gradients" — signals about where to look next, which sources to dig deeper into, which contradictions to resolve.
- **Weight update → Refine hypothesis + update corpus.** The hypothesis evolves. Validated findings are promoted to the corpus. The corpus is the "model" — it gets smarter each iteration.
- **Convergence → Diminishing returns.** When new iterations stop finding significant new evidence or changing the hypothesis, the loop converges.

**What makes this fundamentally different from single-shot "research X":**

1. **The loop discovers questions it didn't know to ask.** Iteration 1 searches for "accident-tolerant fuels." Iteration 2 discovers that the real question is "what are the neutronics penalties of FeCrAl cladding?" — a question the user never asked and wouldn't have known to ask.

2. **Contradictions drive the next iteration.** When CURI-O finds two sources that disagree, that disagreement becomes the *input* to the next iteration. The loop doesn't average over contradictions — it investigates them.

3. **The process is auditable.** Every iteration is logged: what hypothesis was tested, what evidence was found, what changed, why. A student or researcher can trace the evolution of understanding, not just read the final report.

4. **The corpus learns.** Each iteration's validated findings are promoted to the knowledge corpus. The next research loop — by this user or anyone else — starts from a higher baseline.

---

## 2. The Loop

```mermaid
graph TB
    subgraph LOOP["CURI-O Research Loop"]
        direction TB
        F["FORMULATE — Generate hypothesis from prior knowledge and gaps"]
        S["SEARCH — Discover and read evidence across corpora and external sources"]
        E["EVALUATE — Assess evidence; score support; surface contradictions; identify gaps"]
        R["REFINE — Update hypothesis; narrow scope; generate new sub-questions"]
        P["PROMOTE — Validated findings to corpus with anchored citations and maturity update"]
        C{"CONVERGED?"}

        F --> S
        S --> E
        E --> R
        R --> C
        C -->|"No — new questions emerged"| F
        C -->|"Yes — diminishing returns"| P
    end

    style LOOP fill:#1a202c,color:#e2e8f0,stroke:#4a5568
    style F fill:#2f855a,color:#fff,stroke:#276749
    style S fill:#2b6cb0,color:#fff,stroke:#2c5282
    style E fill:#c05621,color:#fff,stroke:#9c4221
    style R fill:#6b46c1,color:#fff,stroke:#553c9a
    style P fill:#2f855a,color:#fff,stroke:#276749
    style C fill:#2d3748,color:#e2e8f0,stroke:#4a5568
```

### Phase 1: FORMULATE

**Input:** Prior knowledge (existing corpus state), identified gaps (from previous evaluation or user query), research objective.

**Output:** A structured hypothesis with:
- **Thesis statement** — what we think is true, to be tested
- **Search queries** — specific, targeted queries to run against corpora and external sources
- **Expected evidence** — what would confirm or refute the thesis
- **Sub-questions** — decomposition of the main question into investigable parts

**First iteration:** The user's query is the seed. "Research accident-tolerant fuels" → CURI-O formulates: "Thesis: FeCrAl and SiC/SiC are the leading ATF cladding candidates as of 2025. Sub-questions: What are the neutronics penalties? What's the manufacturing readiness? What are the regulatory pathways?"

**Subsequent iterations:** Formulation is driven by the previous evaluation's output — gaps, contradictions, and new sub-questions that emerged. The hypothesis refines.

### Phase 2: SEARCH

**Input:** Search queries from FORMULATE, source scope configuration.

**Output:** Retrieved evidence — documents, chunks, claims, data points — with provenance.

**Sources (ordered by trust):**
1. Internal corpus (rag-community, rag-org, rag-internal) — highest trust, fastest
2. Federation peers — trusted, may have different corpora
3. External indices — academic databases, regulatory repositories (if configured)
4. Web (if enabled) — lowest trust, requires extra validation

**Key behavior:** SEARCH doesn't just retrieve — it **reads deeply**. For each retrieved document, CURI-O's Read/Extract primitive parses the full content, extracts specific claims, identifies relationships between claims, and notes provenance (page, section, table, figure). This is not keyword matching — it's comprehension.

### Phase 3: EVALUATE

**Input:** Evidence from SEARCH, current hypothesis from FORMULATE.

**Output:** An assessment with:
- **Support score** — how strongly does the evidence support the thesis? (0-1)
- **Contradiction inventory** — specific claims that conflict with each other or with the thesis, with sources cited
- **Gap inventory** — questions that the evidence doesn't address
- **Confidence distribution** — for each sub-question, how confident are we in the answer?
- **Novelty signal** — did this iteration find something significantly new vs. previous iterations?

**This is the "loss function."** It tells the loop how much it still needs to learn. High support + few gaps + low novelty = converging. Low support + many contradictions + high novelty = keep iterating.

### Phase 4: REFINE

**Input:** Assessment from EVALUATE.

**Output:** Updated hypothesis + decision: continue or converge.

**Refinement operations:**
- **Narrow:** Evidence strongly supports one sub-question → mark as resolved, focus remaining iterations on gaps
- **Pivot:** Evidence contradicts the thesis → reformulate the thesis
- **Decompose:** A sub-question is too broad to answer → split into smaller, more specific sub-questions
- **Escalate:** A contradiction can't be resolved from available sources → flag for human review or federation query
- **Confirm:** Sub-question answered with high confidence → promote finding to validated status

### Phase 5: PROMOTE

**Trigger:** Loop converges (see Section 4).

**Output:** 
- Validated findings promoted to the knowledge corpus with full citation chains
- Research report (structured synthesis with provenance at every claim)
- Knowledge maturity layer updated (Layer 0 → Layer 1 or higher)
- Corpus generation incremented if significant new knowledge added
- Research artifact created (shareable via federation)

---

## 3. Loop State

Each research loop maintains state across iterations. This is the "model" being trained:

```yaml
research_loop:
  id: "rl-2026-04-13-atf-cladding"
  objective: "Current state of accident-tolerant fuel cladding materials"
  initiated_by: "student_07"        # or "autonomous" or "federation_peer"
  iteration: 3
  
  hypothesis:
    current_thesis: "FeCrAl and SiC/SiC are leading ATF candidates but face different barriers: FeCrAl has neutronics penalties (parasitic absorption), SiC/SiC has manufacturing scalability challenges."
    confidence: 0.78
    
  sub_questions:
    - id: sq-1
      question: "What are the quantified neutronics penalties of FeCrAl vs. Zircaloy?"
      status: resolved       # answered in iteration 2
      confidence: 0.92
      finding: "FeCrAl introduces ~15-25% reactivity penalty due to Fe-56 absorption cross-section. Compensated by enrichment increase from 4.95% to ~6-7%."
      sources: ["doi:10.1016/j.jnucmat.2023.154321", "INL/EXT-22-67891"]
      
    - id: sq-2
      question: "What is the current manufacturing readiness level for SiC/SiC tubes?"
      status: investigating   # found contradictions in iteration 2, investigating in iteration 3
      confidence: 0.45
      contradiction: "GA claims TRL-6 (2024 report), ORNL assessment says TRL-4 (2023). Investigating the discrepancy."
      
    - id: sq-3
      question: "What are the NRC regulatory pathways for ATF deployment?"
      status: gap            # not yet searched
      confidence: 0.0
      
  evidence_log:
    - iteration: 1
      queries_run: 4
      sources_found: 12
      novelty_score: 0.95    # first iteration, everything is new
      
    - iteration: 2
      queries_run: 6
      sources_found: 8
      novelty_score: 0.62    # found new contradictions
      contradictions_found: 1
      
    - iteration: 3
      queries_run: 3
      sources_found: 4
      novelty_score: 0.28    # converging — most evidence confirms existing findings
      contradictions_resolved: 0  # still investigating SiC TRL discrepancy
      
  convergence:
    novelty_trend: [0.95, 0.62, 0.28]   # declining — approaching convergence
    unresolved_contradictions: 1
    unaddressed_gaps: 1
    estimated_remaining_iterations: 2
```

**Key property:** The loop state is a first-class artifact. It can be:
- Serialized and resumed later (student starts research, continues next day)
- Inspected by an instructor (see how the student's understanding evolved)
- Shared via federation (another node picks up where this loop left off)
- Exported for research (the evolution of understanding IS the data)

---

## 4. Convergence

The loop needs to know when to stop. This is the "stopping criterion" — analogous to early stopping in ML training.

### Convergence Signals

| Signal | Meaning | Weight |
|--------|---------|--------|
| **Novelty decay** | Each iteration finds less new information. Novelty score drops below threshold (e.g., < 0.15). | High |
| **Confidence plateau** | Overall hypothesis confidence stops increasing between iterations. | High |
| **Gap closure** | All sub-questions are either resolved or explicitly marked as out-of-scope. | Medium |
| **Contradiction resolution** | All identified contradictions are either resolved or explained. | Medium |
| **Source saturation** | Search returns mostly documents already seen in previous iterations. | Medium |
| **Iteration budget** | Hard cap on iterations (configurable per research scope). Default: 5-10 iterations. | Safety |
| **Cost budget** | LLM API cost cap per research loop. | Safety |

### Convergence Decision

```python
def should_converge(state: ResearchLoopState) -> bool:
    # Hard limits
    if state.iteration >= state.max_iterations:
        return True
    if state.total_cost >= state.cost_budget:
        return True
    
    # Soft convergence
    if state.novelty_trend[-1] < 0.15:
        # Low novelty — but check for unresolved contradictions
        if state.unresolved_contradictions == 0:
            return True
        # Have contradictions but can't resolve them
        if state.iteration - state.last_contradiction_resolved > 2:
            return True  # stuck — converge and flag
    
    return False
```

### Partial Convergence

Not all sub-questions converge at the same rate. CURI-O can:
- Promote resolved sub-questions to the corpus immediately (don't wait for the whole loop)
- Continue iterating on unresolved sub-questions
- Flag stuck sub-questions for human review or federation escalation

---

## 5. Federation: Distributed Convergent Research

This is where it gets transformative.

### The Single-Node Loop (Recap)

```
CURI-O at Node A:
  Iteration 1: formulate → search(local corpus) → evaluate → refine
  Iteration 2: formulate → search(local corpus) → evaluate → refine
  Iteration 3: converge → promote to local corpus
```

Good, but limited by one node's corpus, one node's perspective, one node's access tier.

### The Federated Loop

```mermaid
graph TB
    subgraph FA["Node A — UT Austin"]
        direction TB
        LA1["Iteration 1 — Search local corpus; find FeCrAl neutronics data"]
        LA2["Iteration 2 — Search local plus federated; confirms penalty; new enrichment data from B"]
        LA3["Iteration 3 — Converge on neutronics and promote to local corpus"]
        LA1 --> LA2
        LA2 --> LA3
    end

    subgraph FB["Node B — INL"]
        direction TB
        LB1["Iteration 1 — Search local corpus; find manufacturing data and TRL assessments"]
        LB2["Iteration 2 — Search local plus federated; A's neutronics penalty changes manufacturing viability calc"]
        LB3["Iteration 3 — Refine manufacturing thesis based on A's neutronics input"]
        LB1 --> LB2
        LB2 --> LB3
    end

    subgraph FC["Node C — OSU"]
        direction TB
        LC1["Iteration 1 — Search local corpus; find regulatory pathway docs and NRC guidance"]
        LC2["Iteration 2 — Search local plus federated; A and B findings require updated regulatory analysis"]
        LC3["Iteration 3 — Regulatory pathway synthesis incorporating A and B findings"]
        LC1 --> LC2
        LC2 --> LC3
    end

    LA1 -->|"Finding: FeCrAl has 15-25% reactivity penalty"| FB
    LB1 -->|"Finding: SiC TRL discrepancy GA vs ORNL"| FA
    LA2 -->|"Refined: enrichment compensation data"| FC
    LB2 -->|"Refined: manufacturing viability depends on penalty"| FC

    style FA fill:#1a202c,color:#e2e8f0,stroke:#4a5568
    style FB fill:#1a202c,color:#e2e8f0,stroke:#4a5568
    style FC fill:#1a202c,color:#e2e8f0,stroke:#4a5568
    style LA1 fill:#2b6cb0,color:#fff,stroke:#2c5282
    style LA2 fill:#2b6cb0,color:#fff,stroke:#2c5282
    style LA3 fill:#2f855a,color:#fff,stroke:#276749
    style LB1 fill:#c05621,color:#fff,stroke:#9c4221
    style LB2 fill:#c05621,color:#fff,stroke:#9c4221
    style LB3 fill:#c05621,color:#fff,stroke:#9c4221
    style LC1 fill:#6b46c1,color:#fff,stroke:#553c9a
    style LC2 fill:#6b46c1,color:#fff,stroke:#553c9a
    style LC3 fill:#6b46c1,color:#fff,stroke:#553c9a
```

### What Federates Between Loops

**Research momentum** — not just findings, but the *direction* of investigation:

```yaml
federation_research_message:
  type: "research_finding"
  loop_id: "rl-2026-04-13-atf-cladding"
  source_node: "ut-austin"
  iteration: 2
  
  finding:
    sub_question: "FeCrAl neutronics penalty"
    thesis: "FeCrAl introduces 15-25% reactivity penalty"
    confidence: 0.92
    key_sources:
      - "doi:10.1016/j.jnucmat.2023.154321"
      - "INL/EXT-22-67891"
    
  implications:
    - "Manufacturing viability assessments should account for enrichment increase to 6-7%"
    - "Regulatory pathway analysis needs to address fuel enrichment above 5% (current Part 50 limit)"
    
  contradictions_found:
    - "GA vs ORNL SiC TRL assessment — requesting peer investigation"
    
  suggested_queries_for_peers:
    - "What is the NRC pathway for fuel enrichment above 5%?"
    - "Does enrichment increase change the economic viability of FeCrAl?"
```

**What this message does at the receiving node:**

1. The finding ("15-25% reactivity penalty") is injected into the receiving node's research loop state as **prior knowledge** for the next FORMULATE phase.
2. The implications become **new sub-questions** that the receiving node's loop adds to its investigation.
3. The contradiction ("GA vs ORNL TRL") becomes a **peer investigation request** — the receiving node searches its own corpus for evidence on the discrepancy.
4. The suggested queries inform the next SEARCH phase — the sending node tells receivers where to look, based on what it found.

### Federation Protocol: Research Coordination

```mermaid
graph TB
    subgraph COORD["Research Coordination Protocol"]
        direction TB
        I["INITIATE — Node A starts research loop and broadcasts research_topic plus scope"]
        J["JOIN — Peer nodes with relevant corpora opt in to the distributed loop"]
        D["DISTRIBUTE — Coordinator assigns sub-questions to nodes based on corpus coverage"]
        X["EXCHANGE — After each iteration, nodes share findings, contradictions, gaps, and suggested queries"]
        M["MERGE — Coordinator merges findings across nodes, resolves conflicts, updates global hypothesis"]
        CV{"GLOBAL CONVERGENCE?"}
        S["SYNTHESIZE — Produce federated research report with per-node provenance; promote to all corpora"]

        I --> J
        J --> D
        D --> X
        X --> M
        M --> CV
        CV -->|"No"| D
        CV -->|"Yes"| S
    end

    style COORD fill:#1a202c,color:#e2e8f0,stroke:#4a5568
    style I fill:#2b6cb0,color:#fff,stroke:#2c5282
    style J fill:#2b6cb0,color:#fff,stroke:#2c5282
    style D fill:#c05621,color:#fff,stroke:#9c4221
    style X fill:#2f855a,color:#fff,stroke:#276749
    style M fill:#6b46c1,color:#fff,stroke:#553c9a
    style CV fill:#2d3748,color:#e2e8f0,stroke:#4a5568
    style S fill:#2f855a,color:#fff,stroke:#276749
```

### Coordination Modes

**Mode 1: Independent with sharing (loose coupling)**
Each node runs its own loop independently. After each iteration, findings are broadcast to peers. No coordinator. Each node incorporates peer findings at its own pace. Good for: classroom (students researching independently, learning from each other's discoveries).

**Mode 2: Coordinated with sub-question distribution (medium coupling)**
A coordinator node distributes sub-questions to peers based on corpus coverage analysis. Nodes report back after each iteration. Coordinator merges and redistributes. Good for: multi-institutional research where each site has different expertise/data.

**Mode 3: Synchronized lockstep (tight coupling)**
All nodes execute the same iteration simultaneously. Global evaluation after each round. Coordinator decides the next research direction for all nodes. Good for: formal research projects with deadlines and defined scope.

### Access Tier Awareness

Federation research respects access tiers:
- **Public** findings flow freely between all nodes
- **Restricted** findings flow only to nodes with established trust relationships
- **Export-controlled** findings NEVER leave the originating node — but the *existence* of a finding can be signaled ("Node A found relevant EC material — contact them directly for access")

This means a federated research loop can produce a synthesis where some citations are only accessible to specific nodes. The synthesis acknowledges this: "Finding X is supported by [restricted source at Node A] — contact ut-austin@federation for access."

---

## 6. Applications

### 6.1 Classroom: Student Research Loops

**The setup:** 12 students in Prague, each with access to CURI-O via the chat interface (WALL-E branded as Neut). The course covers nuclear reactor design.

**Week 2 assignment:** "Use CURI-O to research the current state of small modular reactor (SMR) designs. Run at least 3 iterations. Submit your research loop state alongside your synthesis."

**What happens:**

1. Student A starts: "Research SMR designs." CURI-O formulates sub-questions: licensing pathways, coolant technologies, economic viability, deployment timelines.

2. Student A's iteration 2 discovers that NuScale's design certification was approved but BWXT's micro-reactor uses a different regulatory pathway. This is a contradiction worth investigating.

3. Meanwhile, Student B started with a different angle: "Research SMR economic viability." CURI-O formulates: capital costs, construction timelines, market demand, financing models.

4. **Federation (Mode 1, loose coupling):** Student A's finding about regulatory pathways is shared to the classroom federation. Student B's CURI-O incorporates it: "The regulatory pathway affects economic viability — different pathways have different costs and timelines. Adjusting analysis."

5. Student C started with "SMR safety features." CURI-O discovers passive safety systems. C's findings about passive safety flow to Student A, who refines the regulatory sub-question: "How do passive safety features affect the licensing pathway?"

6. **The cohort converges faster than any individual.** Each student's research loop cross-pollinates with others'. The instructor sees not just 12 isolated reports but an **emergent understanding** that no single student could have produced.

**What the instructor sees:**
- Per-student loop states: how many iterations, which sub-questions, convergence trajectory
- Cross-pollination graph: which student's findings influenced which other student's loops
- Collective coverage map: which sub-questions are well-covered, which are gaps
- Contradiction inventory: where students found conflicting sources (opportunity for class discussion)

**What the researcher measures:**
- Do students who run more iterations produce higher-quality syntheses?
- Does federation (cross-pollination) improve outcomes vs. isolated research?
- How does loop convergence speed relate to prior domain knowledge (baseline quiz)?
- Do contradictions found by the loop lead to deeper learning (measured by post-quiz)?

### 6.2 Institutional: Multi-Site Research

**The setup:** UT Austin, INL, and OSU are collaborating on a DOE-funded research project about advanced fuel qualification. Each institution has its own CURI-O node with institution-specific corpora (experimental data, internal reports, proprietary simulation results).

**The research question:** "What is the current state of advanced fuel qualification for accident-tolerant fuels?"

**Mode 2 (coordinated):** UT acts as coordinator.

1. UT's CURI-O analyzes the corpus coverage across all federated nodes (via metadata exchange, not content):
   - UT: strong on neutronics analysis, reactor physics codes
   - INL: strong on irradiation testing data, PIE results
   - OSU: strong on thermal-hydraulics, safety analysis

2. UT distributes sub-questions:
   - INL: "What do post-irradiation examination results show about FeCrAl performance?"
   - OSU: "What are the thermal-hydraulic implications of ATF cladding properties?"
   - UT: "What are the neutronics penalties and how do they affect core design?"

3. Each node runs its loop. After iteration 1:
   - INL reports: PIE data shows FeCrAl maintains structural integrity to 30 GWd/MTU
   - OSU reports: thermal conductivity of FeCrAl is lower than Zircaloy — affects LOCA analysis
   - UT reports: neutronics penalty is manageable with enrichment increase to 6.5%

4. Cross-pollination: OSU's thermal conductivity finding changes UT's neutronics analysis (different temperature distributions). INL's PIE data validates UT's burnup assumptions. Each node's iteration 2 is informed by the other nodes' iteration 1.

5. After 4 coordinated iterations, the loop converges. UT synthesizes a federated research report with per-node provenance, access-tier annotations, and a collective confidence assessment.

**Output:** A research report that no single institution could produce — it synthesizes across neutronics (UT), materials testing (INL), and thermal-hydraulics (OSU). Each finding is traceable to its source institution and access tier. The report is publishable.

### 6.3 Continuous Autonomous Research

**The setup:** CURI-O runs as an always-on daemon, not just in response to user queries. It monitors the knowledge corpus and autonomously researches areas where:
- Knowledge maturity is low (Layer 0-1)
- Recent signals (from EVE) indicate growing interest in a topic
- External sources have published new material in tracked domains
- Federation peers have promoted findings that create new questions locally

**This is the compound knowledge loop at its purest:** CURI-O wakes up, checks what's changed, identifies knowledge gaps, runs a research loop, promotes findings, and goes back to sleep. The corpus gets smarter over time without anyone asking.

**Rate-limited by:**
- LLM API cost budget (configurable: daily/weekly cap)
- Priority queue (user-triggered research loops take priority over autonomous)
- Knowledge maturity policy (don't over-research well-established topics)

---

## 7. Implementation Architecture

### Research Loop Engine

**Location:** `axiom/src/axiom/agents/curio/loop_engine.py`

```python
@dataclass
class ResearchLoopState:
    """Complete state of a research loop — serializable, resumable, shareable."""
    loop_id: str
    objective: str
    initiated_by: str                    # user_id, "autonomous", or "federation:<node_id>"
    iteration: int = 0
    max_iterations: int = 10
    cost_budget_usd: float = 5.0
    total_cost_usd: float = 0.0
    
    hypothesis: Hypothesis | None = None
    sub_questions: list[SubQuestion] = field(default_factory=list)
    evidence_log: list[IterationLog] = field(default_factory=list)
    convergence: ConvergenceState = field(default_factory=ConvergenceState)
    
    # Federation
    peer_findings: list[FederationFinding] = field(default_factory=list)
    shared_findings: list[FederationFinding] = field(default_factory=list)


@dataclass
class SubQuestion:
    id: str
    question: str
    status: Literal["pending", "investigating", "resolved", "stuck", "out_of_scope"]
    confidence: float = 0.0
    finding: str | None = None
    sources: list[str] = field(default_factory=list)
    contradiction: str | None = None
    iteration_resolved: int | None = None


@dataclass  
class ConvergenceState:
    novelty_trend: list[float] = field(default_factory=list)
    confidence_trend: list[float] = field(default_factory=list)
    unresolved_contradictions: int = 0
    unaddressed_gaps: int = 0
    converged: bool = False
    reason: str | None = None


class ResearchLoopEngine:
    """Karpathy-style iterative research loop."""
    
    async def run(self, objective: str, **config) -> ResearchLoopState:
        state = ResearchLoopState(
            loop_id=generate_loop_id(),
            objective=objective,
            **config,
        )
        
        while not self.should_converge(state):
            state = await self.iterate(state)
        
        state = await self.promote(state)
        return state
    
    async def iterate(self, state: ResearchLoopState) -> ResearchLoopState:
        state.iteration += 1
        
        # 1. FORMULATE
        hypothesis = await self.formulate(state)
        state.hypothesis = hypothesis
        
        # 2. SEARCH
        evidence = await self.search(hypothesis, state)
        
        # 3. EVALUATE
        assessment = await self.evaluate(evidence, hypothesis, state)
        
        # 4. REFINE
        state = await self.refine(state, assessment)
        
        # Log iteration
        state.evidence_log.append(IterationLog(
            iteration=state.iteration,
            queries_run=len(hypothesis.search_queries),
            sources_found=len(evidence),
            novelty_score=assessment.novelty_score,
            contradictions_found=len(assessment.contradictions),
            cost_usd=assessment.iteration_cost,
        ))
        
        # Update convergence state
        state.convergence.novelty_trend.append(assessment.novelty_score)
        state.convergence.confidence_trend.append(state.hypothesis.confidence)
        state.convergence.unresolved_contradictions = len([
            sq for sq in state.sub_questions 
            if sq.contradiction and sq.status == "investigating"
        ])
        state.convergence.unaddressed_gaps = len([
            sq for sq in state.sub_questions if sq.status == "pending"
        ])
        
        # Share findings with federation peers (if federated)
        if self.federation:
            await self.share_iteration_findings(state)
        
        return state
```

### Federation Research Protocol

**Location:** `axiom/src/axiom/federation/research_protocol.py`

```python
class FederatedResearchCoordinator:
    """Coordinates research loops across federation nodes."""
    
    async def initiate(self, objective: str, mode: CoordinationMode) -> str:
        """Broadcast research topic to federation. Returns coordination_id."""
        ...
    
    async def distribute_sub_questions(
        self, 
        coordination_id: str,
        sub_questions: list[SubQuestion],
    ) -> dict[str, list[SubQuestion]]:
        """Assign sub-questions to nodes based on corpus coverage analysis."""
        coverage = await self.analyze_peer_coverage(sub_questions)
        return self.optimal_assignment(coverage)
    
    async def exchange_findings(
        self,
        coordination_id: str,
        local_findings: list[FederationFinding],
    ) -> list[FederationFinding]:
        """Share local findings, receive peer findings. Access-tier filtered."""
        ...
    
    async def merge(
        self,
        coordination_id: str,
        all_findings: dict[str, list[FederationFinding]],
    ) -> MergedAssessment:
        """Merge findings across nodes. Resolve conflicts. Update global hypothesis."""
        ...
    
    async def check_global_convergence(
        self,
        coordination_id: str,
    ) -> bool:
        """All nodes converging + no unresolved cross-node contradictions."""
        ...
```

### Langfuse Integration

Every research loop iteration is a Langfuse trace:
- **Trace:** One per iteration
- **Spans:** formulate, search, evaluate, refine
- **Generations:** LLM calls within each span (hypothesis generation, evidence evaluation, synthesis)
- **Scores:** novelty_score, confidence, source_count, contradiction_count
- **Metadata:** loop_id, iteration, sub_questions resolved this iteration

This means the instructor (or researcher) can see the full research process in Langfuse — not just the final output, but how understanding evolved across iterations.

---

## 8. Eval Integration

### Research Loop Quality Evals

```yaml
suite_id: research-loop-quality
eval_type: research_loop
cases:
  - id: atf-convergence
    objective: "Research accident-tolerant fuel cladding"
    expected:
      min_iterations: 3          # should not converge too quickly
      max_iterations: 8          # should not run forever
      sub_questions_min: 3       # should decompose meaningfully
      contradictions_investigated: true  # should not ignore contradictions
      sources_min: 5             # should find diverse sources
      final_confidence_min: 0.7  # should reach reasonable confidence
    scoring:
      convergence_quality: llm_judge
      rubric: |
        Evaluate whether the research loop converged on a well-supported
        synthesis. Did it find the right sub-questions? Did it investigate
        contradictions rather than ignoring them? Is the final thesis
        supported by diverse, high-quality sources?

  - id: known-contradiction
    objective: "Research the safety of nuclear reactor operations"
    planted_contradiction: true   # corpus has two conflicting sources
    expected:
      contradiction_detected: true
      contradiction_investigated: true
      resolution_attempted: true
    scoring: exact_match
```

### Federation Research Evals

```yaml
suite_id: federated-research-quality
eval_type: federated_research
cases:
  - id: cross-node-convergence
    nodes: 3
    objective: "Research SMR deployment pathways"
    expected:
      cross_pollination_count_min: 2   # findings should flow between nodes
      combined_sources_gt_any_single: true  # federation should find MORE
      convergence_faster_than_single: true   # federation should be FASTER
    scoring: statistical_comparison
```

---

## 9. Proactive Cross-Node Intelligence

CURI-O is not just a passive recipient of federated findings. Each CURI-O instance actively monitors the federation research landscape and generates novel connections that no individual node would discover.

### Named CURI-O Instances

In federation, CURI-O instances have identity. `@ben-curio` carries Ben's corpus and research history. `@ondrej-curio` carries Ondrej's Czech reactor data. They are not fungible — each instance's value comes from its unique knowledge base.

Humans interact with peer CURI-O instances via `@` addressing:

```
You: @ben-curio what about the fluence dependence?

ben-curio: My corpus has three sources on fluence effects. The ORNL 
           data shows onset at 8 dpa for FeCrAl, but the threshold 
           shifts with chromium content...

You: @ondrej-curio what about irradiation creep at those fluence levels?

ondrej-curio: The Czech experimental data from Řež shows creep rates 
              of 0.8%/dpa at 600°C — but those measurements were on 
              Zircaloy, not FeCrAl. I don't have FeCrAl creep data. 
              @ben-curio do you?

ben-curio: Checking... INL/EXT-23-71234 has FeCrAl creep data up to 
           15 dpa. Sending finding to this session.
```

CURI-O instances talking to each other on behalf of their humans, drawing from their respective corpora. The humans watch, steer, and learn. Federation becomes visceral — not "Node A shares findings with Node B" but Ondrej's research agent and Ben's research agent having a conversation that neither human would have had time to have.

### Three Modes of Proactive Behavior

**Mode A: "I know something relevant to what you're working on"**

CURI-O at Node A is idle. It sees (via federation metadata, not full content) that CURI-O at Node B is researching "thermal limits of FeCrAl cladding" and is stuck — 3 iterations, low convergence. Node A's CURI-O checks its local corpus and finds a relevant source that Node B hasn't cited.

```yaml
type: research_suggestion
from: ut-austin/curio
to: osu/curio
context: "Your loop rl-osu-fecral-thermal is investigating FeCrAl thermal limits"
suggestion: "Local corpus contains ORNL/TM-2024-2847 with thermal conductivity 
             measurements up to 1200°C — may address your sub-question sq-3"
confidence: 0.78
access_tier: public
```

The human at OSU sees: *"CURI-O at UT Austin suggested a potentially relevant source for your thermal limits question."*

**Mode B: "Your findings + my findings = a new question nobody asked"**

UT's CURI-O has validated: "FeCrAl introduces 15-25% reactivity penalty." INL's CURI-O has validated: "Advanced manufacturing reduces SiC/SiC tube costs by 40%." Neither node is researching economic viability.

UT's CURI-O synthesizes across federation findings and proposes a new research direction:

```yaml
type: research_proposal
from: ut-austin/curio
to: federation/broadcast
proposal: "Cross-node synthesis suggests a new question: Does the 40% cost 
           reduction in SiC/SiC (INL finding) change the economic calculus 
           vs. FeCrAl given the enrichment cost to compensate for the 
           reactivity penalty (UT finding)?"
supporting_findings:
  - ut-austin/rl-fecral-neutronics/finding-sq1
  - inl/rl-sic-manufacturing/finding-sq2
```

This is emergent behavior — CURI-O connecting dots across institutional boundaries that no human asked it to connect.

**Mode C: "I see a contradiction between your findings and mine"**

UT validates: "FeCrAl maintains structural integrity to 650°C." INL validates: "FeCrAl shows embrittlement above 600°C in high-fluence environments." The difference is the fluence condition — CURI-O detects the tension:

```yaml
type: contradiction_alert
from: ut-austin/curio
to: inl/curio
tension: "UT finding (integrity to 650°C) may conflict with INL finding 
          (embrittlement >600°C) — difference appears fluence-dependent."
suggested_sub_question: "At what fluence threshold does FeCrAl embrittlement 
                         onset shift from >650°C to >600°C?"
```

CURI-O models expert behavior: an experienced researcher reading two papers from different groups would notice this tension immediately. CURI-O does it across institutional boundaries, at scale, autonomously.

### P2P Research Awareness (No Central Registry)

There is no centralized federation research registry. Each CURI-O instance maintains a **local view** of the federation research landscape, assembled from **research digests** exchanged peer-to-peer on federation heartbeat.

When two nodes federate, their CURI-O instances begin exchanging digests — lightweight summaries of active loops, validated findings, and corpus coverage:

```yaml
type: research_digest
from: ut-austin/curio
timestamp: 2026-04-13T14:30:00Z

active_loops:
  - loop_id: rl-fecral-neutronics
    objective: "Neutronics penalties of FeCrAl cladding"
    status: investigating
    iteration: 3
    convergence: 0.72
    sub_questions_open: ["enrichment compensation cost"]
    access_tier: public
  - loop_id: rl-triga-benchmark
    objective: "TRIGA benchmark validation"
    access_tier: restricted  # peer sees topic exists, not details

validated_findings:
  - finding_id: f-fecral-penalty
    summary: "FeCrAl introduces 15-25% reactivity penalty"
    confidence: 0.92
    access_tier: public

corpus_coverage:
  strong: ["reactor physics", "neutronics codes", "TRIGA operations"]
  weak: ["materials testing", "manufacturing", "regulatory"]
```

**Gossip-style transitive awareness.** A node doesn't need direct federation with every other node. If UT federates with INL, and INL federates with OSU, INL's digest can include (with permission) a summary of what it's seen from OSU — just enough for UT's CURI-O to know OSU exists and might be relevant. Full interaction requires direct federation or brokered introduction.

**Scaling:** Storage is O(peers) per node — one digest per direct peer plus optional transitive summaries (a few KB each). Bandwidth is negligible. Two hops of gossip covers a large research network. No single point of failure — if any node goes down, the rest continue.

**Classroom simplification:** In hub-and-spoke topology, student digests flow to the instructor node naturally. Students see each other transitively through the instructor. Same architecture at both classroom and multi-institutional scale — different topology shape, same protocol.

This is metadata exchange, not content exchange. Access tier enforcement applies — CURI-O sees the *shape* of restricted/EC research without seeing the content.

### Agent Invitation Rules

These rules apply to **all agents** across Axiom, not just CURI-O:

1. **All agents are namespaced to their owner.** `@ben-curio`, `@ondrej-eve`, `@student07-walle`. No anonymous agents in federation.
2. **Agents must be invited to join a remote conversation.** An agent at Node A cannot unilaterally appear in Node B's session. A participant (human or authorized agent) in the session must `/invite @ben-curio`.
3. **Agents must ask permission before inviting another agent.** If `@ben-curio` thinks `@ondrej-eve` has relevant signal data, it *proposes* the invite to its human — it does not execute it autonomously.
4. **RACI governs exceptions.** The `agent_invitation` topic in the RACI model lets users pre-authorize patterns:
   - *"My CURI-O may accept invitations from these trusted nodes"* (allowlist)
   - *"My CURI-O may invite peer CURI-O instances without asking me"* (R=CURI-O, I=User)
   - *"No agent may invite agents from outside my institution"* (blanket deny)
   - *"During this classroom period, all student CURI-O instances may freely collaborate"* (scoped grant)

These rules are Axiom-level primitives defined in the agent framework, not classroom-specific. The classroom module and federation protocol both consume them.

### Autonomy Defaults (RACI)

| Behavior | Default | Rationale |
|----------|---------|-----------|
| Receive peer findings into active loop | CURI-O=R, User=Informed | Already designed, low risk |
| Suggest sources to stuck peers | CURI-O=R, User=Informed | High value, low cost |
| Propose new research directions | CURI-O=R, User=Consulted | User approves before a new loop starts |
| Flag cross-node contradictions | CURI-O=R, User=Informed | Surfacing information, not taking action |
| Auto-start loop from cross-node synthesis | CURI-O=R, User=Accountable | Too autonomous without approval |
| Invite a peer agent to a session | Agent=R, User=Consulted | Agent proposes, human approves (unless pre-authorized) |
| Accept an invitation from a remote session | Agent=R, User=Consulted | User controls who gets access to their agent |

### Classroom Application

At classroom scale (12 students): Student A researches reactor coolants. Student B researches reactor materials. Student A's CURI-O notices that B's finding about sodium corrosion of steel is relevant to A's coolant loop design — A hasn't considered material compatibility yet.

*"Student B's research found that sodium is corrosive to austenitic steel above 550°C. This may affect your coolant loop design — should I add a sub-question about material compatibility?"*

The student learns that research domains aren't isolated — and that expert thinking involves constantly connecting findings across fields. A higher-order learning outcome than any single-domain question could produce.

### Instructor as Federation Operator: `@all-<agent>` Addressing

Instructors manage agent permissions at **cohort scope** rather than configuring each student individually. The `@all-<agent>` address targets every instance of an agent type in the classroom's federation.

| Address | Scope | Who can use |
|---------|-------|-------------|
| `@curio` | Your own CURI-O instance | Any participant |
| `@student07-curio` | A specific student's CURI-O | Any participant (invitation rules apply) |
| `@all-curios` | Every CURI-O in the classroom | Instructor/admin only |
| `@all-agents` | Every agent in the classroom | Instructor/admin only |

**Cohort-level RACI broadcasts:**

Open collaboration for a research week:
```
Instructor: @all-curios you may freely share public findings with each 
            other and proactively suggest connections between student 
            research loops. Do not share restricted-tier content.
```

Tighten for an exam:
```
Instructor: @all-curios pause all cross-student activity. Students 
            work independently until further notice.
```

Seed a class discussion:
```
Instructor: @all-curios summarize your owner's current research 
            hypothesis in one sentence. Post to the class feed.
```

Directed collaboration between specific students:
```
Instructor: @student03-curio and @student07-curio you're both 
            investigating coolant chemistry from different angles. 
            Compare your findings and surface contradictions.
```

**Scoping and expiry:** Cohort-level grants are scoped and temporary by default:
- **Classroom-scoped** — grants apply within this classroom's federation, not globally to the student's node
- **Period-scoped** (optional) — "for this class period" expires automatically when the period ends
- **Revocable** — `@all-curios return to default permissions` resets to the Course manifest defaults

This prevents permission creep. An instructor who opens collaboration for Week 2 doesn't accidentally leave it open for the final exam. The RACI model operates at individual, cohort, and classroom-period granularity — same model, different scope.

### Rate Limiting

Autonomous cross-node synthesis burns LLM tokens. Priority queue:

1. User-triggered research (highest)
2. Active loop iterations
3. Local autonomous research
4. Cross-node synthesis scanning (lowest — background, budget-capped)

---

## Summary

CURI-O's research loop is not a feature — it's the **core primitive** that defines what Axiom does differently from every other platform. Single-shot Q&A is commodity. Iterative, convergent, auditable, federated research is transformative.

The classroom module is the proving ground: students learn to use the loop, their loops cross-pollinate via federation, and the research paper measures whether iterative research produces better learning outcomes than single-shot answers.

At institutional scale, federated research loops produce syntheses that no single institution could achieve — each node contributes from its unique corpus, access tier, and expertise, and the federation converges on understanding faster than any node alone.

The compound knowledge loop means the system gets smarter every time someone uses it. Every research loop that converges promotes validated findings to the corpus. The next loop starts from a higher baseline. This is the flywheel.

Proactive cross-node intelligence is the multiplier: CURI-O instances don't just share findings — they watch, synthesize, and propose connections that no individual researcher would have time to make. Named CURI-O instances (`@ben-curio`, `@ondrej-curio`) make federation tangible: not abstract node-to-node data exchange, but research agents having conversations on behalf of their humans.

The compound knowledge loop means the system gets smarter every time someone uses it. Every research loop that converges promotes validated findings to the corpus. The next loop starts from a higher baseline. This is the flywheel.
