Documentation

Two surfaces, one governed memory.

MemRails exposes the same governed memory two ways — pick whichever fits your stack. The MCP suite is agent-native: tools your model calls in-loop. The HTTP API suite is everything else: a plain REST surface for any language or runtime. Either way the memory is evidence-graded, inspectable, Git-versioned, and model-agnostic. The two are documented independently below; you never need both.

MCP suite

agent-native

Four tools that expose governed memory directly to an agent loop. The dispatcher runs in-process against the file-canonical library; a stdio JSON-RPC transport wraps it so MCP clients (Claude Code, and others) can call the tools natively. The contract is model-agnostic and every retrieval is inspectable; read-only by default — writes are governed proposals.

Connect

Run the stdio server and register it with your MCP client. It speaks JSON-RPC over stdio and dispatches to the same governed primitives as the API.

shell
# start the MCP server (stdio JSON-RPC)
npm run mcp:server
claude code · .mcp.json
{
  "mcpServers": {
    "memrails": { "command": "npm", "args": ["run", "mcp:server"] }
  }
}

memrails.memory.retrieve

Retrieve governed memory for local inference — a scoped, explainable context bundle.

Input
FieldTypeDescription
task_context *stringWhat the agent is about to do.
project_idstringScope. Defaults to the project_memrails namespace.
agent_idstringOptional finer scope; project-wide if omitted.
max_tokensnumberContext token budget for the bundle.
retrieval_mode'exact' | 'tree' | 'hybrid' | 'hot' | 'debug'How the MemoryIndex is walked. Default tree.
Returns
ContextBundle — memories[] (each with reason_selected, score,
tokens), omitted[], retrieval_trace (branches walked, policy filters,
candidates), tokens_returned, and usage.

memrails.memory.write

Write a governed memory record (deduped, contradiction-checked). Never rewrites canonical markdown.

Input
FieldTypeDescription
content *stringThe memory body.
memory_typestringdecision · preference · note · summary · extraction · correction · constraint · claim.
confidencenumber0–1 calibrated confidence.
tagsstring[]Labels that aid later retrieval.
project_idstringScope namespace.
Returns
{ memory_id, status: "active" | "deduplicated", contradicts?: string[],
dedup_of?: string }

memrails.memory.inspect

Open a prior retrieval by id: the trace, branches selected, scores, and what was left out.

Input
FieldTypeDescription
retrieval_id *stringReturned by a previous retrieve call.
Returns
{ trace, memories, omitted } — throws retrieval_not_found if the id is unknown.

memrails.memory.map

Return the project MemoryIndex tree — the nested memory map.

Input
FieldTypeDescription
project_idstringDefaults to project_memrails.
Returns
The hierarchical MemoryIndex tree for the project.

API suite

REST · any runtime

A plain JSON-over-HTTP surface for everything that isn’t an MCP client. Same governed memory, same scope rules, same metering — callable from any language. Model-agnostic, and every retrieval stays inspectable.

Authentication

Pass your key as a bearer token. Without a key you get read-only access to the public demo tenant; mutations require a real key. Provision one with POST /api/enroll.

header
Authorization: Bearer mr_your_key_here
Public — no keyKey optional — demo readsAPI key required

Billing & scope

One successful memory.retrieve() = one billable retrieval ($0.002, $2 / 1,000); the free tier is retrieval credits, not quotas. Writes are free; context tokens are your model provider’s charge. Every record is scoped to an owner / project / agent triple — the owner is derived from your key and never trusted from the body, so tenants can’t read across namespaces.

Account & billing

Provision a tenant, then read metered usage and the event ledger.

POST/api/enrollPublic

Provision an isolated tenant — one email → one account, API key, and starter credits.

Request
FieldTypeDescription
email *stringAccount email (idempotent — re-enrolling returns the existing owner).
plan'free' | 'usage' | 'team' | 'enterprise'Defaults to free.
Response
{ owner_id, email, plan, api_key: "mr_…", credits_remaining }
GET/api/usageAPI key

Metered usage summary for the authenticated owner.

Response
{ owner_id, plan, retrievals_total, credits_remaining, spend_usd,
  projected_cost_usd, billing_unit }
GET/api/ledgerAPI key

The append-only event ledger scoped to the caller (retrievals, writes, billing events).

Response
{ events: LedgerEvent[] } — each event carries type, hashes, cost, and created_at.

Memory

The core surface: retrieve a governed bundle, write proposals, and manage records over their lifecycle.

POST/api/memory/retrieveKey optional

Governed retrieval → a token-budgeted, explainable context bundle. The one billable call.

