MeeMesh Developer API

Persistent, portable memory for AI apps, agents, and robots
← Dashboard

Overview

MeeMesh gives your app, agent, or robot long-term memory that survives across conversations, LLM providers, and time. You store facts and conversation turns; MeeMesh recalls the relevant ones semantically when you ask.

Base URL: https://api.meemesh.com · All request/response bodies are JSON. The web dashboard lives at https://dashboard.meemesh.com — programmatic calls and MCP connectors should always use api.meemesh.com. All /v1 endpoints except /v1/register require the X-API-Key header.

Two memory systems are available per request (see Memory systems): legacy, a classic vector store, and meemesh, the PES engram store whose recall returns verbatim evidence with a confidence score — or formally abstains instead of guessing.

New: MeeMesh is also an MCP connector — plug your memory directly into Claude, ChatGPT, or Gemini and carry it across AI vendors.

Quickstart (60 seconds)

# 1. Register once — save the api_key it returns
curl -X POST https://api.meemesh.com/v1/register \
  -H "Content-Type: application/json" \
  -d '{"name": "Kitchen Robot 7", "kind": "robot"}'

# 2. Store a memory
curl -X POST https://api.meemesh.com/v1/remember \
  -H "X-API-Key: mm_YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"text": "Mr Smith takes his coffee black at 7am", "memory_system": "meemesh"}'

# 3. Recall it — note the evidence and confidence in the response
curl -X POST https://api.meemesh.com/v1/recall \
  -H "X-API-Key: mm_YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"query": "how does Mr Smith take his coffee", "memory_system": "meemesh"}'

Authentication

Register once via POST /v1/register. The response contains your api_key (prefix mm_). Send it on every other /v1 call:

X-API-Key: mm_xxxxxxxxxxxxxxxxxxxxxxxx

Keys identify a user (an app, robot, or person). Each user's memories are fully isolated from every other user's. Treat the key like a password — anyone holding it can read and write that user's memory.

Users & sessions

  • User — your app/robot/person. One API key each. Hard isolation boundary.
  • Session — a memory scope inside a user: one conversation thread, one robot deployment, one household. Every memory carries user_id + session_id. A default session always exists; writing to a new session_id auto-creates it.
  • Recall scope — search one session (scope: "session") or the whole user across all sessions (scope: "user", the default).

Memory systems

Every store/recall/chat request accepts an optional memory_system field. Omit it to use the server default (legacy). Systems store separately — a memory written to one is not visible to the other, which makes side-by-side comparison possible.

legacymeemesh
DesignVector store, nearest-neighbor recallPES engrams: memory objects + compressed trace vault
Irrelevant queryStill returns the closest matchesFormally abstains: "abstained": true
EvidenceEvery hit carries the verbatim stored text
ConfidenceMirrors similarity scoreCalibrated: similarity × capture confidence × trace tier
PlacesPlace entities with containment ("what happened at X")
Discover systems at runtime via GET /memory_systems — new systems (competitor adapters and future MeeMesh phases) appear there without client changes.

The recall contract

All recall-shaped responses share this structure:

{
  "results": [
    {
      "id": "eng_9f3a1c...",
      "text": "Mr Smith takes his coffee black at 7am",
      "meta": { "session_id": "smith-household", "role": "note", "ts": 1751930000, ... },
      "score": 0.81,          // raw similarity 0..1
      "confidence": 0.79,     // calibrated confidence 0..1
      "evidence": "Mr Smith takes his coffee black at 7am"   // verbatim trace (meemesh)
    }
  ],
  "abstained": false,          // true -> the system found nothing relevant enough
  "reason": null,              // human-readable abstention reason
  "memory_system": "meemesh"
}
Handle abstention. When abstained is true, results is empty — your integration should treat it as "no memory", not as an error. This is the cite-or-abstain guarantee: MeeMesh never fabricates a nearest-neighbor answer to fill silence.

Spatial memory Phase 1.5

The meemesh system keeps place entities: named places your memories link to, with a containment hierarchy (Blue Bottle ⊂ Shibuya ⊂ Tokyo). Places are created two ways — automatically, when a stored text explicitly mentions one ("planning session at Blue Bottle in Shibuya"), or explicitly via POST /v1/places.

