API Reference
The HTTP API is a thin, typed veneer over one deployment. Every query endpoint returns the same envelope — the answer plus a machine-readable account of itself (its grain, validity, freshness, and any typed "no"). No query endpoint calls an LLM, and reads never trigger writes. An explicitly composed ingest capability is the sole client write path and always enters E0.
Three things are true of every deployment's API:
- The recipe endpoints render from the registry.
GET /recipesis the deployment's active recipe rows; the CLI and MCP surfaces render the same set, so the three surfaces are always in lockstep. - The API is the one enforcement point. When a deployment configures an auth perimeter, every endpoint is gated on a valid credential for that deployment before any read runs — one deployment is one trust domain.
- Failures are typed. A "no" is a structured negative in the envelope
(
unknown_entity,known_empty,boundary); an unroutable request is an ordinary HTTP status.
Recipes — the registry, rendered
A recipe is a named, frozen composition of the primitives. The recipe surface is the recommended entry point: it is what the MCP tool list and the CLI also use.
GET /recipes
Returns the deployment's active recipes as tool descriptors — the same list an MCP client discovers:
[
{
"name": "relation_current",
"description": "Current relations matching a subject and optional predicate …",
"input_schema": {
"type": "object",
"properties": {
"subject_entity_id": { "type": "string", "format": "uuid" },
"predicate": { "type": "string" }
},
"required": ["subject_entity_id"]
},
"output_grain": "fact",
"answer_intent": "current_facts"
}
]output_grain and answer_intent travel with each descriptor, so a caller
knows what kind of answer a recipe returns before calling it.
POST /recipe/{name}
Runs one recipe by name over a JSON body of arguments and returns the envelope. Arguments are coerced to the types the primitives need (a uuid string to a UUID, an ISO-8601 string to an instant):
curl -X POST "$REMEMBERSTACK_API_URL/recipe/relation_current" \
-H "content-type: application/json" \
-d '{"subject_entity_id": "…", "predicate": "works_for"}'An unknown recipe is 404; a missing required argument is 422.
The stock self-host adds resolve_entity so recipe-only agents can obtain UUIDs,
plus graph_neighborhood and graph_path because that profile composes P2.
Profiles without P2 do not seed the graph recipes.
Client writes
These endpoints exist only when the deployment composes the corresponding service. An absent capability is an ordinary 404, never a client-side fallback that bypasses the deployment.
POST /ingest
Sends raw bytes with filename and mime query parameters. The optional
source_kind and source_ref parameters form one stable lineage identity and
must be supplied together. source_modified_at, source_version_ref, and
versioning_mode=snapshot|living carry the feeder's version metadata. Changed
bytes under the same identity append a document version; identical bytes are
an idempotent no-op. On that no-op, source_version_ref may advance as the
connector cursor, but the existing version's source_modified_at never changes
or clears because it already fed extraction. A supplied source timestamp must
be timezone-aware UTC; omitting it preserves an unknown source time.
POST /readiness
When composed, accepts a JSON list of document-version UUIDs and returns the
exact expected stage generations and their states. With
require_projections=true (the default), readiness also requires both P2 and
P3 builds to have begun after the latest requested terminal stage. The response
includes non-secret model IDs, making writer/query configuration auditable.
This endpoint inspects work; it does not wait, retry, or trigger a rebuild.
Connector management
| Method & path | Operation |
|---|---|
GET /connectors | list deployment-side connectors |
POST /connectors | add typed connector configuration |
GET /connectors/{connector_id} | read current status |
POST /connectors/{connector_id}/pause | pause execution |
Connector credentials remain deployment-side. The client may send a
credential_ref naming an existing secret, but connector execution never
moves into the client process. WP-5.7 defines this typed composition port; the
deployment profile supplies the persistent manager.
Python SDK
The base wheel exposes the synchronous typed client without PostgreSQL, worker, projection, or adapter dependencies:
from pathlib import Path
from rememberstack.client import MemoryClient
with MemoryClient.from_settings() as memory:
tools = memory.recipes()
answer = memory.run_recipe(
name="relation_current",
arguments={"subject_entity_id": "…", "predicate": "works_for"},
)
landed = memory.ingest(
Path("project.md"),
source_kind="custom-feeder",
source_ref="workspace/project",
source_version_ref="revision-17",
)
ready = memory.pipeline_readiness(version_ids=(landed.version_id,))The SDK also exposes typed resolve, search_claims, hydrate_relation, and
connector-management methods. Network and non-success HTTP responses raise
MemoryApiError with the status and deployment-provided detail.
Primitives
The primitives are available directly for callers that compose their own plans. Each returns the envelope.
| Method & path | What it answers |
|---|---|
GET /resolve?name=&entity_type=&context_entity_ids= | resolve a name to ranked current entities; repeat context_entity_ids up to eight times to rank ambiguous names by their current relation adjacency (never a silent guess) |
GET /lookup/relations?subject_entity_id=&predicate=&object_entity_id=&valid_at= | relations matching an (s, p, o) pattern — current, or as-of a world-time instant |
GET /lookup/observations?entity_id=&property_query=&k= | live observations on one entity, semantic over statements |
GET /search/claims?query=&k= | semantic claim search — evidence grain, never a current-fact answer |
GET /hydrate/relation/{relation_id} | the audit chain: a relation → its evidence claims → source documents |
GET /transcript/relation/{relation_id} | the decision history: why the system believes what it believes |
Evidence rows returned by claim search and relation hydration include
claim_valid_from and claim_valid_until. These are nullable ISO-8601
timestamps bounding the source-asserted world interval (valid-time) during which
the fact holds or happened, including bounds resolved from relative phrases
against an in-document timestamp; they are evidence, not the fact layer's
current-validity verdict.
resolve always returns every exact-name candidate. Supplying focal entities only
reorders those candidates: a candidate related to more of the supplied entities
ranks first, and each candidate discloses its context_hits. Context therefore
helps with questions such as “which John from this project?” without converting a
ranking hint into a hidden identity decision.
A relation returned by lookup or hydrate that sits in a live
contradiction group always carries the other sides with it — a contradiction
is surfaced, never silently resolved. A fact whose supporting testimony was
withdrawn is returned flagged, not hidden.
The auth perimeter
A deployment that configures an auth-perimeter provider gates the whole API on
a credential passed in the Authorization header:
Authorization: <scheme> <value>
The credential is handed to the configured provider. A missing or failing credential is 401; a credential authenticated to a different deployment is 403. Inside the perimeter it is one trust domain — there is no per-request, content-level authorization (isolation is achieved by running separate deployments). Without a configured provider the API is open, and the perimeter is the deployment's infrastructure (network, IAM) to enforce.
Configuration
REMEMBERSTACK_API_URL— where the SDK, CLI, and MCP client reach the API.REMEMBERSTACK_API_AUTHORIZATION— optional completeAuthorizationheader value.REMEMBERSTACK_API_TIMEOUT_SECONDS— client request timeout (default 30 seconds).- The API process composes the query engine (search index, model provider) — the surface itself carries no provider adapters.