Native Memory API

Native memory records conversations for a peer, derives claims asynchronously, and returns cited context for later work. The HTTP contract is the semantic authority for direct HTTP, marrowid==1.0.4 imported as marrow, and @marrowid/[email protected], and @marrowid/[email protected]. Hosted MCP at https://mcp.marrow.id and the local marrow mcp compatibility adapter expose the same memory semantics through the exact 15-tool MCP registry.

These integrations run inside a trusted application process. Keeping the API key in that process protects the credential, but it does not provide prompt-injection isolation for untrusted messages or retrieved text. Treat returned context as data and preserve its status, citations, conflicts, and warnings when another model consumes it.

See the complete machine-readable OpenAPI document.

Credential and scope contract

Every route below accepts only a customer API key in Authorization: Bearer $MARROW_API_KEY. Browser cookies and CLI session tokens do not authenticate native memory routes. Workspace, peer, session, claim, and event identifiers are labels or public handles inside the account selected by the key; they are not ownership credentials.

Scope Minimum use
memory.write Get or create workspace, peer, and session labels; add messages; correct or withdraw claims.
memory.read List and fetch labels, messages, claims, cited context, write events, and queue status.

Use both scopes for a process that writes a message, polls its event, and then reads the resulting memory. The current OpenAPI contract admits the default workspace label.

Lifecycle

  1. Get or create the workspace, peer, and session labels with memory.write.
  2. Add one or more peer-attributed messages. The receipt has status: "processing" and an event_id.
  3. Poll GET /v1/workspaces/{ws}/events/{id} with memory.read until EventStatus.status is succeeded, failed, or quarantined.
  4. After succeeded, ask for cited evidence or fetch assembled context. A non-ready status is an application outcome, not permission to invent context.
  5. Read the current claim or its history before a user-approved change. Correct with PUT; withdraw with DELETE. Send the claim's current head_revision with either mutation, retain the stable claim id, and inspect history for ADD, UPDATE, and DELETE events.

Exact routes

Scope Route Request Success response
memory.write POST /v1/workspaces No request fields Workspace
memory.read POST /v1/workspaces/list No request fields PageWorkspace
memory.write POST /v1/workspaces/{ws}/peers LabelUpsertRequest Peer
memory.read POST /v1/workspaces/{ws}/peers/list No request fields PagePeer
memory.read GET /v1/workspaces/{ws}/peers/{peer} Path labels Peer
memory.read POST /v1/workspaces/{ws}/peers/{peer}/ask AskRequest MemoryContext
memory.read GET /v1/workspaces/{ws}/peers/{peer}/context Optional session and q query parameters MemoryContext
memory.read POST /v1/workspaces/{ws}/peers/{peer}/representation No request fields RepresentationResponse
memory.write POST /v1/workspaces/{ws}/sessions LabelUpsertRequest Session
memory.read POST /v1/workspaces/{ws}/sessions/list No request fields PageSession
memory.read GET /v1/workspaces/{ws}/sessions/{s} Path labels Session
memory.write POST /v1/workspaces/{ws}/sessions/{s}/messages MessagesCreateRequest MessagesCreateReceipt
memory.read POST /v1/workspaces/{ws}/sessions/{s}/messages/list No request fields PageMessage
memory.read GET /v1/workspaces/{ws}/sessions/{s}/context Required peer; optional q MemoryContext
memory.read POST /v1/workspaces/{ws}/claims/query ClaimsQueryRequest PageClaim
memory.read POST /v1/workspaces/{ws}/claims/list ClaimsListRequest PageClaim
memory.read GET /v1/workspaces/{ws}/claims/{id} Claim id Claim
memory.read GET /v1/workspaces/{ws}/claims/{id}/history Claim id ClaimHistoryResponse
memory.write PUT /v1/workspaces/{ws}/claims/{id} ClaimUpdateRequest ClaimUpdateResult
memory.write DELETE /v1/workspaces/{ws}/claims/{id} ClaimDeleteRequest ClaimDeleteReceipt
memory.read GET /v1/workspaces/{ws}/events/{id} Event id EventStatus
memory.read GET /v1/workspaces/{ws}/queue/status Workspace label QueueStatus

Message write schemas

MessagesCreateRequest is closed to unknown fields.

Field Required Contract
peer_id Yes Non-empty peer label.
messages Yes 1 to 100 MessageInput objects. Each has role (user, assistant, system, or tool) and content.
agent_id No Non-empty agent label.
infer No Boolean write control. Omit it to use the service default.
created_at No ISO 8601 date-time for the add event.
metadata No Application metadata object. The marrow key is reserved and rejected.
source_ids No Up to 100 succeeded, same-account ingest job IDs. Use public job.id values returned by ingest or job status.
idempotency_key No Non-empty caller-owned replay key.
{
  "peer_id": "riley",
  "messages": [
    {
      "role": "user",
      "content": "Project updates should lead with the decision and keep the open pricing risk visible."
    }
  ],
  "infer": true,
  "source_ids": ["550e8400-e29b-41d4-a716-446655440000"]
}

MessagesCreateReceipt contains event_id, status, results, authority, and eligibility. status is processing; it does not mean the derived claim is ready to read.

Poll the write event

curl -sS "$MARROW_API_BASE_URL/v1/workspaces/default/events/<event-id>" \
  -H "Authorization: Bearer $MARROW_API_KEY"

EventStatus contains event_id and one of queued, running, succeeded, failed, or quarantined. Poll with a bounded interval and deadline. Read derived memory only after succeeded; surface failed and quarantined without silently retrying a different write.

Ask and context

POST /v1/workspaces/{ws}/peers/{peer}/ask accepts an AskRequest with required query plus optional session_id and top_k. Peer context accepts optional session and q query parameters. Session context requires peer because a session is subject-partitioned.

All three return MemoryContext:

  • status: ready, partial, insufficient_evidence, conflicted, or withheld;
  • context and messages: assembled handoff forms;
  • blocks: public text with authority, state, support_status, and citations;
  • citations: excerpt, source_label, char_offset_start, and char_offset_end;
  • conflicts and warnings: visible reasons to narrow, withhold, or request more information.

Use ready or an application-approved partial result only with its cited support. Treat insufficient_evidence, conflicted, and withheld as fail-closed outcomes.

Claim changes and history

Fetch a claim before changing it. Claim includes the stable id, content, peer/session labels, authority, state, eligibility, support_status, validity times, categories, citations, and the opaque head_revision required for a guarded change.

Correct the content with:

PUT /v1/workspaces/{ws}/claims/{id}
Content-Type: application/json

{"content":"Project updates should lead with the decision.","head_revision":"rev_VQS3c7WbiwJT_q1bUPQKMzL6t2L8OyvZ65dnp3qGnqA","reason":"User clarified the preference."}

Withdraw it with:

DELETE /v1/workspaces/{ws}/claims/{id}
Content-Type: application/json

{"head_revision":"rev_34mDXjKdEPihJoJXBIbYg4QbHMbmxNT1-vGCAtdHMfk","reason":"The user withdrew this preference."}

The correction receipt returns a successor head_revision and explicitly marks the corrected head as authority: "correction_memory", state: "current", and eligibility: "pending_review". Use that successor revision for a later change. An exact retry is replay-safe; a stale or competing revision returns 409 revision_conflict without mutation.

Then read GET /v1/workspaces/{ws}/claims/{id}/history. History is an array of entries with event, prior and successor claim text, validity times, and a deterministic marker. A withdrawn claim remains auditable through history; it must not reappear as current eligible context.

Negative outcomes

  • Missing API key: fail before sending the request.
  • Wrong credential class: a browser cookie or CLI session token is rejected.
  • Wrong scope: reads require memory.read; writes require memory.write.
  • Revoked or rotated key: replace the host-managed environment value; a stale process must continue to fail until restarted with the current credential.
  • Foreign account labels: labels do not cross the key-derived account boundary.
  • Unsupported workspace: the current public path admits only default.
  • Malformed write: reject missing peer_id, an empty message array, unknown fields, an unsupported role, or a malformed UUID in source_ids.
  • Invalid source attachment: reject any source_ids entry that is missing, belongs to another account, or has not reached succeeded; the write creates no event, job, or claim.
  • Stale claim mutation: reject a missing or stale head_revision; fetch the current claim and require user approval before retrying against a newer head.
  • Incomplete processing: do not read derived memory while the event is queued or running, or after it failed or was quarantined.
  • Unsupported evidence: preserve insufficient_evidence, conflicts, warnings, and citations; do not turn retrieved text into privileged instructions.

See App integration for HTTP and Python examples, Marrow CLI for local commands and stdio compatibility, and Quickstart for the source/job/query and hosted MCP paths.