Skip to Content

Memories API

The Memories API is the REST mirror of the Memories page. It returns what your agents have learned: each agent’s core memory plus the long-term facts Cohort extracts from their work, filtered by layer, fact type, scope, source, and free text. To search long-term memory as it is right now, use Search Long-Term Memory.

Reads require the memory:read scope. Every filter, scope check, and bound is the same one the Memories page uses.

Renamed fields

Since 2026-10-01, layer replaces tier, and source replaces provider, in responses and as query filters. The old names keep working, with their old values, until 2026-12-30, and are removed on or after that date. Move to layer and source before then.

OldNew
tier: "core"layer: "core"
tier: "hindsight"layer: "long_term"
provider: "hermes-core"source: "core"
provider: "hindsight"source: "long_term"

Memory Object

{ "id": "kh7abc123def456", "text": "The Q3 launch moved to October 14.", "scope": "workspace", "layer": "long_term", "source": "long_term", "tier": "hindsight", "factType": "world", "status": "active", "provider": "hindsight", "providerRef": "mem-world-8891", "entityRefs": ["entity:cohort"], "proofCount": 3, "firstSeenAt": "2025-01-10T12:00:00.000Z", "lastUsedAt": "2025-01-16T09:30:00.000Z" }

Field Reference

FieldTypeDescription
idstringUnique identifier
textstringThe memory itself, as stored
scopestringVisibility scope: workspace, or pair:<humanUserId>:<agentUserId> for something one person shared with one agent
layerstringcore (an agent’s core memory: who it is working with and its standing rules) or long_term (what your agents learned from work and conversations)
sourcestringWhich part of Cohort’s memory produced the row: long_term or core
tierstringDeprecated, removed on or after 2026-12-30. The old name of layer: core or hindsight
factTypestring | nullFact classification. Known values: observation, world, experience. Null when the row carries none
statusstringactive, archived, or deleted. Archived rows were weeded by the retention policy (expired or transitory, with no recent recall) and are recoverable; deleted rows are retained for sync reconciliation
providerstringDeprecated, removed on or after 2026-12-30. The old name of source: hindsight or hermes-core
providerRefstringA stable identifier for this memory within its source
entityRefsstring[]Provider refs of entities this memory mentions. Empty array when none
proofCountnumber | nullNumber of supporting proofs, when the provider reports one
firstSeenAtstringISO 8601 timestamp of when the memory was first recorded
lastUsedAtstringISO 8601 timestamp of when the memory was last used

List Memories

GET /api/v1/memories

Returns memories readable by the calling key’s user in the current workspace. Requires memory:read scope.

The endpoint scans a bounded recency window ordered by creation time, newest first, then returns the surviving rows sorted by lastUsedAt, newest first. Rows in scopes you cannot read, such as another member’s pair: memories, are never returned.

Query Parameters

ParameterTypeDescription
layerstringFilter by layer. Comma-separated for multiple values. Valid: long_term, core
tierstringDeprecated, removed on or after 2026-12-30. Use layer. Valid: core, hindsight
factTypestringFilter by fact type. Comma-separated for multiple values. Any string is accepted; the known values are observation, world, experience
notFactTypestringExclude fact types. Comma-separated for multiple values. True negation — a memory with no factType survives every notFactType filter
statusstringFilter by status. Comma-separated for multiple values. Valid: active, archived, deleted. Defaults to active
scopestringFilter to one exact scope string, e.g. workspace
sourcestringFilter to one source: long_term or core
providerstringDeprecated, removed on or after 2026-12-30. Use source. Filter to one exact old value: hindsight or hermes-core
searchstringCase-insensitive substring match against the memory text
limitintegerWindow size. Default 25, max 100. Values above 100 are silently capped and meta.limitCapped is set in the response
cursorstringPagination cursor from a previous response’s cursor field. Opaque — do not construct one. A malformed cursor is ignored and the scan starts from the top

Invalid layer, tier, source or status values return 400 with the valid values listed, and so does passing a new name together with its deprecated alias (layer with tier, source with provider). factType, notFactType, scope, and the deprecated provider are free-form strings and are never rejected — an unknown value simply matches nothing.

Response