Ask "what happened at X" by adding place to /v1/recall. Recall inherits downward through containment: querying "Tokyo" surfaces episodes recorded at Blue Bottle, and every such hit carries a place_path receipt showing the derivation — hierarchy-based inference is always evidence-linked, never a guess.

Cite-or-abstain extends to the spatial axis with two formal abstentions: an unknown place ("no known place matching 'Atlantis'") and a known place with no linked memories. Coordinates (lat/lon) are optional enrichment on /v1/remember — nothing requires them, and no location permission is ever needed for text-derived places.

Extraction is deliberately conservative: proper names after at / in / @ plus a small set of common places ("the office"). Time words ("in June", "at 5pm") never become places, and assistant-role turns never mint places — the same anti-echo hygiene as recall exclusion. Duplicate names are merged non-destructively via an alias_of link rather than deleted.

Visual memory Phase 4

MeeMesh can now remember what it sees. An image sent to POST /v1/see becomes a visual memory with the same guarantees as text: the original image is archived verbatim in the binary vault (content-addressed and deduplicated — re-seeing the same photo reinforces the memory instead of storing a copy), and a text gist of the image joins the shared recall index. Because the gist is the interlingua, ordinary text recall finds visual memories with no new query machinery — ask "what did the whiteboard say?" and the photo of the whiteboard comes back, with its image as the receipt.

Two capture paths:

1. caption   — you supply the gist ("bring your own percept": an on-device
               captioner, user-typed text, an OCR pass). No server-side model
               call is made; capture confidence is 1.0 — you asserted it.
2. describe  — the server's multimodal model distills the gist, visible
               objects, and any text in the image. The model's own confidence
               becomes the engram's capture_conf, so uncertain perception
               honestly lowers recall confidence downstream:
               confidence = similarity × capture_conf × trace-tier penalty.

Recall hits for visual memories carry meta.media_sha — the handle for fetching the image itself from GET /v1/media/{sha} (strictly ownership-checked). Cite-or-abstain is unchanged; pixels never enter the vector index, so the embedding space stays uniform and rebuildable. Gists flow through the same spatial extraction as text, so a photo captioned "at Blue Bottle in Shibuya" is linked to those places and answers "what happened at Shibuya".

Env: MEEMESH_VISION_PROVIDER (openai | gemini, auto-picked from available keys), MEEMESH_VISION_MODEL (default gpt-4o-mini / gemini-2.0-flash), MEEMESH_VISION_MAX_BYTES (default 8 MB).

Audio memory Phase 5

MeeMesh also remembers what it hears. A recording sent to POST /v1/hear becomes an audio memory with the same guarantees as text and vision: the original recording is archived verbatim in the binary vault (content-addressed and deduplicated — re-hearing the same clip reinforces the memory and never pays for a second transcription), and a transcript-anchored text gist joins the shared recall index. Ask "what did she say in the voice note?" in plain text and the recording comes back, with the audio itself as the receipt.

Two capture paths:

