HTTP API reference
The engine's only public surface — 10 endpoints over a stdlib HTTP server.
The engine exposes a small, single-threaded HTTP API (stdlib server, no web framework)
wrapping the claim store. All examples assume the engine on http://127.0.0.1:8788 with
the token in $TOK.
Auth
If ERGO_API_TOKEN is set, every route except GET /health requires:
Authorization: Bearer <token>If the var is unset, the server logs a warning at boot and runs open (dev/test only).
Write endpoints (contradiction-guarded)
These run the contradiction guard. A hard conflict returns 409 with the prior claim.
POST /remember
Guarded write for decisions / constraints / rejections / conventions.
| field | required | description |
|---|---|---|
org_id | yes | tenant id |
project | yes | project namespace within the tenant |
who | yes | actor (audit row) |
statement | yes | the claim text |
reason | no | why (free text; surfaced via /why) |
force_exception | no | if set, stores even on conflict, with this string as the exception reason |
curl -s -H "$TOK" -X POST http://127.0.0.1:8788/remember -d '{
"org_id":"acme","project":"platform","who":"alice",
"statement":"Deploy on Tuesdays","reason":"team is on-call Mon/Wed"
}'
# 200 → {"result":"stored","claim_id":"...","warnings":[...]}
# 409 → {"result":"conflict","conflicts":[{"claim":{...},"tier":"block","score":0.97,...}]}| code | meaning |
|---|---|
200 | stored (MED-tier warnings included if any) |
409 | blocked — conflict set returned for the client to resolve |
400 | missing required field |
500 | normalizer / judge / store failure |
POST /learn
The bridge between ingest (raw chunks, no gate) and remember (decisions, full gate).
Use it when an agent read something and formed a belief. Same pipeline as remember;
folds source into the stored reason for provenance. The contradiction check runs on the
statement only — the source never pollutes the judge.
| field | required | description |
|---|---|---|
org_id, project, who | yes | as /remember |
statement | yes | the belief to check + store |
source | yes | provenance (file:line, URL, doc id). Blank source is a 400 |
reason | no | extra rationale |
curl -s -H "$TOK" -X POST http://127.0.0.1:8788/learn -d '{
"org_id":"acme","project":"platform","who":"agent",
"statement":"Sessions are never reused across restarts",
"source":"sessions.py:847","reason":"observed in the restart path"
}'
# 200 → {"result":"learned","claim_id":"...","source":"sessions.py:847"}POST /supersede
Change of mind. Replaces an active claim with a new one, and runs the guard against all other active claims first — if the new claim would itself contradict another, the supersede is refused.
curl -s -H "$TOK" -X POST http://127.0.0.1:8788/supersede -d '{
"org_id":"acme","project":"platform","who":"alice","existing_id":"<id>",
"statement":"Deploy on Wednesdays","reason":"Tuesdays now collide with standup"
}'
# 200 → {"result":"superseded","claim_id":"<new id>"}Side effects: old row → status='superseded'; new row inserted with supersedes pointing
at the old id (this is what /why walks).
POST /retract
Wrong-at-birth removal (typo, test junk, mis-scoped write). Flips an active claim to
retracted. Retract ≠ supersede — if a decision genuinely evolved, use supersede to
keep the why-chain. No gate runs (removal can't create a contradiction). The row is not
deleted — it stays in /history with retract_reason; /active, /recall, /why, and
the judge all exclude it.
curl -s -H "$TOK" -X POST http://127.0.0.1:8788/retract -d '{
"org_id":"acme","project":"platform","who":"alice","claim_id":"<id>",
"reason":"test junk written against the prod scope"
}'
# 200 → {"result":"retracted","claim_id":"<id>","retracted":true}All five fields (org_id, project, who, claim_id, reason) are required; a blank
reason is a 400.
Fast document path
POST /ingest
Bulk reference content. Skips the normalizer + judge (fact = upsert freely). Embeds each chunk and stores it. Requires the embedder to be enabled.
| field | required | description |
|---|---|---|
org_id, project, who | yes | as /remember |
text | yes | the document body (any size) |
source | no | provenance string, appended to each chunk for citations |
curl -s -H "$TOK" -X POST http://127.0.0.1:8788/ingest -d '{
"org_id":"acme","project":"kb","who":"alice","text":"...markdown...","source":"NOTES.md"
}'
# 200 → {"result":"ingested","chunks":49,"stored":49,"source":"NOTES.md"}Chunking is paragraph-aware and word-safe (≈1200 chars, ≈150 overlap). Ingested facts are also skipped on the candidate side — a bulk chunk can never 409 a decision; only prior decisions can.
Read endpoints
GET /recall
Hybrid semantic + keyword search over active claims.
| param | required | default | description |
|---|---|---|---|
org_id, project | yes | — | scope |
q (alias query) | yes | — | search text |
limit | no | 10 | clamped to [1, 50] |
curl -s -H "$TOK" "http://127.0.0.1:8788/recall?org_id=acme&project=kb&q=when%20to%20deploy&limit=3"Score = 0.7 × vec_sim + 0.3 × keyword_overlap. Superseded / retracted claims are excluded.
GET /why
Like /recall but reasoned-only (a reason-less fact can never win a "why" query),
returns the top hit, and walks the supersede chain.
curl -s -H "$TOK" "http://127.0.0.1:8788/why?org_id=acme&project=kb&q=when%20to%20deploy"
# → {"why":{"claim":"...","reason":"...","history":[ {newest}, {superseded} ]}}
# no reasoned match → {"why": null}GET /active & GET /history
/active lists active claims with a typed state (project_missing / empty /
has_active_claims). /history returns everything — active + superseded + retracted —
ordered by sequence.
GET /diagnose
The ops view — the running binary answers for itself. Live counts, conflict telemetry,
version-drift detection, and a warnings[] array flagging things the operator must act on
(no backup configured, version drift, etc.). Bearer-authed.
GET /health
Liveness + an allowlisted config snapshot. No auth — so health checks don't need the
secret. Ops metadata (owner, backup path) is deliberately kept off /health and lives on
the authed /diagnose.
End-to-end
TOK="Authorization: Bearer $ERGO_API_TOKEN"
curl -s -H "$TOK" -X POST .../remember -d '{"org_id":"acme","project":"platform","who":"alice","statement":"Deploy on Tuesdays","reason":"on-call Mon/Wed"}'
curl -s -H "$TOK" -X POST .../remember -d '{"org_id":"acme","project":"platform","who":"bob","statement":"Never deploy on Tuesdays","reason":"incident risk"}'
# → 409 conflict against alice's claim
curl -s -H "$TOK" -X POST .../supersede -d '{"org_id":"acme","project":"platform","who":"alice","existing_id":"<id>","statement":"Never deploy on Tuesdays","reason":"incident risk outweighs on-call"}'
curl -s -H "$TOK" ".../why?org_id=acme&project=platform&q=when%20to%20deploy"
# → history with both entries