---
title: "Read Batch"
method: POST
path: "/api/v1/memory/read-batch"
tags: ["memory-v1"]
---

# Read Batch

`POST /api/v1/memory/read-batch`

## Request

- Base URL: `https://core.mnemoverse.com`
- URL: `https://core.mnemoverse.com/api/v1/memory/read-batch`
- Auth: one of:
  - API key in header `X-Api-Key`
  - HTTP bearer

Batch read up to 50 queries.

## Request body

- ReadBatchRequestSchema: Batch read request (up to 50 queries).
  - `queries` ReadRequestSchema[], required: List of read queries (max 50).
    - `query` string, required: Natural language or semantic query.
    - `top_k` integer: Maximum number of items to return. Cap raised from 100 to 500 for benchmark k-sweep (k=200 cells). Per-call rate-limit policy still applies; downstream cost scales linearly.
    - `domain` string, nullable: Optional domain filter (null = all domains).
    - `min_relevance` number: Minimum relevance score threshold.
    - `fingerprint` string, nullable: Optional fingerprint for O(1) episodic exact match.
    - `include_associations` boolean: Whether to expand results via Hebbian concept associations.
    - `concepts` string[]: Optional concept hints to bias search. Capped at 50 to bound parallel embed fan-out in expand_concepts_via_embeddings; the auto-extract path already caps at config.max_query_concepts (10).
    - `two_pass` boolean, nullable: Per-request override for two-pass retrieval. null = use engine config default (Settings.two_pass_enabled). Forwarded to ReadRequest.two_pass; consumed by memory_engine._gate at line 1775.
    - `strategy` 'auto' | 'precise' | 'multi_hop' | 'temporal' | 'exhaustive', nullable: Per-request override for retrieval strategy. null = engine default (no override). 'auto' triggers the LLM classifier → heuristic fallback (memory_engine.py:1739). Named values ('precise', 'multi_hop', 'temporal', 'exhaustive') resolve via STRATEGY_CATALOG. Anything else returns 422 from FastAPI before reaching the engine.
    - `include_timings` boolean: Opt-in per-phase timing dict on the response (TRACING_SPEC §2): phase wall-times in ms (embed_query_ms, vector_search_ms, db_touch_ms, ...) plus n_embed_calls / n_vector_searches / n_db_roundtrips counters. Off by default so the response payload is unchanged for existing clients; the server-side read_completed log line carries the same dict regardless.
    - `order_by` 'relevance' | 'recency': Result ordering. 'relevance' (default) = engine ranking, unchanged. 'recency' = stable re-sort of the final assembled result by created_at DESC (items without a stored timestamp sort last); list length and channel composition are unchanged. This still passes the semantic gate — a pure newest-first feed is #404 R5, a separate endpoint.
    - `since` string, date-time, nullable: Only return items created at or after this ISO-8601 instant (inclusive). Naive datetimes are interpreted as UTC. Applied as an engine post-filter on the assembled result (same placement as the authorship filters): items without a stored timestamp are excluded, and the page may return fewer than top_k when the bound excludes candidates — the queryless feed (#404 R5) is the complete view.
    - `until` string, date-time, nullable: Only return items created at or before this ISO-8601 instant (inclusive). Same UTC/naive, missing-timestamp, and post-filter semantics as `since`. Must be >= since when both are set (422 otherwise).
    - `exclude_author` string, nullable: Drop items whose provenance.principal equals this value — the 'everyone but me' read in shared rooms (#404 R4). Complement of author_principal; the two may combine. Same post-filter semantics as `since`.
    - `include_history` boolean: Return superseded revisions alongside live ones; each carries `superseded_by`, and every item carries `supersedes` when it replaced something. History is returned in the domain where each revision is stored: a read scoped to the successor's domain does not include a cross-domain predecessor — use an unscoped read or `GET /memory/atoms/{id}`. History items compete under normal ranking, `min_relevance` and `top_k`/`limit` — `include_history` grants eligibility, not chain completeness; for the chain itself use `GET /memory/atoms/{id}/chain`, which spends a 64-LOOKUP budget per call (resolved revisions AND dangling-pointer misses both count) and sets `truncated` when the budget ran out — so `truncated` means the walk stopped early, not that the chain necessarily holds more than 64 revisions. One exception to the domain rule above: when a fingerprint matches a revision that has been replaced, the live tip is returned alongside it even if that tip lives in another domain — the episodic index is domain-blind, and this makes it two atoms rather than one. No effect until the read-side supersession filter is enabled (nothing is hidden before then, so nothing needs unhiding), and inert for `xroom:<room_id>` domains, whose atoms cannot be superseded at all.
    - `diversity` number: 0 (default) leaves the ranking as it is: the ranked candidates are cut to `top_k`. A value above 0 turns the cut into a maximal marginal relevance selection: items are picked one at a time, each the one that best trades its relevance against its cosine similarity to the items already picked (weight `diversity` on the similarity, `1 - diversity` on relevance), so a near-copy of something already in the answer loses its slot to the next distinct item. 1 means similarity alone decides after the first pick. Applied after outcome feedback and recency have re-ranked, on the ranked pool of up to 200 candidates that cleared `min_relevance`, and only when `top_k` is below 200 (at 200 or more the plain cut applies); pinned fingerprint revisions and the association-reserved slots are unchanged. It changes which items are returned, not their scores.
    - `author_principal` string, nullable: Only return atoms written by this principal.
    - `author_agent` string, nullable: Only return atoms written by this agent id.
    - `author_client_env` string, nullable: Only return atoms written from this client env (cursor·claude·chatgpt·chat·api·unknown).
    - `author_is_external` boolean, nullable: Filter by authorship class: true = external only, false = internal only, null = no filter.

## Response `200`

Successful Response

- ReadBatchResponseSchema: Response from batch read.
  - `results` ReadResponseSchema[], required: Per-query results.
    - `items` MemoryItemSchema[], required: List of matching memory items, ordered by relevance.
      - `atom_id` string, uuid, required: Unique identifier of the atom.
      - `content` string, required: Stored text content of the memory.
      - `relevance` number, required: Final score after valence modulation: score * (1 + alpha * v).
      - `similarity` number, required: Raw cosine similarity from pgvector search.
      - `valence` number, required: Outcome polarity [-1, +1]: positive = successful, negative = failed.
      - `importance` number, required: Importance score in [0, 1] from L4 gate.
      - `source` string, required: Retrieval stage that found this item. Production reads return semantic, concept_scoped (found under a concept extracted from the query) and hebbian_retrieval (missed by the direct stages and reached through learned associations, via a concept the query did not name); episodic marks an exact fingerprint match. Other stage names can appear: treat an unknown value as one more stage.
      - `concepts` string[], required: Concepts associated with this atom.
      - `domain` string, required: Domain/namespace of the atom.
      - `metadata` object: Arbitrary key-value metadata.
      - `provenance` ProvenanceSchema: Server-stamped authorship of an atom (CN-001). Returned (as the optional `provenance` object on a read item) only when at least one field is non-null; an atom with no recorded authorship omits the whole object. Stamped from VERIFIED JWT claims at write time — never client-supplied.
        - `principal` string, nullable: The person/principal who wrote it.
        - `agent` string, nullable: Stable agent identifier, if any.
        - `agent_name` string, nullable: Human-readable agent name, if any.
        - `client_env` string, nullable: Calling client environment: cursor·claude·chatgpt·chat·api·unknown.
        - `is_external` boolean: True when the principal is external to the org.
      - `created_at` string, date-time, nullable: UTC creation instant of the atom, ISO-8601 (#404 R1). OMITTED for legacy atoms that predate timestamping — same omission pattern as `provenance`, so their payload shape is unchanged.
      - `supersedes` string[]: Ids of the revisions this item replaced. OMITTED when this item replaced nothing.
      - `superseded_by` string, uuid, nullable: Id of the revision that replaced this one. OMITTED while this item is the live tip. Present means the item is history — reported as a fact of the data regardless of server settings: while the read-side supersession filter is off, ordinary reads still return replaced revisions and this field is how you tell. Once the filter is on, history reaches a read only via `include_history`. The id names the IMMEDIATE successor as of the moment of replacement and carries no FK — if that successor was later destroyed, a GET on it is a documented 404, and `GET /memory/atoms/{id}/chain` reports the break rather than failing.
    - `episodic_hit` boolean, required: True if an exact episodic (fingerprint) match was found.
    - `query_concepts` string[], required: Concepts extracted or used for the query.
    - `expanded_concepts` string[], required: Concepts expanded via Hebbian associations.
    - `search_time_ms` number, required: Search duration in milliseconds.
    - `timings` object, nullable: Per-phase wall times in ms + call counters (TRACING_SPEC §2). Present only when the request set include_timings=true; an absent phase key means the phase was skipped.

## Other responses

- `400`: Validation error
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not found
- `422`: Validation Error
- `429`: Rate limited
- `500`: Internal server error
- `503`: Service unavailable

---

[API](https://skmtc.dev/mnemoverse/apis/mnemoverse-core.md) · [All operations](https://skmtc.dev/mnemoverse/apis/mnemoverse-core/llms.txt) · [OpenAPI document](https://skmtc.dev/mnemoverse/apis/mnemoverse-core/revisions/1f5e0048f017?raw)