1. transcript — you supply the gist ("bring your own percept": on-device
                speech-to-text, a call stack's ASR, human notes). No server-side
                model call is made; capture confidence is 1.0 — you asserted it.
2. transcribe — the server transcribes/describes the recording. With
                whisper models, capture_conf is derived from the segments'
                average log-probability — an honest per-recording estimate,
                not a constant. Gemini returns a structured percept that also
                captures non-speech sounds (an alarm, applause, a dog barking).
                Either way: confidence = similarity × capture_conf × tier penalty.

Recall hits for audio memories carry meta.media_sha — fetch the recording from GET /v1/media/{sha} (strictly ownership-checked). Cite-or-abstain is unchanged; waveforms never enter the vector index. Gists flow through spatial extraction, so a voice note mentioning "the Marina Bay office" links to that place.

Env: MEEMESH_AUDIO_PROVIDER (openai | gemini, auto-picked from available keys), MEEMESH_AUDIO_MODEL (default whisper-1 / gemini-2.0-flash), MEEMESH_AUDIO_MAX_BYTES (default 16 MB).

Open modality registry PES v2.1

Senses are not special cases in MeeMesh — they are entries in an open registry (GET /v1/modalities). Every modality declares its media class: rich/continuous media (text, vision, audio — verbatim vault archive plus a text gist) or scalar/structured telemetry (temperature, heart rate, tactile pressure — typed values with templated gists, arriving with the first telemetry sense). The text gist is the universal interlingua: because every sense distills into it, all modalities share one embedding space and one recall path, and adding a new sense never touches core engram logic.

Write-time admission runs through an ordered gate pipeline shared by all modalities — the trigger/gating subsystem. Built-in gates stop zero-information utterances and bare recall questions from polluting the store; deployments can register additional gates (PII filters, compliance policies) without forking the core.

MCP connector — memory inside Claude, ChatGPT & Gemini Phase A

MeeMesh is also a remote MCP server (Model Context Protocol, Streamable HTTP). Add it as a connector and the AI you already use gains persistent, portable memory — stored here, available on every connected platform. Store a fact in Claude, recall it in Gemini, with evidence receipts.

Your connector URL embeds your API key:

https://api.meemesh.com/mcp/mm_YOUR_KEY

Claude

Settings → Connectors → Add custom connector → paste the URL → Connect. Works on all plans, including free. In the connector's tool permissions, a sensible split: allow memory_search / memory_context always (read-only), keep memory_forget / memory_update on approval, and set memory_settings to never — change backend and mode from the dashboard buttons instead.

Gemini CLI

// ~/.gemini/settings.json
{ "mcpServers": { "meemesh": { "httpUrl": "https://api.meemesh.com/mcp/mm_YOUR_KEY" } } }

ChatGPT

Requires OAuth 2.1 (Phase B, in development). The tool surface will not change.

The URL is a bearer credential. Anyone holding it can read, write, and delete that user's memory. HTTPS only, never share it in screenshots or screen recordings, rotate by registering a new user if leaked.

Verify by hand

# handshake
curl -s https://api.meemesh.com/mcp/mm_YOUR_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl"}}}'

# list tools (expect 7)
curl -s https://api.meemesh.com/mcp/mm_YOUR_KEY \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

The 7 tools

The connected AI decides when to call these; you steer with plain language ("remember that…", "what do you know about…", "forget that").

ToolWhat it does
memory_searchFind relevant memories. Empty query = most recent. On meemesh, results carry verbatim evidence receipts, and abstained: true is a reliable "nothing stored". Optional filters: memory_types, time_range: {"days": n}.
memory_storeSave a durable memory with type (fact, preference, project, goal, decision, commitment, …) and importance (0–1). On meemesh the raw content is also archived verbatim in the evidence vault.
memory_updateCorrect an outdated memory. On meemesh the old engram is tombstoned and linked as superseded — history preserved, contradiction removed from recall.
memory_forgetDefault tombstone (unrecallable, audit record kept) or permanent_delete. Given only a query, returns candidates to confirm by id first.
memory_contextOne packed context packet for the current conversation (relevant memories + open commitments + recent items) within a token_budget. Called once at conversation start instead of many searches.
memory_log_turnFull-backup path: archives a conversation turn. Active only when the connection's mode is full.
memory_settingsGet/set this user's default backend and memory mode from chat. Recommended: disable in Claude's permissions and use the dashboard buttons instead.

Store a memory with type: "commitment" ("I promised to review the spec by Friday") and memory_context will surface it automatically in future conversations — on every connected platform. Prospective memory, cross-AI.

Backends & memory modes

Backend routing

Every tool accepts an optional backend; without it, the user's saved default applies (initially legacy, so connector memories are shared with this dashboard's chat from day one).

BackendBehavior over the connector
legacyClassic vector store. Always returns nearest neighbors; no evidence, no abstention. Updates and forgets are permanent (no supersedence history).
meemeshPES engrams + trace vault. Recall cites verbatim evidence or formally abstains; updates supersede with history; forgets tombstone by default.

Memory modes