Request
FieldTypeDescription
task_context *string (1–4000)The retrieval query.
project_idstringScope. Default project_memrails.
agent_idstringOptional finer scope.
max_tokensinteger (1–8000)Context token budget.
retrieval_mode'exact'|'tree'|'hybrid'|'hot'|'debug'Default tree.
include_evidencebooleanAttach evidence references.
include_disputedbooleanInclude disputed memories (off by default).
include_packetbooleanAlso synthesize a compressed packet.
Response
{ context_bundle_id, retrieval_id, scope, mode,
  memories: [{ memory_id, summary, content, confidence, reason_selected, score, tokens }],
  omitted: [{ memory_id, reason }],
  tokens_returned, token_budget, retrieval_trace, packet,
  usage: { billable_retrievals, credits_remaining, credit_exhausted }, latency_ms }
POST/api/memory/writeAPI key

Governed write — deduplicated and contradiction-checked. Returns a record, not a silent mutation.

Request
FieldTypeDescription
content *string (1–8000)The memory body.
summarystring (≤400)One-line summary.
memory_typeenumdecision · preference · note · summary · extraction · correction · constraint · claim.
confidencenumber (0–1)Calibrated confidence.
sensitivity'normal'|'sensitive'|'restricted'Handling class.
tagsstring[]Retrieval labels.
index_pathstringMemoryIndex node path.
sourceobject{ type, id, ref, hash } provenance.
Response
{ memory_id, status: "active" | "deduplicated", contradicts?: [], dedup_of?: "mem_…" }
GET/api/memory/{id}Key optional

Read a single memory record by id (scoped to the caller).

Response
MemoryRecord — { memory_id, scope, memory_type, status, confidence,
  content, summary, tags, contradictions, index_path, current_version, created_at, … }
DELETE/api/memory/{id}API key

Tombstone a memory (soft delete; canonical body preserved for audit). Optional ?reason=.

Response
{ memory_id, status: "tombstoned" }
POST/api/memory/{id}/supersedeAPI key

Mark a memory superseded and optionally point it at a replacement (by id or inline).

Request
FieldTypeDescription
reasonstring (≤500)Why it was superseded.
new_memory_idstringExisting replacement. Mutually exclusive with new_memory.
new_memoryobjectInline replacement (same shape as write).
Response
{ superseded: "mem_…", replacement: "mem_…" | null }
POST/api/memory/{id}/disputeAPI key

Flag a memory as contested — halves confidence and excludes it from retrieval by default.

Request
FieldTypeDescription
reason *string (1–500)Why it is disputed.
Response
{ memory_id, status: "disputed", confidence }
GET/api/memory/exportKey optional

Export the caller’s registry — memory is file-canonical and Git-versioned. No lock-in; read it all out any time.

Request
FieldTypeDescription
format'json' | 'jsonl' | 'markdown'Query param. Default json.
project_idstringQuery param. Filter to one project.
Response
json: { count, artifact_ref, records[] } · jsonl: ndjson stream · markdown: text/markdown
GET/api/memory/mapKey optional

Project the MemoryIndex tree for a project (?project_id=).

Response
{ project_id, map } — the nested index tree.
POST/api/memory/queryPublic

Synthesize a compressed packet over the curated corpus via the L1–L5 retrieval stack — cheap filters first, compression as last resort (public).

Request
FieldTypeDescription
query *string (1–2000)The question.
intent'answer'|'summarize'|'compare'|'extract'|'refactor'|'route'Synthesis intent.
max_tokensinteger (1–2000)Packet token cap.
Response
{ packet_id, packet, confidence, tokens, contradictions_surfaced,
  evidence: [{ claim_id, weight, source_file }], input_hash, output_hash, resolved_layer }

Retrievals & feedback

Replay why a bundle came out the way it did, and feed quality signals back.

GET/api/retrievals/{id}/traceKey optional

Replay a past retrieval’s full trace — branches selected, scoring, and omissions.

Response
{ retrieval_id, query, scope, trace, memories: [{ memory_id, score, reason_selected }], omitted }
POST/api/feedbackKey optional

Rate a retrieval or a specific memory to train ranking.

Request
FieldTypeDescription
retrieval_id *stringThe retrieval being rated.
memory_idstringA specific memory in it (optional).
rating *'positive' | 'negative'The signal.
commentstring (≤2000)Free-form note.
Response
{ feedback_id, retrieval_id, memory_id, rating, created_at }

Platform

Inspect the infrastructure itself.

GET/api/stackPublic

The canonical rail map — planes, providers, and what each graduates to (public).

Response
{ summary, core, global_plane, per_owner_plane, rails: [{ id, scope, provider, graduates_to }] }

Get a key, make a call.

Enroll for retrieval credits, then point either surface at your corpus.