membral
Membral is an MCP server that lets agents search, recall, and read your saved coding-agent sessions and chats.
Search extracted memory records by topic with
memory_search, filtering by kind, scope, project, path, and time.Recall outcome, decision, learning, blocker, or preference records by repo or file path with
memory_recall.Retrieve coding sessions by ID with
get_code_session, including paged turns, files touched, summaries, and sub-agents.Retrieve chat conversations by ID with
get_conversation, with paging and optional tool input/output.List coding projects and recent chats or coding sessions with
list_code_projectsandlist_recent_conversations.Get a short session story or journey with
session_summary.Search raw synced conversations and coding sessions by keyword/semantic similarity with
search_conversations.Mark blockers as fixed with
memory_resolveby quoting the fix from your own or the user's message.Results are dated records of what sessions did, not live PR, issue, deployment, or repo state.
Captures GitHub Copilot CLI and VS Code Copilot Chat transcripts, syncs them into the local store, and exposes memory search to Copilot through MCP.
Runs local embeddings with nomic-embed-text and can serve as the extraction model provider, such as qwen2.5:7b, for processing session turns.
Supports an OpenAI API key as an extraction-model provider for deriving decisions, learnings, and outcomes from session turns.
Membral
Your coding agent can answer from what your past sessions found, including what nobody wrote down.
Membral saves your coding-agent sessions (Claude Code, Codex, opencode, Copilot, Antigravity) in one store on your machine, extracts the decisions, learnings and outcomes, and lets your agents search them.
How it fits together
flowchart LR
you([You])
subgraph inputs["Where your work happens"]
direction TB
subgraph agents["Coding agents"]
direction TB
cc[Claude Code]
cx[Codex CLI]
oc[opencode]
cp["GitHub Copilot<br/>CLI and VS Code"]
ag[Antigravity]
end
subgraph chats["Chat apps"]
direction TB
gpt[ChatGPT]
cai[Claude.ai]
end
end
cli["membral CLI<br/>hooks · 20-min sweep · import"]
ext["Chrome extension"]
subgraph stack["Your machine · membral local up (Docker)"]
direction TB
api["Membral app<br/>API · dashboard"]
mcp["MCP server<br/>memory_search · get_code_session · …"]
extract["Extraction<br/>runs on a timer"]
db[("Postgres + pgvector<br/>sessions · turns · memories")]
end
llm["Extraction model<br/>Claude login · Ollama 7B+ · API key"]
emb["Ollama on your machine<br/>nomic-embed-text"]
you -->|prompts| agents
you -->|chats| chats
agents -->|transcripts on disk| cli
chats -->|export file| cli
chats -->|open chat pages| ext
cli -->|upload sessions| api
ext -->|sync chats| api
api -->|store| db
db -->|new sessions| extract
extract <-->|turns in, records out| llm
extract -->|decisions · learnings · outcomes| db
api <-->|text in, vectors out| emb
agents <-->|MCP tool calls| mcp
mcp <-->|search| db
api -->|preamble · prompt lookup| cli
cli -->|added to the agent's context| agents
api -->|dashboard| you
style stack stroke-dasharray: 6 4In. The membral CLI reads each agent's transcripts from disk (end-of-session hooks and a 20-minute sweep) and
uploads them. Chats come in through the Chrome extension or an export file.
Stored and processed. The app keeps sessions, turns and memories in Postgres with pgvector. A timed job sends new turns to an extraction model and stores the decisions, learnings and outcomes that come back. A local embedding model turns text into vectors so search can compare meaning.
Back to your agent. Agents search over MCP. The CLI adds a preamble at session start and, in Claude Code, matching records at each prompt. The dashboard shows everything stored.
Related MCP server: ChatCrystal
What it does
One store for sessions from every agent, in one shape: turns, models, token usage, tools, files and sub-agents.
Extracts decisions, learnings and outcomes, each with its quote and a link to the session.
Searches by meaning, with keyword search as the fallback.
MCP tools (
memory_search,memory_recall,get_code_session) for any MCP-capable agent. Clients that only speak stdio can runmembral mcp.A session-start preamble and, in Claude Code only, prompt-time lookup.
ChatGPT and Claude.ai chats saved next to your coding sessions, and a dashboard to browse it all.
It is not live state: whether a PR is merged or what is deployed is checked in your forge. One store per person; no team or admin controls yet.
Run it locally
You need Node 22.5+ with Git, Docker with Compose 2.23+ (40 GiB of VM disk), Ollama for embeddings, and one extraction model (step 3).
Install the CLI from a clone. This builds it and installs it globally:
git clone https://github.com/surajtripathy07/membral && cd membral && npm ci && npm run cli:installPull the embedding model:
ollama pull nomic-embed-textPick an extraction model by putting one choice in
~/.membral/local/.env(mkdir -p ~/.membral/localfirst):Claude subscription:
MEMBRAL_LLM_PROVIDER=claude-codeandCLAUDE_CODE_OAUTH_TOKEN=<from claude setup-token>API key:
OPENAI_API_KEY=...(orOPENROUTER_API_KEY)Ollama: a 7B+ model such as
qwen2.5:7b, run withOLLAMA_CONTEXT_LENGTH=16384 ollama serve
Start it:
membral local up --embeddings ollamaCheck it:
membral local status(it prints anEmbeddings: ...line).
up prints a sign-in URL and password and an API key; treat that output as a secret. The app is at
http://localhost:3000. The image is multi-arch (amd64 and arm64); if a pull fails, build it locally and pass --image. Image source builds, extraction setup, disk, logs, Linux notes and what works without an
extraction model are in docs/SELF-HOSTING.md.
To run a second stack beside it (for example to test a branch), add --project <name> to local up|down|status|logs
(or set MEMBRAL_LOCAL_PROJECT) and pass free --port and --gateway-port values. Its files live in
~/.membral/local-<name> and its Docker volumes end in -<name>; the default stack is untouched. Both stacks write
the one local CLI profile, so the last up wins.
Why embeddings
Search compares meaning, so a question worded differently from the saved text still finds it. Without an embedder,
memory_search works on keywords only and says so ("SEARCH DEGRADED ... keyword-only results"), and the relevance
floor that drops weak matches is off. nomic-embed-text is the model whose thresholds are calibrated in this repo
(apps/cloud/src/lib/memory/similarity.ts). It runs on Ollama on your machine, so record text never leaves it.
Vectors are 1,536 wide, and smaller models are zero-padded. Chat and session-text search (search_conversations) is calibrated only for text-embedding-3-small, so with
nomic-embed-text it stays keyword-only and says so. The claude-code provider does no embeddings.
Chrome extension
It syncs ChatGPT and Claude.ai chats to your local stack.
npm run build --workspace=@membral/extension(targetshttp://localhost:3000; for another port build withVITE_CLOUD_URL=http://localhost:<port>, or save a Server URL in the options page, where Chrome asks permission).In
chrome://extensions, turn on Developer mode, choose Load unpacked, pickpackages/extension/dist.In the options page, paste the API key
membral local upprinted (it startslls_) and Save. The popup shows the server and "Connected with an API key".
Supported agents
Agent | Capture | Sync | MCP | Preamble |
Claude Code | yes | yes | yes | yes |
opencode | yes | yes | yes | yes |
GitHub Copilot (CLI + VS Code Copilot Chat) | yes | yes | yes | yes |
Codex CLI | yes | yes | yes | yes |
Antigravity | yes | yes | yes | yes |
Capture reads the agent's transcripts. Sync is membral sessions plus the sweep. MCP is search by the agent. The
preamble is added at session start. The per-prompt lookup is Claude Code only. A Claude Code plugin is an
alternative to the CLI hooks (docs/SELF-HOSTING.md).
Where your data goes
The local stack keeps everything on your machine. The exceptions are model calls: with an API key, session text
goes to that provider, and with a Claude login, to Anthropic through Claude Code. Saved: prompts, replies, tools
called, files touched and text written to files (capped). Tool output is not kept. Secrets are redacted by
pattern, and files such as .env keep no text. You choose which projects sync (~/.membral/sync.json).
To skip throwaway scratch directories, add path patterns to that file (* matches any characters):
{"excludePathPatterns":["/private/var/folders/*/membral-lab-*"]}. A project listed with enabled: true still syncs.
Commands
membral local up | status | logs <service> | downruns the stack (down --wipedeletes the data).membral setup,login(defaulthttp://localhost:3000),use,sessions,import <export.json>andstatus.membral --helplists every command.npm run smokechecks the dashboard renders the fixtures.
More
docs/SELF-HOSTING.md covers the stack in depth. CONTRIBUTING.md goes from clone to green gate to PR.
License
MIT, see LICENSE. Source: github.com/surajtripathy07/membral.
Available Tools
9 toolsget_code_sessionA
Retrieve a specific coding session by ID (a memory_search record's session_id, a list_recent_conversations code row's id): its user-spine turns (what the human asked/decided/corrected), files touched, and per-session summary. To read the turns around a record, pass its session_id as id and its turn_idx as turn: you get only turns turn-window..turn+window (window default 8, max 40; max_chars default 12000 here) with focus {turn, window, first_idx, last_idx, total_turns}; prev_start/next_start, passed as start (without turn), read the turns before/after; start reads forward from there with the default 60000 chars. Whole-session paging below is the fallback. Long sessions come in parts: each call returns the session metadata and summary plus whole turns from start up to about max_chars of turn text (default 60000), with total_turns, total_chars, returned {start, end (exclusive)} and next_start. files_touched is on the first part only (up to 200 paths; files_touched_total and files_touched_omitted give the rest's count). When next_start is not null, call get_code_session again with the same id and start=next_start until next_start is null to read every turn. The first part also lists sub_agents: the sub-agent sessions this session spawned (id, agent_type, description, started_at, ended_at, turn_count, brief = first 160 chars of the task it was given; at most 200, sub_agents_total gives the full count); open one with get_code_session id=. When this session is itself a sub-agent, parent_session_id is the id of the session that spawned it. Use it to read what was actually said; use session_summary for a short threaded overview of the same session. Results are dated records of what sessions did, not the current state of a PR or issue; check that live.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Code session ID; a unique prefix of ≥ 8 chars also works | |
| turn | No | Open the session at this turn (a memory_search record's turn_idx): only the turns within ±window of it are returned. Omit to page the whole session from start. | |
| start | No | Index of the first turn to return (default 0). Pass the previous call's next_start to continue. Ignored when turn is given (turn wins over start). | |
| window | No | With turn: how many turns either side to return (default 8, clamped to 1–40). | |
| max_chars | No | Approximate turn-text budget for this part, in characters (default 60000, or 12000 with turn; clamped to 5000–200000). A single turn larger than this is returned alone, cut, and marked truncated. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full load and does most of it: paging contract (start/end exclusive, next_start, max_chars budget, truncated oversized turns), caveats that files_touched appears only on the first part with a 200-path cap, sub-agent listing limits, parent_session_id, and the staleness warning that these are dated records rather than live PR/issue state. What it never says explicitly is the safety profile (that this is a non-mutating read with no auth/permission requirements), so a 4 rather than a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Information-dense but structurally heavy: one enormous run-on sentence packs the turn-window, paging, files_touched caps, sub_agents and parent_session_id together, and the aside "Whole-session paging below is the fallback" refers to text that arrives later. Nearly every clause is load-bearing, but sectioning or bullets would make the branching logic far easier to scan.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a five-parameter paginated reader with no output schema and no annotations, the description still tells the agent what comes back (session metadata, summary, turns, files_touched, sub_agents, returned/next_start), how to continue, and when the data is stale. There is no output schema to lean on, and the return shape is nonetheless fully described.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description earns extra credit by explaining interactions the schema only hints at, such as turn winning over start, the ±window focus object returned ({turn, window, first_idx, last_idx, total_turns}), and that max_chars defaults to 12000 in turn-mode versus 60000 otherwise. Much of the per-parameter default/clamp text duplicates the schema, which keeps it from a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb and resource ("Retrieve a specific coding session by ID") and immediately enumerates the payload: user-spine turns, files touched, per-session summary. It also explicitly contrasts itself with the sibling session_summary ("short threaded overview of the same session") and ties its ID to memory_search records and list_recent_conversations rows, so an agent can place it among siblings without reading any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete entry paths (a memory_search record's session_id + turn_idx, a list_recent_conversations code row's id) and states the selection rule against the alternative: "Use it to read what was actually said; use session_summary for a short threaded overview." It also documents the drill-down loop (repeat with start=next_start until next_start is null) and the sub-agent traversal, leaving little to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_conversationA
Retrieve a specific conversation by ID with its messages. Long conversations come in parts: each call returns whole messages from start up to about max_chars of content (default 60000), plus total_messages, total_chars, returned {start, end (exclusive)} and next_start. When next_start is not null, call get_conversation again with the same id and start=next_start until next_start is null to read the whole conversation. Tool calls/results are replaced by short stubs by default (see include_tool_io) so tool-heavy chats don't overflow the part budget.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Conversation ID | |
| start | No | Index of the first message to return (default 0). Pass the previous call's next_start to continue. | |
| max_chars | No | Approximate content budget for this part, in characters (default 60000, clamped to 5000–200000). A single message larger than this is returned alone, cut, and marked truncated. | |
| include_tool_io | No | Include full tool call inputs and tool result outputs (default false). By default, tool calls/results are replaced by short stubs (e.g. web-search results), since they can be tens of thousands of characters and push a conversation past the part budget; set true to see them in full. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations present, the description carries the full burden and does well: it discloses part-based pagination, the default budget (~60000 chars), the returned metadata fields, and that tool calls/results are stubbed by default to protect the budget. It does not cover error behavior for an invalid id or any access/permission constraints, which keeps it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core purpose, then the pagination contract, then the tool-IO caveat. Dense but every sentence conveys behavior an agent needs; the trailing tool-IO sentence partially duplicates the schema's include_tool_io description, costing a point.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must describe return shape — and it does, naming total_messages, total_chars, returned {start, end (exclusive)} and next_start, plus truncation of oversized single messages. An agent has everything needed to page through a conversation to completion.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3; the description earns above that by explaining the continuation protocol that binds `start` to `next_start` and by giving the rationale for `include_tool_io` (tool payloads are enormous and blow the part budget). It still defers the actual bounds and clamping to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Retrieve a specific conversation by ID with its messages'), which cleanly separates it from list_recent_conversations and search_conversations that operate without an ID. It does not explicitly name a sibling to contrast with, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit operational guidance for the common multi-call case: when next_start is not null, call again with the same id and start=next_start until null. That is clear context for correct invocation, though it offers no routing advice about using search_conversations or list_recent_conversations to discover an id first.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_code_projectsA
List the user's coding-agent projects (repos worked on via Claude Code etc.) with a rollup summary, session count, and last-active time
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries full behavioral burden. It does disclose the returned payload (rollup summary, session count, last-active time), which is valuable given there is no output schema, but it says nothing about scoping restrictions, ordering, or pagination for a tool that could return many projects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence that identifies the resource, its scope, and the payload in one pass. Every clause ('coding-agent projects', 'repos worked on via Claude Code') earns its place by disambiguating what a project is.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully enumerates what the results contain, which is the main thing an agent needs to decide to call it. Given zero parameters and a simple read listing, little else is required; only result ordering/volume behavior is left unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters and the schema is empty, so there is nothing to document; baseline 4 applies. The description correctly adds no spurious parameter guidance.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (List) and resource (the user's coding-agent projects), with a parenthetical scoping clarification ('repos worked on via Claude Code etc.'). This clearly separates it from get_code_session, which retrieves one session rather than a project rollup, though no sibling is named.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied — an agent can infer this is the entry point for project discovery versus get_code_session for drilling into a session. There is no explicit when-to-use / when-not-to-use statement or named alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_recent_conversationsA
List the user's recent sessions — chats AND coding sessions (Claude Code, opencode, Copilot CLI, Codex; main sessions, not sub-agents) — from the last few days by default, newest first, metadata only. Chat rows (type "chat"): id, title, source, created_at, updated_at, message_count. Code rows (type "code"): id, project_name, git_branch, source, started_at, ended_at, turn_count, summary (up to 200 chars). Defaults to the last 7 days and both kinds. Use it to find something by when it happened (e.g. yesterday's chat → since = yesterday's date, kind = chat), then open a chat with get_conversation id= or a coding session with get_code_session id=; both return long results in parts. Results are dated records of what sessions did, not the current state of a PR or issue; check that live.
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | Only results from the last N days, a whole number 1-365 (e.g. 1 = the last 24 hours). Ignored when since is given. Default 7. | |
| kind | No | Which rows to list: "chat", "code" (coding sessions) or "all" (default). E.g. "code" for yesterday's coding session. | |
| limit | No | Max rows to return across both kinds, a whole number 1-100 (default 30). E.g. 10. | |
| since | No | Only results from this time on. ISO date "2026-09-24" (read as 00:00 UTC that day) or ISO datetime "2026-09-24T09:30:00Z" (no offset = UTC). For "yesterday" pass yesterday's date. Wins over days. | |
| source | No | Only rows from this source: one of chatgpt, claude, claude-code, codex, copilot-cli, grok, opencode. Chat sources filter chats, code sources (claude-code, opencode, copilot-cli, codex) filter coding sessions. E.g. "chatgpt". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so: defaults (last 7 days, both kinds), metadata-only return, per-type field lists including the 200-char summary cap, and that downstream get_* tools return long results in parts. It also warns results are dated records rather than live PR/issue state, which is exactly the kind of caveat annotations would otherwise supply.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and scope, and essentially every clause carries information (row shapes, defaults, routing, caveat). It is a single dense paragraph with heavy parenthetical stacking, which costs a little readability but no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Five optional parameters, no annotations and no output schema — the description covers what is returned for both row types, the defaults, pagination-adjacent limit behavior implicitly, and the caveat about staleness. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description still adds value by restating the temporal defaults and by showing how natural-language intents map to parameter values (since for 'yesterday', kind for chat-vs-code). It doesn't add syntax beyond the schema's ISO examples.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (List) and resource (recent sessions) and immediately disambiguates scope: chats AND coding sessions, main sessions not sub-agents, newest first, metadata only. It even enumerates the row shapes per type, so an agent can distinguish it from search_conversations or session_summary without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use with a concrete worked example ('yesterday's chat → since = yesterday's date, kind = chat') and explicit follow-up routing to get_conversation / get_code_session. It does not name the alternative for content-based lookup (search_conversations), so the exclusion side is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_recallA
Recall memory records BY REPO OR PATH (not by topic -- use memory_search for that). 'outcome' alone answers 'what shipped here lately'. Ordered kind-priority then recency. Read the turns around a record with get_code_session id=<session_id> turn=<turn_idx>. Records carry links to their sources when known: sha (the commit the session was on), paths (files it names, up to 5), ref_url (the ref's forge page). Open them directly; they locate sources, they do not report current state. Replaced records are hidden and paraphrases of one fact are served once with seen_in; every record carries as_of.
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | One or more of: outcome, decision, learning, blocker, preference | |
| path | No | Only records whose paths[] includes this file | |
| repo | No | Repo remote URL, absolute path, or short repo name (e.g. "acme/payments" or "owner/repo") | |
| limit | No | Max records to return, a whole number 1-20 (default 10) | |
| scope | No | Only records of this scope: "project" (about one repo, the default a record gets) or "global" (a rule or fact bigger than one repo). Omit for both. | |
| durable_only | No | Default true -- session-scoped records never push, but can still be recalled with this off | |
| recall_token | No | The recall_token line from this session's Membral preamble, if you have one. Only logged to link this call to that preamble; it never changes the results. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does: it discloses result ordering (kind-priority then recency), dedup semantics (replaced records hidden, paraphrases served once with seen_in), the as_of timestamp on every record, and an explicit caveat that links locate sources rather than report current state. That is unusually rich behavioral context for a read tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and the memory_search exclusion are front-loaded in the first clause, and every subsequent sentence carries new information. The style is telegraphic (fragments like 'Ordered kind-priority then recency', em-dash asides), which is efficient but slightly dense to parse on first read.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers return shape (links, seen_in, as_of, hidden replaced records), result ordering, and follow-up navigation, which is a lot for a tool with no output schema and no annotations. It does not mention pagination or whether truncated result sets are signaled, a minor gap for a 7-parameter read tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3; the description still adds meaning by showing that kind='outcome' alone is a valid, useful call shape and by framing path/repo as the primary selectors. It does not add anything for scope, durable_only, or recall_token beyond the schema, so it is an incremental gain rather than full compensation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (recall) and resource (memory records) and immediately bounds the scope: by repo or path, not by topic. It names the sibling memory_search as the tool for the excluded case, so an agent can pick between them without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit routing to memory_search for topic lookups and to get_code_session for surrounding turns, plus a concrete usage hint ('outcome' alone answers 'what shipped here lately'). It does not address when to prefer memory_resolve or the list_* siblings, so the alternative coverage is partial rather than complete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_resolveA
Mark a blocker as fixed. Call this right after you fix a blocker that Membral showed you (in the preamble, memory_search or memory_recall); quote your own or the user's message text that states the fix (not tool output, which is not stored). The blocker and its repeats are closed for every later session; the owner can restore it. The quote is checked against this session's transcript when it uploads and kept as the receipt. Only your own open blockers can be resolved.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The blocker record's id (the id field of a memory_search/memory_recall record) | |
| quote | Yes | Verbatim text from your own or the user's message in this session that states the fix, not tool output (12-500 characters) | |
| recall_token | No | The recall_token line from this session's Membral preamble, if you have one. It links the resolution to this session so the quote can be checked. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so: it discloses the blast radius ('the blocker and its repeats are closed for every later session'), reversibility ('the owner can restore it'), and a validation mechanism ('the quote is checked against this session's transcript when it uploads'). It also pre-empts a likely failure mode by forbidding tool output as the quote source.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action, then timing, then consequences, then the permission constraint — a sensible order with no filler sentences. Slightly dense with nested parentheticals ('in the preamble, memory_search or memory_recall', 'not tool output, which is not stored'), which marginally slows scanning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no annotations and no output schema, the definition covers when to call, what it affects, how the quote is validated, and who may call it. The remaining gap is what happens on rejection (e.g. a quote that fails transcript validation) and what the call returns, though the latter is a minor omission for a simple state-change.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so parameter definitions alone would justify a 3. The description adds meaning beyond the schema by explaining why the quote must be verbatim message text — it is re-validated against the uploaded transcript and stored as the receipt — which gives the agent a reason to comply rather than just a rule.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Mark a blocker as fixed') and immediately anchors it to the blocker objects surfaced by the sibling tools memory_search and memory_recall. An agent can tell this apart from the read-only search/recall siblings without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit timing ('Call this right after you fix a blocker') and names the upstream sources that produce the blocker (preamble, memory_search, memory_recall). It also states an exclusion — 'Only your own open blockers can be resolved' — which prevents misuse on other users' or already-closed records.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_searchA
Search past sessions' learnings, decisions, blockers and other memory records by TOPIC (Postgres full-text search fused with semantic similarity) -- the tool for 'what did we decide/learn about X'. Filter by kind, scope, project, path, or since/days. A date phrase in the query ("last week", "yesterday", "Sept 20") is read as a time hint: it is taken out of the search text and records from that window rank higher, but older matches still come back (date_hint shows the reading); since/days are hard filters. Newer records win near-ties. since/days filter on the session's start time; each record's when is its session's end time (else start). Covers extracted, quote-verified records (extraction runs on sessions within about 30 days of upload; older extracted records stay searchable); a fact that was said but never extracted is only in the raw turns (search_conversations). When nothing is relevant enough, reason says why -- that is the answer, not an error. Records a newer record replaced are hidden unless include_superseded is true or the query names a past date; paraphrases of one fact are served as one record with seen_in (the number of sessions that said it); every record carries as_of, the day its session recorded it (true when recorded, not current state). Local installs return served: lines (records as JSON, raw session excerpts marked "raw excerpt") packed whole to max_tokens (default 3000). Else (hosted; raw_reason says why) ranked records cut at max_tokens (dropped_for_budget). A record's session_id is a code session: read the turns around it with get_code_session id=<session_id> turn=<turn_idx>, or session_summary session_id=<session_id>. Records carry links to their sources when known: sha (the commit the session was on), paths (files it names, up to 5), ref_url (the ref's forge page). Open them directly; they locate sources, they do not report current state. Results are dated records of what sessions did, not the current state of a PR or issue; check that live.
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | Only records from sessions in the last N days, a whole number 1-365 (a hard filter). Ignored when since is given. | |
| kind | No | One or more of: outcome, decision, learning, blocker, preference | |
| path | No | Only records whose paths[] includes this file | |
| limit | No | Max records to return, a whole number 1-20 (default 10) | |
| query | Yes | What to search for | |
| scope | No | Only records of this scope: "project" (about one repo, the default a record gets) or "global" (a rule or fact bigger than one repo). Omit for both. | |
| since | No | Only records from sessions on or after this time (a hard filter). ISO date "2026-09-24" (00:00 UTC) or ISO datetime "2026-09-24T09:30:00Z". Wins over days. | |
| project | No | Repo remote URL, absolute path, or short repo name (e.g. "acme/payments" or "owner/repo", as the preamble names the current repo) to scope the search to one project | |
| max_tokens | No | Token budget for the result, 200-20000 (default 3000). Served lines (records and raw excerpts) are packed whole, in order, estimated as characters / 4, and stop at the first line that does not fit. Without raw excerpts the ranked records fill it instead, and at least one is returned. | |
| recall_token | No | The recall_token line from this session's Membral preamble, if you have one. Only logged to link this call to that preamble; it never changes the results. | |
| include_superseded | No | Also return records a newer record replaced, each marked superseded_by {id, on}. Default false: replaced records are hidden. A past date phrase in the query ("as of Sept 20") also serves what was current then. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full burden, and it delivers: ranking rules (newer wins ties), date-hint soft ranking vs since/days hard filtering, superseded-record hiding and how to unhide, paraphrase merging with seen_in, as_of staleness, extraction coverage window (~30 days of upload), and two different result-shaping modes (served vs records with raw_reason/dropped_for_budget). It also states that an empty result with a 'reason' is a valid answer, not an error.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in sentence one, but the body is a dense run-on with repeated content: since/days filtering is explained twice and the 'records are not current state' caveat is stated twice ('they do not report current state' and 'not the current state of a PR or issue'). The information is valuable but could be tightened without loss.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 11-parameter tool with no output schema and no annotations, the description covers return shapes, key fields (date_hint, seen_in, as_of, dropped_for_budget, served), failure semantics, and source-link fields (sha, paths, ref_url). An agent has what it needs to call and interpret results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3; the description goes beyond it by clarifying that since/days filter on session start time while each record's `when` is session end time, and by explaining that include_superseded is implicitly true when the query names a past date. Remaining params (kind values, limit, project, recall_token) are left to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
First sentence states a specific verb and resource ('Search past sessions' learnings, decisions, blockers...') plus the search mode (full-text fused with semantic) and the agent-facing intent ('what did we decide/learn about X'). It explicitly marks its boundary against search_conversations for unextracted facts, so an agent can choose without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear conditions: use this for topics, use search_conversations for raw turns, and follow up with get_code_session/session_summary when you need surrounding context. It does not differentiate itself from memory_recall or memory_resolve, so the sibling routing is incomplete, but the affirmative usage context is strong.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_conversationsA
Search the user's synced conversations AND coding-agent sessions by keyword and semantic similarity — results are tagged source_type (chat/code) and, when a matching chunk exists, resolve to the specific message span inside the conversation rather than just its title. To find a chat or session from a specific time, pass since (or days): e.g. yesterday's chat about X → query = X, since = yesterday's date. To browse recent activity with no query, use list_recent_conversations. Hits are raw text as said, not extracted, checked or versioned: true when said, not current truth; for decisions, learnings and outcomes use memory_search. Results are dated records of what sessions did, not the current state of a PR or issue; check that live.
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | Only results from the last N days, a whole number 1-365 (e.g. 1 = the last 24 hours). Ignored when since is given. Omit (and omit since) for no time bound. | |
| limit | No | Max results to return (default 10) | |
| query | Yes | Search query | |
| scope | No | A LifeArea id or label to narrow the result to | |
| since | No | Only results from this time on. ISO date "2026-09-24" (read as 00:00 UTC that day) or ISO datetime "2026-09-24T09:30:00Z" (no offset = UTC). For "yesterday" pass yesterday's date. Wins over days. Chats count by last update, coding sessions by end time. Omit for no time bound. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so: it discloses that hits are raw text 'as said, not extracted, checked or versioned', that they are dated records rather than current state ('check that live'), and that chunks resolve to message spans. These are non-obvious semantic traits an agent could not infer from the schema alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded: purpose first, then time-filter usage, then the sibling routing, then the truth-vs-record caveats. Each sentence addresses a distinct concern, though the closing three caveat clauses stack up and could be tightened.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 5-parameter search tool with no annotations and no output schema, the description covers invocation, alternatives, time filtering, and return-value semantics. An agent has everything needed to call it correctly and interpret hits.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so a baseline of 3 applies, but the description adds real value by explaining when to prefer since over days and giving a natural-language example of mapping a relative date to since. The scope parameter is not addressed in the description, keeping it below a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and dual resource ('Search the user's synced conversations AND coding-agent sessions') plus the retrieval modes (keyword and semantic similarity). It also pins down result shape (source_type tagging, resolution to message span rather than title), which lets an agent distinguish it from get_conversation and list_recent_conversations without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit routing to alternatives: browsing with no query goes to list_recent_conversations, and decisions/learnings/outcomes go to memory_search. It also gives a concrete time-filter recipe ('yesterday's chat about X → query = X, since = yesterday's date'), leaving little to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
session_summaryA
Get one coding session's header (repo, branch, turns, models, files touched) and its JOURNEY: threads in order from the first prompt, each with its records (outcomes first) and files touched in that range. Use it for the short story of a session (what it set out to do and what it found); use get_code_session when you need the actual turns, e.g. the exact words around a memory_search record. Results are dated records of what sessions did, not the current state of a PR or issue; check that live.
| Name | Required | Description | Default |
|---|---|---|---|
| last | No | The most recent session (optionally narrowed by repo) | |
| repo | No | Repo remote URL, absolute path, or short repo name (e.g. "acme/payments" or "owner/repo"), narrows `last` | |
| session_id | No | A specific code_sessions id; a unique prefix of ≥ 8 chars also works | |
| recall_token | No | The recall_token line from this session's Membral preamble, if you have one. Only logged to link this call to that preamble; it never changes the results. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses ordering semantics (threads in order from the first prompt, records with outcomes first), scoping (files touched in that range), and the crucial data-freshness trait that results are historical records rather than live state. It stops short of covering result size, truncation, or cost of a call, so not a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with purpose, then routing, then the freshness caveat; the parentheticals all carry information rather than filler. Nothing could be removed without losing selection-critical detail.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 4-param read tool with no output schema, the description conveys the return shape well enough (header fields plus an ordered journey of threads and records) and flags the historical nature of the data. It leaves open the default selection behavior when no identifying parameter is given, and jargon like 'records'/'threads' is not defined, which is a modest remaining gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so `last`, `repo`, `session_id` (including the ≥8-char prefix rule) and `recall_token` are already fully documented in structured fields. The description adds nothing about parameters — notably it never explains selection precedence when neither `last` nor `session_id` is supplied — so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get one coding session's header ... and its JOURNEY') and enumerates the returned fields (repo, branch, turns, models, files touched, threads, records). It explicitly names the sibling get_code_session and the condition that selects it, so an agent can route without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a positive selection rule ('short story of a session — what it set out to do and what it found'), names the alternative for a different need ('use get_code_session when you need the actual turns, e.g. the exact words around a memory_search record'), and warns when not to rely on it ('dated records ... not the current state of a PR or issue; check that live').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
9 tool updates
v0.1.0- First observed
get_code_session - First observed
get_conversation - First observed
list_code_projects - First observed
list_recent_conversations - First observed
memory_recall - First observed
memory_resolve - First observed
memory_search - First observed
search_conversations - First observed
session_summary
TDQS
Scored across 9 tools
The retrieval tools are mostly distinct: memory_search targets extracted topic memory, memory_recall targets repo/path memory, search_conversations targets raw keyword/semantic text, and list_recent_conversations is for browsing recent sessions. Some overlap remains among the three search/recall tools, but the descriptions provide clear selection guidance.
All names use snake_case and are generally readable, with mostly verb_noun patterns like get_code_session, list_code_projects, and search_conversations. Minor deviations exist, such as memory_search/recall/resolve using an object-first grouping and session_summary being noun-only, but the conventions are still predictable.
Nine tools is well-scoped for a memory and conversation retrieval server. Each tool maps to a meaningful operation: listing, searching, recalling, resolving, and retrieving sessions or conversations.
The surface covers the core lifecycle of browsing conversations and coding sessions, searching raw text, finding extracted memories, and resolving blockers. Minor gaps exist, such as no explicit browse/list operation for memory records or dedicated project-scoped session listing, but agents can work around these with existing filters.
Maintenance
Related MCP Connectors
Shared memory for coding agents. Stop re-explaining your codebase every session.
Persistent AI memory shared across Claude, ChatGPT, coding agents, and compatible MCP clients.
Persistent cross-session memory shared by Codex, Claude Code, ChatGPT, and other AI agents.
Persistent memory for AI agents across Claude, ChatGPT and any MCP client.
Related MCP Servers
- AlicenseAqualityAmaintenanceMCP-native, local-first memory for coding agents that turns real sessions into reusable decisions, gotchas, and domain knowledge.1757 PyPI7MIT
- AlicenseAqualityAmaintenanceLocal-first AI PKM memory server for coding conversations. Imports Claude Code, Cursor, Codex CLI, Trae, and GitHub Copilot chats into notes, semantic search, tag graphs, Markdown exports, and MCP memory tools.7121 npm61Apache 2.0
- AlicenseNot gradedqualityCmaintenanceLocal-first memory daemon for AI coding agents that captures session transcripts, distills typed memories (decisions, facts, lessons, commands, todos), and serves them via hybrid search through MCP tools.10 npmMIT
- AlicenseAqualityAmaintenancePersistent memory for AI coding agents, storing decisions, bug fixes, conventions, and discoveries in a local SQLite database and automatically recalling them when relevant. Works with Claude Code, Codex, Cursor, Gemini CLI, and other MCP-compatible agents.224MIT