ModeWhat the connected AI is instructed to do
selective defaultStore only noteworthy, durable facts via memory_store.
summariesAlso store a distilled summary at natural breakpoints (topic change, conversation end).
fullAlso call memory_log_turn after every reply, archiving the conversation. On meemesh: user turns become recallable engrams with receipts; assistant turns and low-information turns are archived in the vault but excluded from recall by design.
Mode changes take effect through the instructions the AI receives when the connector session starts — after changing the mode, disconnect and reconnect the connector. Full-mode capture is best-effort per-turn logging: the calling model occasionally skips a turn.

Connector settings endpoints

The dashboard's MCP Connector card uses these; you can call them directly.

GET/mcp-settings/{user_id}

{ "settings": { "default_backend": "legacy", "memory_mode": "selective" },
  "available_backends": ["legacy", "meemesh"],
  "available_modes": ["selective", "summaries", "full"] }

POST/mcp-settings/{user_id}

{ "default_backend": "meemesh", "memory_mode": "full" }

Settings are per user, not per platform: one change applies to every AI connected with that user's key. Invalid values return 400; unknown users 404.

Import chat history M3

Bring your existing conversations into MeeMesh: request your official data export from ChatGPT (Settings → Data controls → Export) or Claude (Settings → Privacy → Export data), then upload the zip — or the conversations.json inside it — unmodified. The format is auto-detected. This also captures history from before you ever connected MeeMesh.

POST/v1/import?source=auto&include_assistant=false&dry_run=false

# preview what an import would do (nothing is written)
curl -s "https://api.meemesh.com/v1/import?dry_run=true" \
  -H "X-API-Key: mm_YOUR_KEY" \
  --data-binary @chatgpt-export.zip

# run it
curl -s "https://api.meemesh.com/v1/import" \
  -H "X-API-Key: mm_YOUR_KEY" \
  --data-binary @chatgpt-export.zip
# → { "job_id": "imp_…", "status": "running", "conversations": 214, "total_turns": 6031,
#     "estimated_disk_mb": 52.3, … }

# poll progress
curl -s "https://api.meemesh.com/v1/import/imp_JOBID" -H "X-API-Key: mm_YOUR_KEY"

What happens to each turn — the percept/engram split doing its job:

Claude Projects caveat. Claude's export includes each Project's definition (name, description, knowledge docs) but not the conversations inside Projects. MeeMesh imports the definitions as project-type memories and the docs as semantic memories (and is forward-compatible: if a future export adds in-Project conversations, they are detected and imported as full conversations automatically). Until then, capture in-Project work live with the MCP connector (full-backup mode inside the Project), or ask the Project to write a summary and store it via memory_store.
TurnVault (evidence)Recall index
Your messagesverbatim perceptepisodic engram with receipt, timestamp backdated to the original conversation date
Assistant repliesverbatim perceptexcluded by default (include_assistant=true to index them too)
Low-information turns ("ok", "thanks")verbatim perceptgated out

Import targets the meemesh backend only — full history in the vault, recall index stays curated. Re-running the same import is safe: exact duplicates are detected by content hash before any embedding cost. Both the dry run and the import kickoff return estimated_disk_mb — roughly 18 KB per recallable memory (vector index + row) plus the compressed vault, deliberately a slight over-estimate — so check it against your free disk before committing. Caps: 20 000 turns per run, 100 MB per upload (env-tunable). Once imported, the history is a ready corpus for the consolidation daemon to distill into semantic facts. The dashboard's Import / Export card wraps all of this with a file picker and progress display.

Export your memory

Your memory belongs to you, so it can leave. One request returns everything MeeMesh holds for your user — every engram (including superseded ones, with their full audit chain) alongside its verbatim vault evidence, plus legacy vector memories.

GET/v1/export?backend=all

curl -s "https://api.meemesh.com/v1/export?backend=all" \
  -H "X-API-Key: mm_YOUR_KEY" -o meemesh_export.json
{ "exported_at": "2026-07-20T…", "user_id": "…",
  "backends": {
    "meemesh": { "count": 96, "engrams": [
      { "id": "…", "kind": "episodic", "gist": "…", "salience": 0.6,
        "ts": 1718000000.0, "valid_to": null, "superseded_by": null,
        "derived_from": [], "evidence": "verbatim original text…" } ] },
    "legacy":  { "count": 44, "memories": [ … ] } } }

