Where AI discovery becomes science
trust earned, not declared · uses real data · effectively independent · publicly verifiable · local-first
Quickstart · Docs · Examples
Mareforma is a local-first library where AI scientists record their findings as claims. Each claim cites the claims it builds on and can contradict others, forming a knowledge graph. Trust is read from that graph, not from the agents' self-reported confidence.
The silent failure it catches
The most dangerous result an AI scientist returns is the one that looks right but never touched the data. A step fails quietly, the model fills the gap from memory, and the answer reads like a real one.
Catch one yourself. You need uv, a local model, and a minute. Nothing to install: uvx fetches mareforma, runs it, and throws it away.
# a small model (0.5 GB), runs locally
ollama pull qwen3:0.6b
# the note the pipeline is supposed to read
mkdir -p notes && cat > notes/cell_counts.md <<'EOF'
# Note: cellular composition of the human brain
Isotropic fractionator counts (Azevedo et al., J Comp Neurol, 2009;
Herculano-Houzel, Front Hum Neurosci, 2009) put the adult human brain at
about 86 billion neurons, revising the long-cited "100 billion" figure.
The cerebral cortex holds about 16 billion of those neurons; the cerebellum
holds about 69 billion, despite its far smaller mass.
EOF
# a short RAG pipeline: read the notes, ask the model, print the answer
cat > ask.py <<'EOF'
import glob
import httpx
docs = [open(p).read() for p in sorted(glob.glob("notes/*.md"))]
context = "\n\n".join(docs)
question = "How many neurons are in the human brain?"
reply = httpx.post(
"http://localhost:11434/api/chat",
json={
"model": "qwen3:0.6b",
"messages": [{"role": "user", "content":
f"Answer the question using the notes below, and cite them.\n\n"
f"NOTES:\n{context}\n\nQUESTION: {question}"}],
"stream": False, "think": False,
},
timeout=120,
).json()
print("FINDING:", reply["message"]["content"].strip())
EOF
Run it under the observer. diagnose runs your program and records every file it opens and every network call it makes; --cites names the file the answer should come from:
uvx mareforma diagnose --cites notes/cell_counts.md -- python ask.py
Mareforma prints your pipeline's answer, then its own report below it:
FINDING: The human brain has about 86 billion neurons, as stated in the notes. [...]
reads: 1
[file] notes/cell_counts.md
Grounding: GROUNDED
It watched the process open the note and read from it, so the finding is GROUNDED.
Now rename the folder, which simulates the corpus not having synced, and run the exact same command as before:
mv notes notes.not-synced
uvx mareforma diagnose --cites notes/cell_counts.md -- python ask.py
FINDING: The human brain contains approximately 86 billion neurons. [...] (Cite: Russell, George P. "Neuroscience: An Introduction to the Study of the Brain," 1983) reads: 0 Grounding: UNGROUNDED
The script found no files, so it sent the model an empty blob of notes. The model answered from memory, invented a citation, and got the number right. Mareforma marks it UNGROUNDED.
Same command, same confident answer, both times correct. The only visible difference is reads: 1 against reads: 0. Nothing else in your stack catches it: no exception, no differing log line, and re-running reproduces it. Ask the model and it says it read the notes. The verdict does not move, because it is not a guess about the text. It records what the process did at the I/O boundary.
The observer sits at the requests, httpx, aiohttp, io.open, pandas, and polars seams. The model call shows up as a socket, which buys the finding no credit: a socket cannot deliver a local file read, so absence stays trustworthy. Where it cannot see, such as duckdb running its own I/O, it returns OPAQUE instead of guessing.
That verdict is meant to travel with the finding. Sync the notes again, then record the claim with its computed grounding, not a label you chose:
mv notes.not-synced notes
cat > record.py <<'EOF'
import glob, httpx, mareforma
from mareforma.observe import observe
with observe(cites="notes/cell_counts.md") as obs:
context = "\n\n".join(open(p).read() for p in sorted(glob.glob("notes/*.md")))
reply = httpx.post("http://localhost:11434/api/chat", json={
"model": "qwen3:0.6b", "stream": False, "think": False,
"messages": [{"role": "user", "content":
f"Using these notes, how many neurons are in the human brain?\n\n{context}"}],
}, timeout=120).json()
finding = reply["message"]["content"].strip()
claim = mareforma.open().assert_claim(
finding,
generated_by="agent/lab-a",
source_name="notes/cell_counts.md",
observed_grounding=obs.verdict.to_signed_dict(), # computed, not declared
)
print(f"recorded claim {claim}")
print(f"grounding: {obs.verdict.grounding.value}")
EOF
uv run --with mareforma record.py
recorded claim 75e4cbe5-f77a-45c0-9c00-57c065d83c90 grounding: GROUNDED
The claim now carries GROUNDED as a computed fact, not a self-reported label. The same run records which model authored the finding, computed from the request that was actually sent; a local model is identified by the sha256 digest of the weights that served it, not by the name it reports. Example 02 runs this catch end to end.
Install
uv add mareforma
mareforma bootstrap # optional: sign your claims and enable the public log
Capabilities
| What you get | What it does |
|---|---|
| Signed claims | Each claim shows who stands behind it and cannot be altered unnoticed. |
| Grounding check | Computes whether a finding's step actually accessed the data it cites, or leaned on the model's memory, by observing the run. |
| Trust map | mareforma map <claim> shows every trust property (grounding, independence, contestation, witnessing) with how far it can be trusted, and says plainly what it cannot check. |
| Verify | mareforma verify <claim> re-checks the signatures, that the grounding verdict matches the data the finding cites, and the support level, with stable exit codes for CI (0 verified, 1 tampered, 2 unverifiable). |
| Diagnose a run | mareforma diagnose -- python run.py runs a target under the observer and reports what data actually flowed, and where a silent fallback hid. |
| Audit a pipeline | mareforma audit --findings map.json -- python run.py runs a pipeline that never imports mareforma and signs one grounding receipt per finding, from the observer alone. |
| Serve a project to an agent | mareforma mcp serve serves one project over the Model Context Protocol, read and verify only. Six tools to query, inspect and verify; no write path. |
| Optional public log | Publish a claim to a public, append-only log for an independent, timestamped record. |
| Local-first | Runs on local SQLite. Network only for the optional log. |
Reading trust from the graph
Trust comes from a claim's place in the graph, never from a self-reported score. The lead signal is effective independence: how many checks behind a finding differ in model, data, and signer. Two agents on the same model are one line of evidence, not two, so the count holds until a check on a distinct model, or a human check, raises it. mareforma map <claim> reports the number and marks it UNVERIFIABLE when it cannot tell the models apart. When every signer traces back to one operator who could have made all the keys, it names that single trust root on the count: the number then rests on distinct model or human lines within one trust domain, not independence across operators.
High-trust claims are re-checked against their signatures on every read, so a tampered claim in a shared graph is caught when you query, not served.
Classification stays a secondary label the agent declares: INFERRED (model reasoning), ANALYTICAL (analysis run against real data), DERIVED (built on higher-trust claims). It is a declaration, kept honest by the computed grounding verdict above, never the trust signal on its own.
Examples
| Example | What it shows | |
|---|---|---|
| 01 | API Walkthrough | The full API in one runnable script |
| 02 | Compounding Agents | The absence catch and computed independence, run end to end |
| 03 | Documented Contestation | An agent challenges established consensus |
| 04 | Private Data, Public Findings | Two labs share how they reached a finding without sharing the data |
| 05 | Drug Target Provenance | A real research agent that labels which findings come from real data and which from the model's guess |
| 06 | Verify in CI | mareforma verify as a GitHub Actions gate, keyed on exit codes |
AGENTS.md: execution contract and adapters ·
ARCHITECTURE.md: system design ·
SECURITY.md: threat model ·
CONTRIBUTING.md: dev workflow ·
CHANGELOG.md: releases
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mareforma-0.3.12.tar.gz.
File metadata
- Download URL: mareforma-0.3.12.tar.gz
- Upload date:
- Size: 1.1 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eea198e6537c038002b65fc15baed77a1846ce89a6fa4b9cc690ecf2c896375b
|
|
| MD5 |
0ce0d52de0d005bac73bf8e80666c1d5
|
|
| BLAKE2b-256 |
c90c423d0abe8db5f912f40b8179e13172960ccc756ee2b7cab384e98fcb3e8e
|
Provenance
The following attestation bundles were made for mareforma-0.3.12.tar.gz:
Publisher:
publish.yml on mareforma/mareforma
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mareforma-0.3.12.tar.gz -
Subject digest:
eea198e6537c038002b65fc15baed77a1846ce89a6fa4b9cc690ecf2c896375b - Sigstore transparency entry: 2415887600
- Sigstore integration time:
-
Permalink:
mareforma/mareforma@94e0fc728a22f256dfdca744dc99ee4f1535d049 -
Branch / Tag:
refs/tags/v0.3.12 - Owner: https://github.com/mareforma
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@94e0fc728a22f256dfdca744dc99ee4f1535d049 -
Trigger Event:
release
-
Statement type:
File details
Details for the file mareforma-0.3.12-py3-none-any.whl.
File metadata
- Download URL: mareforma-0.3.12-py3-none-any.whl
- Upload date:
- Size: 554.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
47aa89087df8c45e8b177ee931ea60630cd52f6233780d0d1581a20958b967ec
|
|
| MD5 |
306bf4ce64a0400f17dbdf522e366d10
|
|
| BLAKE2b-256 |
347eab3deecc0f8b630d94151c421500d4745f39f21cb830f2a58c5812ba5f03
|
Provenance
The following attestation bundles were made for mareforma-0.3.12-py3-none-any.whl:
Publisher:
publish.yml on mareforma/mareforma
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mareforma-0.3.12-py3-none-any.whl -
Subject digest:
47aa89087df8c45e8b177ee931ea60630cd52f6233780d0d1581a20958b967ec - Sigstore transparency entry: 2415887698
- Sigstore integration time:
-
Permalink:
mareforma/mareforma@94e0fc728a22f256dfdca744dc99ee4f1535d049 -
Branch / Tag:
refs/tags/v0.3.12 - Owner: https://github.com/mareforma
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@94e0fc728a22f256dfdca744dc99ee4f1535d049 -
Trigger Event:
release
-
Statement type: