Skip to main content
The Memory API is the UI-facing half of Clawboo’s shared memory tier. You use it to search stored facts, save new facts or versioned procedures, browse what is stored, and inspect which embedding provider backs vector search. The model-facing half is the Memory MCP server at /api/mcp/memory. Both halves share one SqliteMemoryStore over the same SQLite file — a fact saved here is immediately searchable from a runtime’s Memory tool.
Memory is always on — these routes are not feature-gated. The store uses FTS5 (full-text) plus an optional vector index. Vector and hybrid search require a reachable embedding provider. When none is available, they degrade to FTS automatically. Use GET /api/memory/provider to see the active provider.
Secrets are scrubbed at the write boundary: a fact’s title/content and a procedure’s content are passed through a secret scrubber before they are embedded and inserted. Credentials can never land in a durable, searchable fact regardless of who wrote it.

Routes

MethodPathSummary
GET/api/memorySearch facts (FTS, vector, or hybrid)
POST/api/memorySave a fact or a procedure
GET/api/memory/browseList recent facts and procedures
GET/api/memory/providerInspect the active embedding provider

GET /api/memory

Searches stored facts. Scope filters are inclusive of globally-scoped facts — a scoped query also sees facts with a null scope.
query
string
required
Search query. 1–2,000 chars. A missing or blank query returns 400.
mode
string
Search mode. One of fts, vector, or hybrid. Defaults to hybrid when an embedding provider is reachable, otherwise fts. Vector and hybrid degrade to FTS when no provider is available.
limit
number
Number of results to return. 1–100, default 10.
teamId
string
Scope filter. Results include team-scoped and globally-scoped facts.
agentId
string
Scope filter. Results include agent-scoped, team-scoped (if teamId is also set), and globally-scoped facts.

Response 200 OK

results
array
Matched facts, each annotated with a relevance score and the mode that matched it.
In hybrid mode, the score blends cosine similarity (60%) and an FTS-hit signal (40%).
curl 'http://localhost:18790/api/memory?query=deploy%20checklist&mode=hybrid&teamId=<team-uuid>&limit=5'

POST /api/memory

Saves a memory entry. The body is a discriminated union: a fact (the default) or a procedure (kind: "procedure"). A fact is a durable declarative statement. A procedure is a versioned “how-to” kept separately from the fact store — saving a procedure under an existing name + scope creates a new version rather than overwriting.

Request body — Fact

kind
string
Omit or pass "fact" to save a fact.
title
string
required
Fact title. 1–500 chars.
content
string
required
Fact content. 1–50,000 chars.
tags
string[]
Up to 50 tags, each up to 100 chars.
scope
object
Scope the fact to a team and/or agent. Omit for global scope.

Request body — Procedure

kind
string
required
Must be "procedure" to save a procedure.
name
string
required
Procedure name. 1–200 chars. Saving under an existing name + scope creates a new version.
content
string
required
Procedure content. 1–100,000 chars.
scope
object
Optional scope (same structure as fact scope above).

Response 200 OK — Fact saved

{
  ok: true
  fact: {
    id: string
    title: string      // scrubbed
    content: string    // scrubbed
    tags: string[]
    scopeAgentId: string | null
    scopeTeamId: string | null
    createdAt: number
    updatedAt: number
  }
}

Response 200 OK — Procedure saved

{
  ok: true
  procedure: {
    id: string
    name: string
    version: number    // prior max version + 1
    content: string    // scrubbed
    scopeAgentId: string | null
    scopeTeamId: string | null
    createdAt: number
  }
}
# Save a team-scoped fact
curl -X POST http://localhost:18790/api/memory \
  -H 'Content-Type: application/json' \
  -d '{"title":"Release cadence","content":"Ship on Thursdays.","tags":["process"],"scope":{"teamId":"<team-uuid>"}}'

# Save a procedure (auto-versions if name+scope already exists)
curl -X POST http://localhost:18790/api/memory \
  -H 'Content-Type: application/json' \
  -d '{"kind":"procedure","name":"deploy-runbook","content":"1. run tests\n2. tag release"}'

GET /api/memory/browse

Lists the most recent facts and procedures, scoped the same inclusive way as search. Facts are ordered by updatedAt descending; the limit applies to facts and procedures independently.
limit
number
Max entries to return per type. 1–200, default 10.
teamId
string
Scope filter (inclusive of global rows).
agentId
string
Scope filter (inclusive of global rows).

Response 200 OK

facts
array
Recent facts, newest updatedAt first. Same shape as search results minus score and matchedVia.
procedures
array
Recent procedures.
curl 'http://localhost:18790/api/memory/browse?teamId=<team-uuid>&limit=50'

GET /api/memory/provider

Reports the embedding provider that backs vector and hybrid search. The resolution order at boot is: reachable Ollama (http://localhost:11434) → OpenAI key (OPENAI_API_KEY) → null. A null provider means the store is FTS-only.

Response 200 OK — provider resolved

provider
object
The active embedding provider.

Response 200 OK — no provider (FTS-only)

{ "provider": null }
curl http://localhost:18790/api/memory/provider

Scope inclusivity

When you pass teamId and/or agentId to search or browse, results include:
  1. Facts scoped to that team (scopeTeamId = teamId)
  2. Facts scoped to that agent (scopeAgentId = agentId)
  3. Globally-scoped facts (scopeTeamId = null AND scopeAgentId = null)
You always see global memory, regardless of scope filters.

See also