backend=meemesh or backend=legacy narrows the export. The download is plain JSON — no proprietary format, no lock-in.

POST/v1/registerno auth

Create a user and receive an API key. Call once and persist the key.

// request
{ "name": "Kitchen Robot 7", "kind": "robot", "user_id": "kitchen-robot-7" }
// kind: "app" | "robot" | "human" · user_id optional (slug is generated from name)

// response
{ "ok": true, "user_id": "kitchen-robot-7", "name": "Kitchen Robot 7",
  "api_key": "mm_...", "kind": "robot",
  "usage": "Send header 'X-API-Key: <api_key>' on all /v1 requests." }

GET/v1/me

Who am I: your profile, sessions, and memory counts per system.

{ "user_id": "kitchen-robot-7", "name": "Kitchen Robot 7", "kind": "robot",
  "sessions": [ { "session_id": "default", "name": "default", "created": 1751... } ],
  "memories": { "legacy": 5, "meemesh": 12 } }

POST/v1/sessions  ·  GET/v1/sessions

Create a session / list your sessions. Creating is optional — writing to a new session_id auto-creates it.

// POST request            // POST response
{ "name": "smith-household" }   { "ok": true, "session_id": "smith-household", ... }

POST/v1/remember

Store one memory.

// request
{ "text": "Mr Smith takes his coffee black at 7am",
  "session_id": "smith-household",       // default: "default"
  "role": "note",                        // free-form tag: note | user | assistant | sensor ...
  "memory_system": "meemesh",            // default: server default (legacy)
  "place": "Smith kitchen",              // optional — resolved place identity (Phase 1.5)
  "lat": 35.6595, "lon": 139.7005 }      // optional pose enrichment; never required

// response (meemesh includes the trace receipt; places lists spatial links)
{ "ok": true, "id": "eng_9f3a1c...", "trace_ref": "vault://ab/abf3...",
  "places": ["Smith kitchen"],
  "session_id": "smith-household", "memory_system": "meemesh", "total": 13 }

Without an explicit place, meemesh conservatively extracts place mentions from the text itself ("at Blue Bottle in Shibuya" links the memory to Blue Bottle and records Shibuya as its parent). See Spatial memory.

POST/v1/recall

Semantic recall. Returns the recall contract plus scope and session_id echoes.

// request
{ "query": "how does Mr Smith take his coffee",
  "k": 5,                                // max results
  "scope": "user",                       // "user" (all sessions) | "session"
  "session_id": null,                    // required when scope = "session"
  "place": null,                         // set -> spatial recall ("what happened at X")
  "memory_system": "meemesh" }

// spatial recall: place is the filter, query (optional) re-ranks within it
{ "place": "Tokyo", "query": "investor meeting", "memory_system": "meemesh" }

// spatial response adds the resolved place and per-hit place_path receipts
{ "results": [ { ..., "meta": { ..., "place_path": ["Blue Bottle","Shibuya","Tokyo"] } } ],
  "abstained": false, "reason": null,
  "place": { "name": "Tokyo", "path": ["Tokyo"] }, "memory_system": "meemesh" }

GET/v1/memories?limit=25&session_id=&memory_system=

Most recent memories, newest first — a browse view, no semantic search.

POST/v1/chat

One-call convenience: recalls relevant memories, injects them into the system prompt, calls the LLM, and (optionally) stores the exchange as new memories.

// request
{ "provider": "openai",                 // openai | gemini | deepseek | ollama
  "model": "gpt-4o-mini",
  "message": "What do you know about Mr Smith?",
  "session_id": "smith-household",
  "k": 5,
  "store": true,                         // store this turn as memories
  "recall_scope": "user",
  "memory_system": "meemesh" }

// response
{ "reply": "...", "used_memories": [ ...recall results... ],
  "abstained": false, "abstain_reason": null,
  "memory_system": "meemesh", "provider": "openai", "model": "gpt-4o-mini",
  "user_id": "kitchen-robot-7", "session_id": "smith-household", "total": 15 }

