> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mareforma.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Compounding Agents

> Two agents work sequentially. Knowledge accumulates in the graph instead of evaporating between runs.

<Card title="View on GitHub" icon="github" href="https://github.com/mareforma/mareforma/tree/main/examples/02_compounding_agents">
  `examples/02_compounding_agents/`
</Card>

Agent A analyses two independent runs on distinct datasets, citing the same upstream evidence.
Agent B queries the graph before asserting, finds the REPLICATED findings, and
builds a DERIVED synthesis on top. The closing act tells the same story with the
trust layer, where the support is earned rather than declared.

## Run

```bash theme={"dark"}
pip install langchain-core
cd examples/02_compounding_agents
python 02_compounding_agents.py
```

No API key required. To use a real LLM:

```python theme={"dark"}
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
agent = create_react_agent(ChatOpenAI(model="gpt-4o"), tools=[query_graph, assert_finding])
```

## Key pattern

```python theme={"dark"}
@tool
def query_graph(topic: str, min_support: str = "PRELIMINARY") -> str:
    results = graph.query(topic, min_support=min_support)
    return json.dumps([r["text"] for r in results])

@tool
def assert_finding(text: str, classification: str, supports: list[str]) -> str:
    return graph.assert_claim(
        text, classification=classification, supports=supports,
        generated_by="agent/synthesiser",
    )
```

## The trust layer

The same question, now as a structured finding. Each analyst registers a
prediction before seeing the numbers; mareforma computes the bearing and derives
the status from independent runs.

```python theme={"dark"}
from mareforma.trust import (
    Proposition, Direction, Prediction, TestType, DirectionOfInterest,
    EffectEstimate, EffectType,
)

prop = Proposition(
    subject="cell type A", relation="inhibitory connectivity onto",
    object="cell type B", direction=Direction.INCREASES,
    scope={"region": "cortex", "species": "mouse"},
)
plan = Prediction(
    test_type=TestType.SUPERIORITY,
    direction_of_interest=DirectionOfInterest.INCREASE, alpha=0.05,
)

# Analyst A on dataset_alpha: one independent line.
graph.assert_finding(prop, plan,
    EffectEstimate(estimate_value=0.42, effect_type=EffectType.SMD,
                   ci_lower=0.18, ci_upper=0.66, ci_level=0.90, n_total=842),
    data_id="dataset_alpha", generated_by="analyst/model-a/lab_a")

# Analyst B is a distinct run on a distinct dataset: a second independent line.
graph.assert_finding(prop, plan,
    EffectEstimate(estimate_value=0.51, effect_type=EffectType.SMD,
                   ci_lower=0.20, ci_upper=0.82, ci_level=0.90, n_total=1104),
    data_id="dataset_beta", generated_by="analyst/model-b/lab_b")

graph.query_frame(prop, min_status="PRELIMINARY")[0]["status"]   # "CORROBORATED"
```

Neither agent declared support. The bearing is computed from the pre-registered
rule, and `CORROBORATED` is derived from two independent runs. See
[Findings](/concepts/findings).
