Reading a workspace back
memory:inspect lists what a workspace actually holds - the stored chunks, the
graph nodes and edges, and the execution-log steps - without requiring a search query.
It is a diagnostic and audit surface, not a retrieval path. Use it to check
what a writer produced, to audit stored history, or to hand someone a complete
account of what you hold about them. Don't use it to feed an agent - that's what
memory:query is for.
It is addressed by scope, so it reads a subject scope exactly as it
reads an agent workspace: POST /v1/scopes/{scopeId}/memory:inspect, with
/v1/agents/{id}/memory:inspect serving the same operation for agent-shaped
callers. That matters for the last of those uses above, because what one subject's
memory amounts to is a question about a subject scope. The console reads it too, on
either kind's detail page, with the same paging and the same pinning to a single
instant described below; it is read-only there, and commits and supersessions stay
in the CLI and the SDK.
Requesting sections
Each section is requested by including it; leave one out and it isn't read. All present sections are evaluated at one snapshot, so they agree with each other.
{
"vectors": { "limit": 50 },
"graph": { "nodeLimit": 100, "edgeLimit": 100 },
"log": { "limit": 50 }
}
Chunks come back with their content and metadata but never their embedding vector - it is large and unreadable, and no caller has wanted it.
Paging to the end
Every listing is bounded, and the bounds are lower than people expect:
| Section | Default | Maximum per page |
|---|---|---|
vectors |
50 | 200 |
graph nodes |
100 | 500 |
graph edges |
100 | 500 |
log |
50 | 200 |
A busy workspace passes those within its first year, so a single response is a page, not an inventory. Each section returns its own continuation token; feed it back on the next request until the token comes back empty:
The response carries one token per listing:
{
"vectors": { "chunks": [ ... ] },
"nextChunkToken": "CjE3NTQw...",
"nextNodeToken": "",
"nextEdgeToken": "",
"nextLogToken": ""
}
Pagination completion
An empty token indicates that the entire result set has been returned. The pagination loop terminates when pageToken is empty, not upon receiving a short page.
Sections exhaust independently. A workspace with thousands of chunks and a few hundred log steps will report the log done while chunks keep going - keep paging each listing on its own token.
Consistency while you page
By default each page is read at its own instant, so a commit landing mid-walk can show up. That's usually fine for a debug listing and wrong for an audit.
For a stable walk, set asOf to the read timestamp of your first page and
send the same value on every subsequent request:
Every page then observes the workspace as it was at that instant. The first
response's readTimestamp is the value to pin.
asOf cannot reach back indefinitely
Historical reads are bounded by the backend's version-retention window, about
an hour. A walk that takes longer than that will start failing on stale-read
errors, so for a very large workspace either page faster (raise limit to the
maximum) or accept the unpinned walk.
Tokens are opaque
Tokens are server-generated position cursors:
- Do not construct or modify tokens. Invalid tokens return INVALID_ARGUMENT.
- Tokens are scoped to specific workspaces. Tokens cannot be used across different scopes.
- Tokens are transient. Do not store tokens as persistent bookmarks.
Worked example
Reading every chunk in a workspace:
token, chunks = "", []
while True:
body = {"vectors": {"limit": 200}}
if token:
body["vectors"]["pageToken"] = token
r = post(f"/v1/agents/{agent_id}/memory:inspect", body)
chunks += r["vectors"]["chunks"]
token = r.get("nextChunkToken", "")
if not token:
break # exhausted - not merely a short page
Auditing embedding truncation across stored chunks? That's the same call - see Chunking.
Listings include superseded memories, since inspect reports what a workspace holds rather than what is current. Each chunk carries its validity window - see Temporal memory.