When the memory system abstains, the model is explicitly told no relevant memories exist, so it answers honestly instead of hallucinating a recollection.

POST/v1/forget

Delete your memories. Scope by session and/or memory system; defaults are broad.

// request — both fields optional
{ "session_id": "smith-household",   // null -> ALL your sessions
  "memory_system": "meemesh" }       // null -> ALL memory systems

// response
{ "ok": true, "deleted": { "meemesh": 12 }, "total": { "legacy": 5, "meemesh": 0 } }

GET/v1/places  ·  POST/v1/placesPhase 1.5

GET lists your place entities — the spatial index of your memory — with containment paths and live memory counts.

// GET /v1/places?limit=100
{ "places": [
    { "id": "plc_4d2e...", "name": "Blue Bottle", "kind": "place",
      "lat": 35.6595, "lon": 139.7005, "parent_id": "plc_a1b2...",
      "path": ["Blue Bottle", "Shibuya", "Tokyo"],
      "memory_count": 3, "salience": 0.7, "attrs": {} } ],
  "memory_system": "meemesh" }

POST declares a place explicitly: containment, coordinates, attributes, or an alias link (the non-destructive merge for duplicate names).

// state containment — explicit declarations may re-parent
{ "name": "Shibuya", "parent": "Tokyo" }

// merge a duplicate name into its canonical place
{ "name": "Blue Bottle Shibuya", "alias_of": "Blue Bottle" }

// response
{ "ok": true, "place": { ..., "path": ["Shibuya", "Tokyo"] }, "memory_system": "meemesh" }

Attributes (attrs) describe an already-identified place — "quiet", "has wifi" — and are never used as identity criteria.

POST/v1/seePhase 4

Store one visual memory. Base64 image bytes only — no data: prefix, no URLs. Allowed mimes: jpeg, png, webp, gif.

// request — caption path (no server-side model call)
{ "image_b64": "<base64>", "mime": "image/jpeg",
  "caption": "Team lunch at Blue Bottle in Shibuya",
  "session_id": "default",
  "place": "Blue Bottle",                // optional resolved place (Phase 1.5)
  "lat": 35.6595, "lon": 139.7005,       // optional pose enrichment
  "memory_system": "meemesh" }

// request — describe path (server-side multimodal model)
{ "image_b64": "<base64>", "mime": "image/png",
  "hint": "photo of our planning whiteboard" }   // optional context

// response
{ "ok": true, "id": "eng_9f3a1c...", "gist": "A whiteboard covered in ...",
  "media_sha": "4be1...64-hex...", "trace_ref": "vault://4b/4be1...",
  "capture_conf": 0.82, "modality": "vision", "places": ["Blue Bottle"],
  "session_id": "default", "memory_system": "meemesh", "total": 14 }

// duplicate image (same bytes, same scope): reinforced, not re-stored
{ "ok": true, "id": "eng_9f3a1c...", "media_sha": "4be1...", "deduplicated": true }

Without a configured vision provider the describe path returns 502 with an explanation — the caption path always works. Oversize or invalid images are rejected with 400 before anything is stored.

POST/v1/hearPhase 5

Store one audio memory. Base64 audio bytes only — no data: prefix, no URLs. Allowed mimes include mp3, wav, m4a/mp4, aac, webm, ogg, flac.

// request — transcript path (no server-side model call)
{ "audio_b64": "<base64>", "mime": "audio/m4a",
  "transcript": "Standup recap: demo moved to Thursday at the Marina Bay office",
  "session_id": "default",
  "place": "Marina Bay office",          // optional resolved place (Phase 1.5)
  "lat": 1.2839, "lon": 103.8607,        // optional pose enrichment
  "memory_system": "meemesh" }

// request — transcribe path (server-side model)
{ "audio_b64": "<base64>", "mime": "audio/webm",
  "hint": "voice note about the investor demo" }   // optional context

// response
{ "ok": true, "id": "eng_2c8d0e...", "gist": "A voice note about ... Transcript: ...",
  "transcript": "Remember the investor demo is moved to Thursday ...",
  "media_sha": "9d27...64-hex...", "trace_ref": "vault://9d/9d27...",
  "capture_conf": 0.74, "modality": "audio", "places": ["Marina Bay office"],
  "session_id": "default", "memory_system": "meemesh", "total": 15 }

