| doc_id | API_REFERENCE |
|---|---|
| status | current |
| version | generated |
| owner | GenesisBlockDB Engineering |
| updated | 2026-09-22 |
Generated from src/router.rs (Axum server) — 2026-08-14. This replaces the
prior corrupted file. The server is the SSOT; update this when routes change.
- Base URL:
http://localhost:3000(port viaGENESIS_PORT, bind0.0.0.0) - Data dir:
.brain/gks/storage(viaGENESIS_DATA_DIR) - Bodies: JSON. Errors use the route-appropriate HTTP status with a plain-text
message. CORS defaults to localhost origins;
GENESIS_CORS_ORIGINselects one origin, while*explicitly enables permissive mode. - Authentication: when
GENESIS_API_KEYis set, all/v1/*routes requireAuthorization: Bearer <key>. This is a bootstrap shared secret, not scoped OIDC/JWT authorization./metricsremains unguarded. - Run:
cargo run --features bins --bin genesis-db-server
⚠️ Two contract gotchas that have bitten SDKs:
POST /v1/query/hqlaccepts both a raw JSON string body (e.g."SEARCH …") and{"query":"…"}.POST /v1/studio/query/readaccepts the same two shapes but enforces the read-only HQL command family.- Edge
from/toare node string ids (e.g."N-…"), not integers.
The core distinguishes rejection from a durable or uncertain write. REST retains its route-specific HTTP status and plain-text error body; NAPI exposes the same message through promise rejection. Inspect the message prefix rather than assuming that every non-success status means no write occurred.
| Error prefix / outcome | Client action |
|---|---|
| Unified input/PK/unique/FK rejection | No WAL frame or graph/vector/row publication; correct the payload and retry the same transaction ID |
COMMIT_OUTCOME_UNKNOWN |
The request was sent but the WAL acknowledgement failed; reopen and inspect durable state; retry the same identity only for APIs with an idempotency contract |
DURABLE_COMMIT_APPLY_FAILED |
The message includes a durable frame sequence; address the underlying error and reopen to replay, rather than issuing a new mutation identity |
RECOVERY_REQUIRED |
Query/write/checkpoint access is stopped on this Storage instance; reopen is required |
Superseding a node retains its two-frame history. If its second write fails, the closing frame is already durable; this is partial durable completion, not full rejection. Supported query calls see a complete publication boundary, and concurrent reads serialize. ANN remains eventual until its existing flush or read-your-write barrier. Diagnostic getters are not a readiness signal during recovery-required state. See Wave A for the exact boundary, tests and performance limitations.
| Method | Path | Request body | Response |
|---|---|---|---|
| POST | /v1/node/add |
NodeInput |
NodeOutput |
| POST | /v1/node/supersede |
{ id, new_props?, caused_by? } |
NodeOutput |
| POST | /v1/edge/add |
EdgeInput |
EdgeOutput |
| POST | /v1/edge/retract |
{ id, at? } |
EdgeOutput (retracted) |
| POST | /v1/collection/create |
{ name, model, dim, metric? } |
{ ok: true } |
| GET | /v1/collections |
none | CollectionInfo[] |
| POST | /v1/vector/add |
{ node_id, collection, embedding } |
{ ok: true } |
| POST | /v1/bulk/nodes |
NodeInput[] |
200 (empty) |
| POST | /v1/bulk/edges |
EdgeInput[] |
200 (empty) |
| POST | /v1/bulk/rebuild |
none | 200 (empty) |
| POST | /v1/relational/schema/register |
RelationalSchemaPackage |
current schema_version |
| GET | /v1/relational/schema/:namespace |
none | normalized RelationalSchemaPackage or 404 |
| POST | /v1/relational/mutate |
RelationalMutationBatch |
RelationalMutationResult |
| POST | /v1/relational/query |
NamedQueryRequest |
JSON row array |
| POST | /v1/transaction/commit |
GenesisTransaction |
TransactionCommitResult |
| GET | /v1/frontier |
none | { frame: u64, txn: u64 } — durable frame and transaction lineage frontiers |
| GET | /v1/studio/capabilities |
none | negotiated Studio protocol/features/limits |
| GET | /v1/studio/graph |
query seed?, limit?, offset?, direction?, as_of? |
bounded StudioGraphScene without embeddings |
| GET | /v1/studio/entity/:entity_id |
path id | StudioEntityInspection without embeddings |
| POST | /v1/studio/query/read |
raw JSON string or { query } |
read-only HQL result; 256 KiB body ceiling |
| GET | /v1/studio/relational/schemas |
none | logical RelationalSchemaPackage[] |
| POST | /v1/query/hql |
raw JSON string or { query } |
JSON (shape depends on command) |
| POST | /v1/query/ir |
QueryIrRequestV1 |
versioned Query IR response envelope |
| GET | /v1/query/ir/capabilities |
none | operation-specific Query IR capability manifest |
| POST | /v1/query |
QueryInput |
EdgeOutput[] |
| POST | /v1/search/hybrid |
HybridSearchInput |
NeighborOutput[] |
| POST | /v1/reason/context |
HybridSearchInput |
NeighborOutput[] (alpha forced 0.4) |
| GET | /v1/insight/drift/:cluster_id |
path u32 |
SuperNode[] |
| GET | /v1/insight/communities |
none | community detection results |
| GET | /v1/insight/gaps |
none | structural gap analysis |
| POST | /v1/insight/rebuild |
none | trigger community detection rebuild |
| GET | /v1/status |
none | ExtendedStatus |
| GET | /v1/version |
none | { version } |
| GET | /v1/swarm/status |
none | SwarmStatus |
| POST | /v1/consensus/propose |
{ event: Event, signature: u8[] } |
String (proposal id) |
| POST | /v1/consensus/sign-vote |
{ proposal_id, approve } |
u8[] (ed25519 signature) |
| POST | /v1/consensus/vote |
{ proposal_id, peer_id, approve, signature: u8[] } |
bool (quorum reached) |
| POST | /v1/consensus/verify |
Event |
bool |
Engine capabilities NOT exposed over REST (NAPI/embedded only) include
compact, set_language_centroid, set_index_params, reconcile_state, and
flush_index. REST exposes batch/transaction commit, tiered context, index lag,
and bounded graph traversal through their guarded logical routes; it never
exposes a raw SQLite connection or projection file.
Applications never receive a SQLite handle and cannot submit raw SQL. Schema
registration and mutation events enter the signed Genesis WAL before the staged
SQLite transaction commits. Network reads execute only named queries registered
in the current schema package; the ad hoc query_relational method remains an
embedded compatibility API and is not a REST route.
mutation_id retries are idempotent only when the complete payload is identical;
reuse with another payload returns REL_MUTATION_CONFLICT. Schema versions must
advance exactly by one and additive migrations cannot remove or incompatibly
change existing tables, columns, or primary keys.
Async vector indexing. HNSW insertion runs off the write path on a dedicated indexing thread — a vector is durable (WAL) and in its collection's arena immediately, but eventually searchable (the index lags). NAPI exposes
flushIndex()(drain the queue — read-your-write) andindexLag()(staged but not-yet-indexed count). SeeADR--GENESISDB-ASYNC-INDEXING.
POST /v1/query/ir accepts a closed versioned envelope. The current partial implementation supports
operation.kind = "search", operation.kind = "traverse" and target-id
operation.kind = "context". Unknown fields and unsupported
versions return HTTP 400 with { "code", "message" }; execution failures return HTTP 500.
{
"contract_version": "query-ir.v1",
"request_id": "client-correlation-id",
"operation": {
"kind": "traverse",
"seed_id": "entity:42",
"depth": 2,
"relations": ["depends_on"],
"direction": "out"
}
}search requires exactly one of target_id or query_vector, plus mode and k. Supported modes
are vector and hybrid; lexical mode remains planned and typed metadata filters are unsupported.
Supplying a filters object is recognized and rejected with QUERY_CAPABILITY_UNSUPPORTED until a
typed metadata contract exists.
context is implemented for a target id with tier H0–H6, optional token budget and optional
fuzzy; query-vector and temporal context fail closed with QUERY_CAPABILITY_UNSUPPORTED. Its
data is the existing context packet, including coverage, and compressed packets carry the
context_truncated warning. GET /v1/query/ir/capabilities is the runtime authority for implemented
operation kinds and current bounds.
HQL remains a compatibility frontend. New machine integrations should prefer Typed Query IR for implemented operations.
SEARCH <target> SIMILAR TO [v1, v2, …] K <k> [IN <collection>] [LANGUAGE "th"] [AS OF "<rfc3339>"]
TRAVERSE FROM <seed> DEPTH <n> REL <rel|INFER(rel)|ANY> [AS OF "…"]
MATCH <target> SIMILAR TO [v…] ALPHA <a> [IN <collection>] [LANGUAGE "…"] [AS OF "…"]
MATCH (<node>) (<edge> (<node>))* [AS OF "…"] [<clauses>] # Cypher graph patterns
CONTEXT FOR <target> TIER <H0..H5> [BUDGET <n>]
# Optional trailing <clauses> on SEARCH / TRAVERSE / MATCH (both forms):
[ WHERE <field> <op> <value> (AND …)* ] [ ORDER BY <field> (ASC|DESC)? ] [ LIMIT <n> ] [ RETURN <field> ("," …)* ]
~ prefix on target/seed enables fuzzy id resolution. SEARCH runs pure vector
k-NN (alpha=0); MATCH <t> SIMILAR is hybrid (vector + K-Impact, k=10). IN <collection> scopes the query to a named vector collection (quoted "code" or
bare code); omitted → the default collection. The query dim is validated
against the collection dim.
Cypher graph patterns (MATCH ( routes here, not to hybrid): a linear path
(a:Label {k:v})-[r:REL]->(b) …. Nodes are (var? :Label? {props}?); edges are
-[var? :Type?]-> / <-[…]- / -[…]- (out / in / either). {id:"…"} anchors on
a node id. Clause fields are variable-qualified — a, a.id, a.label,
a.prop.<key>; RETURN omitted ⇒ one object per row keyed by variable. Linear
paths only in v1 (no variable-length *, branching, or OR). See
ADR--GENESISDB-HQL-CYPHER-PATTERNS.
{ "id": "N-1"?, "labels": ["USER"], "props": {}?, "embedding": [f64]?,
"lang": "en"?, "valid_from": "<rfc3339>"?, "caused_by": "…"?, "ttl": 3600?,
"collection": "default"? }(collection routes embedding into a named vector space; defaults to default.)
{ "id", "labels": [], "props": {}, "impact": f64?, "embedding": [f64]?,
"lang": "en"?, "valid_from", "valid_to": null?, "caused_by": null?,
"expires_at": null?, "clock": { "time": u32, "peer_id": "…" },
"collection": "default"? }(Embedding is omitted from node read responses — the vector lives in its
collection's arena/HNSW. collection records which space it lives in.)
// EdgeInput
{ "id": "…"?, "from": "N-1", "to": "N-2", "rel": "LINK", "props": {}?,
"valid_from": "…"?, "supersede": false?, "impact": f64?, "caused_by": "…"? }
// EdgeOutput
{ "id", "from": "N-1", "to": "N-2", "rel", "props", "valid_from",
"valid_to": null?, "recorded_at", "superseded_by": null?, "impact": f64?,
"caused_by": null?, "clock": { "time", "peer_id" } }from/to are node string ids (interned to u32 internally only).
{ "from": "N-1"?, "to": "N-2"?, "rel": "…"?, "as_of": "…"?,
"include_invalid": false?, "limit": u32? }{ "query_vector": [f64], "k": u32, "alpha": f64?, "lang": "…"?, "as_of": "…"?,
"collection": "default"? }(Searches the named collection; query length is validated against the collection dim — a mismatch is a typed error, not garbage neighbors.)
{
"name", "model", "dim": u32, "metric": "L2|Cosine", "quant",
"count": u32, "indexed": u32, "ef_search": u32?, "rerank": boolean,
"sidecar_resident_bytes": i64, "sidecar_disk_bytes": i64,
"arena_resident_bytes": i64, "index_lag": u32,
"coverage": {
"collection", "state": "UNVERIFIED|CATCHING_UP|READY|FAILED",
"source_count": u32, "indexed_count": u32, "missing_count": u32,
"extra_count": u32, "pending_count": u32,
"source_frontier": i64, "built_frontier": i64, "validated": boolean
}
}(Create with POST /v1/collection/create { name, model, dim, metric? };
metric defaults to L2. A default collection always exists. coverage
is structural source-to-HNSW membership only; READY is not an exactness or
ANN-recall claim. The core validation operation is explicit and is not yet a
REST maintenance route.)
{ "node_id": "N-1", "collection": "code", "embedding": [f64] }(Attaches an ADDITIONAL vector to an existing node in another collection — one
node, one vector per collection, e.g. a code and a text embedding. The node
must exist; embedding length is validated against the collection dim. Durable
via WAL Event::Vector; eventually searchable. NAPI: addVector.)
{ "node": NodeOutput, "path": [EdgeOutput], "depth": u32 }{ "open", "read_only", "page_cache_mb", "node_count", "edge_count", "memory_usage_mb" }{ "peer_id", "logical_clock": u32, "peers": [SyncPeer] }Tiers MASTER (0) / SPEC (1) / ADR (2) / USER (3), derived from node
labels. External callers cannot create/modify MASTER-tier nodes (→ 403-class
error); MASTER promotion requires multi-signature consensus. Guard cost is
<0.1% of a write (audit P24).
Consensus votes are signed. A voter signs VOTE|{proposal_id}|{peer_id}|{approve}
with its ed25519 key (/v1/consensus/sign-vote); submit_vote verifies the
signature against the voter's registered public key (SyncPeer.verifying_key, or
this node's own key for a self-vote) before counting it. Unknown-peer, malformed,
or non-matching signatures are rejected (400) and not counted — forged or
replayed votes cannot reach quorum. See ADR--GENESISDB-CONSENSUS-VOTE-SIGNATURES.