Installation
pip install hypgraph # engine, CLI, JSON API, UI — standard library only pip install "hypgraph[mcp]" # + the MCP server (FastMCP)
Python 3.10+. Eine SQLite-Datei pro Protokoll (Graph("research.hypgraph")) oder Graph() im Speicher für Tests und Notebooks.
Das Modell
Typisierte Knoten — Frage, Hypothese, Experiment, Lauf, Ergebnis, Behauptung, Quelle, Prüfung, Entscheidung — verbunden durch typisierte Verknüpfungen, deren Endpunkte durchgesetzt werden (supports, challenges, requires, tests, produced, replicates, based_on …). Alle Tabellen sind nur anhängend; jeder Schreibvorgang ist ein Ereignis in einer SHA-256-Kette. Kein Stand wird gespeichert. Jedes Lesen leitet ab:
- Prüfung — geprüft / ungeprüft / angefochten / veraltet, aus den Urteilen der Prüfer zur aktuellen Version;
- Risiko — vorgelagert gefallene Prämissen (
AT RISK), Entscheidungen, deren Grundlage sich bewegt hat (REVISIT), alle Stützung gefallen (UNSUPPORTED); - unabhängige Linien — Stützen, die weder Lauf noch Datenartefakt noch Quelle teilen;
- Belege — die stärkste Linie: von einem Agenten gemeldet → vom Instrument aufgezeichnet → reproduziert → unabhängige Implementierung → neue Daten → externe Quelle.
Die vollständigen Regeln stehen im Protokollformat; hypgraph schema --json gibt das Vokabular aus.
Richtlinie und Rollen
from hypgraph import Graph, Policy
POLICY = Policy(
reviewers={"critic", "stats-reviewer"}, # whose verdicts count (an investigation can add its own)
instrument="runner", # the only author whose kind=lab runs are "recorded" evidence
operator="operator", # revises anything, settles disputes
importer="importer", # brings legacy records in, with their original dates
)
g = Graph("research.hypgraph", policy=POLICY)author= beim Wort. Wo immer ein Agent den Graphen erreicht, setzen Sie seinen Autor auf Ihrer Seite fest und lehnen POLICY.reserved ab — genau das tun der mitgelieferte MCP-Server und die HTTP-API.Ein Muster, das für ein Team von Agenten funktioniert:
| Rolle in Ihrem System | in HypGraph |
|---|---|
| arbeitende Agenten (Forscher, Analysten) | jeder unter eigenem Autorennamen; ihre Behauptungen werden geprüft; ihre Prüfungen sind Kommentare |
| Kritiker- / Prüfer-Agenten | reviewers; ihre Urteile setzen den Stand; nie über ihre eigenen Knoten |
| der Job-Ausführer / die Sandbox, die Code ausführt | instrument: zeichnet Läufe mit Hashes auf, damit Ergebnisse als aufgezeichnet zählen |
| Sie selbst oder ein Orchestrator, der für Sie handelt | operator |
Agenten verbinden
MCP
Ein Serverprozess pro Agentenidentität — der Autor wird beim Start festgelegt:
hypgraph --db research.hypgraph --as critic mcp # stdio hypgraph --db research.hypgraph --as worker-1 mcp --transport http --port 8766 # streamable HTTP
Oder bauen Sie ihn im Prozess (eigene Richtlinie, eigene Authentifizierung): hypgraph.mcp.build(graph, author="worker-1") gibt den FastMCP-Server zurück.
Ausführbare Beispiele, dieselbe Geschichte auf sechs Arten eingebunden (LangChain, LangGraph, PydanticAI, CrewAI, OpenAI Agents SDK, Claude Agent SDK): examples/frameworks. Jedes läuft offline mit einem geskripteten Modell oder mit --real auf einem echten.
Agent Skill
hypgraph skill --install schreibt .claude/skills/hypgraph/SKILL.md: die Methode, die Ablehnungen und ihre Korrekturen, über die CLI.
Ihre eigenen Werkzeuge
Jedes Framework, das Python-Funktionen als Werkzeuge annimmt (Claude Agent SDK, LangChain, LangGraph, OpenAI Agents …) — geben Sie den Ablehnungstext zurück, damit das Modell darauf reagieren kann:
from hypgraph import GraphError
def add_claim(statement: str, scope: str, result: str, measurements: list[dict], why: str) -> str:
"""Add a claim supported by a result; every number in the statement must be bound in measurements."""
try:
n = g.create(author=AGENT_NAME, type="claim", inv=INV,
fields={"statement": statement, "scope": scope, "measurements": measurements},
links=[{"rel": "supports", "from": result, "why": why}])
return f"Added {n['code']}: {n['state']['sentence']}"
except GraphError as e:
return f"Refused — fix this and retry:\n{e}"Legen Sie g.report(inv)["markdown"] oder den MCP-Text overview zu Beginn einer Aufgabe in den Kontext des Agenten, damit er liest, was feststeht, bevor er es neu herleitet.
Läufe aufzeichnen
from hypgraph import file_sha256
data, code = file_sha256("evals/heldout.jsonl"), file_sha256("eval.py")
a_data = g.create(author="runner", type="artifact", inv=INV, fields={**data, "format": "jsonl"})["id"]
a_code = g.create(author="runner", type="artifact", inv=INV, fields={**code, "format": "py"})["id"]
run = g.create(author="runner", type="run", inv=INV, fields={"kind": "lab", "state": "succeeded", "seed": 7},
links=[{"rel": "uses", "to": a_data, "data": {"role": "data"}},
{"rel": "uses", "to": a_code, "data": {"role": "code"}}])["id"]
res = g.create(author="runner", type="result", inv=INV, links=[{"rel": "produced", "from": run}],
fields={"summary": "Held-out accuracy, fine-tune vs baseline.",
"values": {"finetune": {"k": 1624, "n": 2000}, "baseline": {"k": 1568, "n": 2000}}})["id"]Artefakte werden über ihren Inhalt adressiert (gleiche Bytes, ein Knoten), daher verschmelzen zwei Ergebnisse aus denselben Daten automatisch zu einer Beleglinie. Ein erneuter Lauf verknüpft replicates mit data.differs (new_seed, new_impl, new_data …) und hebt das Belegprofil an.
Profile und Workflows
Setzen Sie ein Profil auf die Untersuchung, und das Protokoll setzt die Regeln dieser Disziplin durch — und mit den Profilen @2 ihren Workflow: Phasen mit Schranken, was Belege ungültig macht, die typisierten Formen, die ein Diff, eine Instanz, eine Quelle oder eine Position haben müssen. Die Phase wird bei jedem Lesen abgeleitet, wie der Stand.
inv = g.create(author="operator", type="investigation",
fields={"title": "Issue 412", "objective": "Fix the importer and prove it.", "profile": "software@2"})["id"]
q = g.create(author="operator", type="question", inv=inv, fields={"text": "Does the importer keep quoted commas?"})["id"]
g.stage(q) # {"stage": "implemented", "index": 2, "of": 6, "complete": False,
# "next": "no live artifact kind=diff (meta: base_sha, head_sha, files) part_of Q1", "gates": [...]}
g.stages(inv) # one row per live question; GET /api/graph/stages?inv=… · MCP tool: stage
g.completion(inv) # the profile's criteria for the whole investigation- Schranken sind Prädikate.
hypothesis_stated,preregistered,diff_registered,tests_pass_current,backtested,positioned,still_valid,solved,result_reviewed… — auch alsdone_wheneines Auftrags verwendbar. - Was ungültig macht. Zusätzlich zu den Prämissen fügt ein Workflow
uses(eine korrigierte Datendatei, ein ersetzter Diff oder eine ersetzte Instanz) odercites(eine zurückgezogene Quelle) zu dem hinzu, was Abhängige GEFÄHRDET — pro Profil, daher behalten Protokolle unter@1genau den Stand, den sie hatten. - Aktualität. Ein Ergebnis, dessen Lauf ein inzwischen ersetztes Artefakt verwendet hat oder dessen
valid_untilverstrichen ist, ist VERALTET; eine Behauptung ist veraltet, wenn alle sie stützenden Ergebnisse es sind. Eine Prüfung auf veralteten Belegen erfülltreviewednicht. - Typisierte Formen.
artifact.kind+meta(eindiffbraucht base_sha, head_sha, files),source.kind,decision.kind=positionmit size, stop, review_date, paper — abgelehnt, wenn unvollständig. Dieselben Bytes erneut aufzuzeichnen typisiert ein untypisiertes Artefakt und fügt die genannten Verknüpfungen hinzu. - Ehrliche Abschlüsse. Eine geprüfte
inconclusive-Antwort, eineno_position-Entscheidung, ein verifizierter Fehlschlag (ein vom Instrument aufgezeichnetes negatives Ergebnis, geprüft) schließen jeweils eine Frage ab, die die Schranken allein nie abschließen würden.
Die Methode, aus der jeder Workflow stammt, und die Entscheidung hinter jeder Schranke haben jeweils eine Seite in docs/workflows. Der Planer von HypSwarm erstellt den Phasenauftrag jeder Frage genau daraus.
Rezept: Evaluationsberichte, die halten
- Präregistrieren. Ein Experiment mit
tests-Verknüpfungen zu jeder Hypothese („das Fine-Tuning ist besser“, „kein Unterschied“), jede mitdata.expected, vor dem Lauf. - Zeichnen Sie den Lauf auf wie oben; tragen Sie die Zählungen als
{k, n}in die Werte des Ergebnisses ein, nicht nur Prozente. - Behaupten Sie mit Messungen. „1.624 von 2.000 gegenüber 1.568“ ist gebunden; „5 Punkte besser“ ohne Ergebnisfeld für die 5 wird abgelehnt.
- „Kein Unterschied“ braucht Teststärke. Pflanzen Sie einen bekannten Effekt ein (fügen Sie einer Kopie der Vorhersagen einen Unterschied von 2 Punkten hinzu), zeigen Sie, dass der Vergleich ihn bei dieser Stichprobengröße erkennt, und markieren Sie dieses Ergebnis als
power: "demonstrated". Ohne das zeichnen Sie die Behauptung alsinconclusiveauf — das Protokoll besteht darauf. - Prüfung. Ein Kritiker-Agent führt den Bewerter erneut auf den gespeicherten Vorhersagen aus; sein
passoderfailwird an diese Version der Behauptung geheftet. - Bericht.
g.report(inv)["markdown"]ist die Faktentabelle für den Anfang des Berichts; sie kann keine zurückgezogene Behauptung erneut aufstellen.
Kosten
def spend(inv, tasks, since=None): # your meter: model calls per task id
rows = ledger.calls(task_ids=tasks, since=since)
return {"usd": sum(r.usd for r in rows), "calls": len(rows), "input_tokens": ..., "cached_tokens": ...,
"output_tokens": ..., "by_task": [{"task_id": t, "usd": ...} for t in tasks]}
g = Graph("research.hypgraph", policy=POLICY, spend=spend)
with g.writing_for(task_id): # events carry the task
g.create(...)
g.cost(inv) # $ for the investigation, per node, per verdict, and since the record last movedHTTP und die Oberfläche
hypgraph serve --db research.hypgraph # HypGraph UI + JSON API on 127.0.0.1:8765, read-only hypgraph serve --db research.hypgraph --writable # + POST /api/graph/write
In Ihrer eigenen App (gezeigt mit FastAPI; jedes Framework geht):
from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from hypgraph.server import dispatch
from hypgraph.ui import static_dir
app = FastAPI()
app.mount("/hypgraph", StaticFiles(directory=static_dir(), html=True))
@app.get("/api/graph/{path:path}")
def graph_api(path: str, request: Request):
status, body = dispatch(g, "GET", "/" + path, dict(request.query_params))
return body # (set the status code too)Die Oberfläche braucht kein Framework und keinen Build-Schritt: HypGraph.mount(el, {source: HypGraph.HttpSource('/api/graph')}) oder HypGraph.BundleSource(bundle) ganz ohne Server. Sie verfolgt GET /api/graph/stream live, und die Telemetrie eines HypSwarm-Laufs (<record>.telemetry.jsonl) ergänzt jeden Modell- und Werkzeugaufruf. hypgraph export --telemetry trägt sie zum Abspielen in einem Bundle, außerhalb der Hash-Kette; {play: true} öffnet im Abspielmodus. Gestalten Sie sie mit den CSS-Variablen --hg-*. Sehen Sie sie in den Live-Beispielen.
Bundles in der CI
hypgraph export -o record.bundle.json # every event as the exact string that was hashed hypgraph verify record.bundle.json # exit 1 if anything was edited
Veröffentlichen Sie den head-Hash des Bundles an einer Stelle, die Sie nicht kontrollieren (ein Tag, ein Paper, ein Ticket), wenn ein Ergebnis veröffentlicht wird: Ein späteres Protokoll, das durch diesen Hash läuft, kann nichts Früheres umgeschrieben haben. Prüfer können ein Bundle unter /verify prüfen, ohne etwas zu installieren.
Den Bericht prüfen
Der meiste Hype steckt im Abschlussbericht, nicht im Protokoll. hypgraph check liest Markdown gegen das Protokoll und endet bei Fehlern mit 1, sodass die Zusammenfassung, die ein Agent abgibt, dem nicht widersprechen kann, was tatsächlich gezeigt wurde:
hypgraph check summary.md # errors fail hypgraph check --strict summary.md # warnings (unsourced numbers …) fail too
| Fehler | erkennt |
|---|---|
REPORT_OVERSTATES_STANDING | „gesichert“ / „bestätigt“ für eine Behauptung, die das Protokoll als ungeprüft, angefochten oder gefährdet führt |
REPORT_CITES_WITHDRAWN | eine zurückgezogene Behauptung zitieren, als hätte sie noch Bestand |
REPORT_UNKNOWN_CODE | ein Zitat einer Behauptung oder eines Ergebnisses, das es nicht gibt |
REPORT_ABSOLUTE_UNBACKED · REPORT_ABSENCE_UNBACKED · REPORT_SIGNIFICANCE_UNBACKED | nie / kein Effekt / signifikant ohne etwas Zitiertes dahinter |
Warnungen: Zahlen, die kein Ergebnis enthält oder impliziert, ausgelassene Streitpunkte, ersetzte Zitate, kausale Sprache ohne Zitate. Codeblöcke, Inline-Code, URLs, zitierte Passagen, Verneinungen („lässt sich nicht zeigen“) und Anweisungen („verwende nie den Evaluationsdatensatz“) werden nicht als Behauptungen behandelt — kalibriert an zwei Dutzend echten Berichten, geprüft gegen das lebende Protokoll, über das sie berichten. In Python: g.check_text(text, inv); über HTTP: POST /api/graph/check; für Agenten: das MCP-Werkzeug check_report.
Das Ablehnungs-Log
Jede abgelehnte Behauptung wird aufgezeichnet — Autor, Aussage, Codes — und als korrigiert markiert, wenn derselbe Autor mit der ehrlichen Fassung zurückkommt. Das ist die Zahl, die Ihnen sonst niemand zeigen kann: wie oft Ihre Agenten versucht haben zu übertreiben, welche Regeln sie gestoppt haben und welche sie stillschweigend aufgegeben haben.
hypgraph refusals # per author and rule, fixed vs open hypgraph refusals --author analyst # one agent's refusals in full
Nur anhängend, mit eigener Hash-Kette (g.verify_refusals()), getrennt von der des Protokolls. In Python: g.refusal_report(inv); HTTP GET /api/graph/refusals; MCP refusal_log; und eine Zählung abgelehnter Überbehauptungen in der HypGraph-Übersicht.
Leistung
| Knoten | den gesamten Stand ableiten | einen Knoten lesen | schreiben | die Kette verifizieren |
|---|---|---|---|---|
| 1,001 | 0.047 s | 0.1 ms | 5.7 ms | 0.028 s |
| 3,301 | 0.095 s | 0.07 ms | 6.0 ms | 0.07 s |
| 10,001 | 0.37 s | 0.07 ms | 11.4 ms | 0.21 s |
Reines Python, gemessen mit python dev/bench.py --nodes N auf einem Windows-Laptop (Python 3.13, hypgraph 0.6). Sein Protokoll ist eine Untersuchung aus Fragen, an Werte gebundenen Ergebnissen, daraus abgeleiteten Behauptungen und Prüfungen einiger davon; die Ableitung wächst im selben Tempo wie das Protokoll. Ein Schreibvorgang kostet, was er berührt: Snapshots teilen die unberührten Daten, und der zwischengespeicherte Stand bleibt für jeden Knoten erhalten, den der Schreibvorgang nicht erreichen kann (geprüft gegen einen vollständigen Neuaufbau mit einer randomisierten Testsuite). Das meiste eines Schreibvorgangs ist SQLite, das auf die Platte schreibt. Führen Sie den Benchmark auf Ihrem Rechner und in Ihren Größen aus.