Esta página es una traducción. La versión en inglés es la de referencia: English

Para ingenieros y científicos

Dales a tus agentes un registro al que no puedan halagar.

Un paquete de Python, sin dependencias. Tú decides quién revisa, qué ejecuciones cuentan como registradas y cuánto cuesta el trabajo; HypGraph lo aplica, comprueba cada afirmación al escribirse y deriva lo que de verdad se ha demostrado.

Instalación

pip install hypgraph            # engine, CLI, JSON API, UI — standard library only
pip install "hypgraph[mcp]"     # + the MCP server (FastMCP)

Python 3.10+. Un archivo SQLite por registro (Graph("research.hypgraph")), o Graph() en memoria para pruebas y notebooks.

El modelo

Nodos tipados — pregunta, hipótesis, experimento, ejecución, resultado, afirmación, fuente, revisión, decisión — unidos por enlaces tipados cuyos extremos se hacen cumplir (supports, challenges, requires, tests, produced, replicates, based_on …). Todas las tablas son de solo anexión; cada escritura es un evento en una cadena SHA-256. Nada de la situación se almacena. Cada lectura deriva:

  • revisión — comprobado / sin comprobar / impugnado / desactualizado, a partir de los veredictos de los revisores sobre la versión actual;
  • riesgo — premisas caídas aguas arriba (AT RISK), decisiones cuya base se movió (REVISIT), todo el apoyo caído (UNSUPPORTED);
  • líneas independientes — apoyos que no comparten ejecución, artefacto de datos ni fuente;
  • evidencia — la línea más fuerte: notificada por un agente → registrada por el instrumento → reproducida → implementación independiente → datos nuevos → fuente externa.

Las reglas completas están en el formato del registro; hypgraph schema --json imprime el vocabulario.

Política y roles

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)
La autenticación es cosa tuya. HypGraph toma author= al pie de la letra. Allí donde un agente llegue al grafo, fija su autor de tu lado y rechaza POLICY.reserved — eso es lo que hacen el servidor MCP incluido y la API HTTP.

Un patrón que funciona para un equipo de agentes:

rol en tu sistemaen HypGraph
agentes trabajadores (investigadores, analistas)cada uno con su propio nombre de autor; sus afirmaciones se comprueban; sus revisiones son comentarios
agentes críticos / revisoresreviewers; sus veredictos fijan la situación; nunca sobre sus propios nodos
el ejecutor de trabajos / sandbox que ejecuta códigoinstrument: registra ejecuciones con hashes, así que los resultados cuentan como registrados
tú, o un orquestador que actúa en tu nombreoperator

Conectar agentes

MCP

Un proceso de servidor por identidad de agente — el autor se fija al arrancar:

hypgraph --db research.hypgraph --as critic mcp                                # stdio
hypgraph --db research.hypgraph --as worker-1 mcp --transport http --port 8766 # streamable HTTP

O constrúyelo dentro del proceso (política propia, tu propia autenticación): hypgraph.mcp.build(graph, author="worker-1") devuelve el servidor FastMCP.

Ejemplos ejecutables, la misma historia integrada de seis formas (LangChain, LangGraph, PydanticAI, CrewAI, OpenAI Agents SDK, Claude Agent SDK): examples/frameworks. Cada uno funciona sin conexión con un modelo guionizado, o con --real sobre uno real.

Agent Skill

hypgraph skill --install escribe .claude/skills/hypgraph/SKILL.md: el método, los rechazos y sus correcciones, a través de la CLI.

Tus propias herramientas

Cualquier framework que acepte funciones de Python como herramientas (Claude Agent SDK, LangChain, LangGraph, OpenAI Agents …) — devuelve el texto del rechazo para que el modelo pueda actuar en consecuencia:

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}"

Pon g.report(inv)["markdown"] o el texto MCP overview en el contexto del agente al principio de una tarea, para que lea lo que está establecido antes de volver a derivarlo.

Registrar ejecuciones

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"]

Los artefactos se direccionan por contenido (mismos bytes, un nodo), así que dos resultados calculados a partir de los mismos datos se funden automáticamente en una línea de evidencia. Una reejecución enlaza replicates con data.differs (new_seed, new_impl, new_data …) y eleva el perfil de evidencia.

Perfiles y flujos de trabajo

Fija un perfil en la investigación y el registro aplica las reglas de esa disciplina — y, con los perfiles @2, su flujo de trabajo: etapas con compuertas, qué invalida la evidencia, las formas tipadas que deben tener un diff, una instancia, una fuente o una posición. La etapa se deriva en cada lectura, como la situación.

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
  • Las compuertas son predicados. hypothesis_stated, preregistered, diff_registered, tests_pass_current, backtested, positioned, still_valid, solved, result_reviewed … — utilizables también como el done_when de una orden.
  • Qué invalida. Además de las premisas, un flujo de trabajo añade uses (un archivo de datos corregido, un diff o una instancia sustituidos) o cites (una fuente retirada) a lo que deja EN RIESGO a los dependientes — por perfil, así que los registros bajo @1 conservan exactamente la situación que tenían.
  • Vigencia. Un resultado cuya ejecución usó un artefacto ahora sustituido, o cuyo valid_until ya pasó, está DESACTUALIZADO; una afirmación está desactualizada cuando lo están todos los resultados que la respaldan. Una comprobación sobre evidencia desactualizada no cumple reviewed.
  • Formas tipadas. artifact.kind + meta (un diff necesita base_sha, head_sha, files), source.kind, decision.kind=position con size, stop, review_date, paper — rechazados si están incompletos. Registrar de nuevo los mismos bytes tipa un artefacto sin tipo y añade los enlaces indicados.
  • Finales honestos. Una respuesta inconclusive comprobada, una decisión no_position, un fallo verificado (un resultado negativo registrado por el instrumento, comprobado) completan cada uno una pregunta que las compuertas por sí solas nunca completarían.