// duplicate recording (same bytes, same scope): reinforced, not re-stored
{ "ok": true, "id": "eng_2c8d0e...", "media_sha": "9d27...", "deduplicated": true }

Without a configured audio provider the transcribe path returns 502 with an explanation — the transcript path always works (pairs naturally with on-device STT). Oversize or invalid recordings are rejected with 400 before anything is stored.

GET/v1/modalitiesPES v2.1

The open modality registry: every registered sense with its media class, mime allowlist, size cap, and capture module — plus the ordered write-time gate pipeline. No authentication required.

// response
{ "modalities": [
    { "name": "text",   "media_class": "rich", "allowed_mimes": null,  "max_bytes": null, ... },
    { "name": "vision", "media_class": "rich", "allowed_mimes": ["image/jpeg", ...], "max_bytes": 8388608, ... },
    { "name": "audio",  "media_class": "rich", "allowed_mimes": ["audio/mpeg", ...], "max_bytes": 16777216, ... } ],
  "gates": ["low_information", "bare_question"] }

GET/v1/media/{sha}Phase 4

Fetch the verbatim media (image or recording) behind a memory — the receipt. sha comes from media_sha on a recall hit, /v1/memories row, or a /v1/see / /v1/hear response. Responds with the raw bytes and original mime type.

curl -s "https://api.meemesh.com/v1/media/4be1...&memory_system=meemesh" \
  -H "X-API-Key: mm_YOUR_KEY" -o receipt.jpg

Strictly ownership-checked: media resolves only for the user whose engram references it; everyone else gets 404 (no existence oracle). Forgetting the memory garbage-collects the media from the vault.

DELETE/v1/me

Self-service account deletion: removes the user, all sessions, and all memories in every system. The API key stops working immediately. Irreversible.

GET/memory_systemsno auth

Registered memory systems with capability flags — use it to build system pickers or feature-gate on capabilities.

{ "memory_systems": [
    { "name": "legacy",  "label": "Legacy (vector store)",  "description": "...",
      "capabilities": { "abstention": false, "evidence": false, "multimodal": false,
                        "spatial": false, "consolidation": false }, "default": true },
    { "name": "meemesh", "label": "MeeMesh PES (engrams)",  "description": "...",
      "capabilities": { "abstention": true,  "evidence": true,  "multimodal": false,
                        "spatial": false, "consolidation": false }, "default": false }
  ],
  "default": "legacy" }

GET/healthno auth

Service status: per-system memory counts, user count, embedding config, and which LLM providers are enabled.

Python example

import requests

BASE = "https://api.meemesh.com"

# one-time setup
key = requests.post(f"{BASE}/v1/register",
                    json={"name": "My Agent", "kind": "app"}).json()["api_key"]
H = {"X-API-Key": key}

# store
requests.post(f"{BASE}/v1/remember", headers=H, json={
    "text": "Project codename is Blue Lantern",
    "memory_system": "meemesh",
})

# recall — handle abstention
out = requests.post(f"{BASE}/v1/recall", headers=H, json={
    "query": "what is the project codename",
    "memory_system": "meemesh",
}).json()

if out["abstained"]:
    print("No memory of that:", out["reason"])
else:
    top = out["results"][0]
    print(top["text"], "| confidence:", top["confidence"])
    print("evidence:", top["evidence"])

Errors

StatusMeaning
400Bad request — e.g. unknown memory_system, or scope: "session" without a session_id. The detail field explains.
401Invalid or missing X-API-Key.
404Unknown user or session.
502An upstream LLM provider failed (chat only); detail carries the provider error.
An abstained recall is not an error — it returns 200 with "abstained": true. Design your integration to branch on it.

Interactive explorer

A machine-generated OpenAPI explorer (Swagger UI) is available at /docs — try any endpoint live from the browser. This page is the curated guide; /docs is the exhaustive schema reference.

MeeMesh Memory Service · memory with receipts