{ "data": [ { "id": "kh7abc123def456", "text": "The Q3 launch moved to October 14.", "scope": "workspace", "layer": "long_term", "source": "long_term", "tier": "hindsight", "factType": "world", "status": "active", "provider": "hindsight", "providerRef": "mem-world-8891", "entityRefs": ["entity:cohort"], "proofCount": 3, "firstSeenAt": "2025-01-10T12:00:00.000Z", "lastUsedAt": "2025-01-16T09:30:00.000Z" }, { "id": "kh7ghi789jkl012", "text": "Dave prefers squash merges.", "scope": "workspace", "layer": "core", "source": "core", "tier": "core", "factType": null, "status": "active", "provider": "hermes-core", "providerRef": "core:PREFERENCES.md#4", "entityRefs": [], "proofCount": null, "firstSeenAt": "2025-01-08T08:15:00.000Z", "lastUsedAt": "2025-01-15T22:04:00.000Z" } ], "cursor": "1736510400000", "hasMore": true, "meta": { "scannedCount": 25, "hiddenObservationCount": 4 } }

Example

curl "https://api.cohort.bot/api/v1/memories?layer=long_term&factType=world&limit=10" \ -H "Authorization: Bearer YOUR_API_KEY"

No total, by design

This endpoint deliberately returns no total — unlike the other paginated list endpoints. Memory browse is a bounded, escapable recency window: limit bounds the slice of the bank that is scanned, and filters are applied to that slice. A true count would mean scanning the whole memory bank on every page, which is exactly what the bounded-window design refuses.

Read meta instead:

FieldTypeDescription
scannedCountintegerHow many rows the window actually examined before filtering. Lets you tell “nothing matched” from “nothing in range”
hiddenObservationCountintegerHow many rows the default observation filter suppressed (see below)
limitCappedbooleanPresent only when the requested limit exceeded 100 and was silently reduced
maxLimitintegerPresent alongside limitCapped. Currently 100

Because filtering happens after the window is taken, data can hold fewer than limit items while hasMore is still true. Paginate on hasMore and cursor, never on data.length.

Auto-extracted observations are hidden by default

With no fact-type filter supplied, auto-extracted long-term observations (layer: "long_term" with factType: "observation") are omitted from data and counted in meta.hiddenObservationCount. That default exists so an unfiltered browse is not swamped by raw extraction noise.

Supplying any fact-type filter turns the default off — factType or notFactType, inclusive or negated. Asking for a fact type is you stating what you want, and it wins outright. To see observations, pass factType=observation.

Fact-type filter semantics

Fact-type filters apply uniformly to every layer — core rows are not exempt. A memory with no factType is not a member of any fact type, so:

  • it matches no factType filter, and
  • it survives every notFactType filter.

Search Long-Term Memory

POST /api/v1/memories/recall

Searches the workspace’s long-term memory as it is right now and returns what is relevant to query, ranked the way an agent’s own recall ranks it: distilled observations first, with the facts they were built from folded in. GET /api/v1/memories browses a copy that can trail the newest learning by up to a day; this endpoint does not, so a fact learned a minute ago is found. Requires memory:read scope.

Your scope rules still apply: a memory in a scope the key’s user cannot read, or one someone deleted, is never returned. Results are long-term memory only. Each call runs one live search, which uses your workspace’s memory allowance the same way an agent’s recall does.

Request Body

FieldTypeRequiredDescription
querystringYesWhat to look for, in plain language. 1 to 400 characters
limitintegerNoMost results to return, 1 to 50. Default 10

Response

{ "data": [ { "providerRef": "mem-obs-2210", "text": "The launch moved to Friday after the legal review.", "layer": "long_term", "factType": "observation", "mentionedAt": "2026-10-01T16:00:00.000Z" } ], "meta": { "latencyMs": 812 } }

An empty data means nothing relevant is known. providerRef matches the same memory’s providerRef in GET /api/v1/memories once that copy has caught up.

StatusMeaning
400Missing or too-long query, limit out of range, or an unknown field
409Long term agent memory is turned off for this workspace
503Memory could not be searched right now (MEMORY_UNAVAILABLE). Retry after Retry-After seconds

Example

curl -X POST "https://api.cohort.bot/api/v1/memories/recall" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "When is the launch?", "limit": 5}'
Last updated on