El método del que sale cada flujo de trabajo, y la decisión detrás de cada compuerta, ocupan una página cada uno en docs/workflows. El planificador de HypSwarm emite la orden de etapa de cada pregunta exactamente a partir de esto.

Receta: informes de evaluación que se sostienen

  1. Prerregistra. Un experimento con enlaces tests a cada hipótesis («el ajuste fino es mejor», «no hay diferencia»), cada una con data.expected, antes de ejecutar.
  2. Registra la ejecución como arriba; pon los recuentos en los valores del resultado como {k, n}, no solo porcentajes.
  3. Afirma con mediciones. «1.624 de 2.000 frente a 1.568» queda ligado; «5 puntos mejor» sin un campo de resultado para el 5 se rechaza.
  4. «No hay diferencia» necesita potencia. Siembra un efecto conocido (inyecta una diferencia de 2 puntos en una copia de las predicciones), demuestra que la comparación lo detecta con este tamaño de muestra y marca ese resultado como power: "demonstrated". Sin eso, registra la afirmación como inconclusive — el registro insiste.
  5. Revisión. Un agente crítico vuelve a ejecutar el evaluador sobre las predicciones guardadas; su pass o fail queda fijado a esta versión de la afirmación.
  6. Informe. g.report(inv)["markdown"] es la tabla de hechos para el principio del informe; no puede volver a enunciar una afirmación retirada.

Coste

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 moved

HTTP y la interfaz

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

En tu propia aplicación (se muestra FastAPI; funciona cualquier framework):

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)

La interfaz no usa frameworks ni paso de compilación: HypGraph.mount(el, {source: HypGraph.HttpSource('/api/graph')}), o HypGraph.BundleSource(bundle) sin ningún servidor. Sigue GET /api/graph/stream en directo, y la telemetría de una ejecución de HypSwarm (<record>.telemetry.jsonl) añade cada llamada al modelo y a herramientas. hypgraph export --telemetry la lleva en un bundle para reproducirla, fuera de la cadena de hashes; {play: true} abre en la reproducción. Dale tema con variables CSS --hg-*. Míralo en los ejemplos en directo.

Bundles en 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

Publica el hash de head del bundle en algún sitio que no controles (una etiqueta, un artículo, un ticket) cuando se publique un resultado: un registro posterior que pase por ese hash no puede haber reescrito nada anterior. Los revisores pueden comprobar un bundle en /verify sin instalar nada.

Revisar el informe

La mayor parte del hype vive en el informe final, no en el registro. hypgraph check lee markdown contra el registro y sale con 1 si hay errores, así que el resumen que entrega un agente no puede contradecir lo que de verdad se demostró:

hypgraph check summary.md              # errors fail
hypgraph check --strict summary.md     # warnings (unsourced numbers …) fail too
errordetecta
REPORT_OVERSTATES_STANDING«establecido» / «confirmado» sobre una afirmación que el registro tiene sin comprobar, impugnada o en riesgo
REPORT_CITES_WITHDRAWNcitar una afirmación retirada como si siguiera en pie
REPORT_UNKNOWN_CODEuna cita a una afirmación o un resultado que no existe
REPORT_ABSOLUTE_UNBACKED · REPORT_ABSENCE_UNBACKED · REPORT_SIGNIFICANCE_UNBACKEDnunca / sin efecto / significativamente sin nada citado detrás

Avisos: números que ningún resultado contiene ni implica, disputas omitidas, citas sustituidas, lenguaje causal sin citas. Los bloques de código, el código en línea, las URL, los pasajes citados, las negaciones («no se puede demostrar») y las instrucciones («nunca uses el conjunto de evaluación») no se tratan como afirmaciones — calibrado con dos docenas de informes reales comprobados contra el registro en vivo del que informan. En Python: g.check_text(text, inv); por HTTP: POST /api/graph/check; para agentes: la herramienta MCP check_report.

El registro de rechazos

Cada afirmación rechazada se registra — autor, enunciado, códigos — y se marca como corregida cuando el mismo autor vuelve con la versión honesta. Es el número que nadie más puede enseñarte: con qué frecuencia tus agentes intentaron sobreafirmar, qué reglas los pararon y cuáles abandonaron en silencio.

hypgraph refusals                      # per author and rule, fixed vs open
hypgraph refusals --author analyst     # one agent's refusals in full

De solo anexión con su propia cadena de hashes (g.verify_refusals()), aparte de la del registro. En Python: g.refusal_report(inv); HTTP GET /api/graph/refusals; MCP refusal_log; y un recuento de sobreafirmaciones rechazadas en el Resumen de HypGraph.

Rendimiento

nodosderivar toda la situaciónleer un nodoescribirverificar la cadena
1,0010.047 s0.1 ms5.7 ms0.028 s
3,3010.095 s0.07 ms6.0 ms0.07 s
10,0010.37 s0.07 ms11.4 ms0.21 s

Python puro, medido con python dev/bench.py --nodes N en un portátil con Windows (Python 3.13, hypgraph 0.6). Su registro es una investigación de preguntas, resultados ligados a valores, afirmaciones derivadas de ellos y revisiones sobre algunas; la derivación crece al mismo ritmo que el registro. Una escritura cuesta lo que toca: las instantáneas comparten los datos no tocados, y la situación en caché sobrevive para cada nodo que la escritura no puede alcanzar (comprobado contra una reconstrucción completa con un conjunto de pruebas aleatorizado). La mayor parte de una escritura es SQLite confirmando en disco. Ejecuta el benchmark en tu máquina y con tus tamaños.