# Exomem assistant guide This guide is for agents using Exomem after the MCP server or connector is available. It keeps the contract simple: - Keep temporary working context in the current conversation. Custom instructions can guide one client; native memory is an explicit fallback when Exomem cannot capture. - Use Exomem as long-term governed memory: eligible durable preferences, personal baselines, project context, decisions, sourced conclusions, failures, experiments, proof-bearing records, and anything that should be searchable, citeable, reviewable, or supersedable across clients. - Do not make the user choose internal folders or page types unless the choice changes the outcome. ## Start here If the Exomem skill has already been loaded, follow it. Otherwise call: ```text read_instructions(profile="compact") ``` Do this once at the start of a session for generic MCP clients, hosted chat clients, Cursor, Codex, ChatGPT, scripts, and future clients that only see tool schemas. Use `read_instructions(profile="full")` when the client needs examples. Use `read_instructions(profile="diagnostics")` only for speed, ranking, cache, CPU/GPU, rerank, or packed-context questions. ## The rule Search Exomem before answering when the turn touches the user's prior projects, notes, decisions, sources, failures, experiments, entities, or domains. Stay quiet for unrelated chat, short control prompts, and follow-ups where the current conversation already contains fresh KB evidence. An empty search means "not found with that query and scope." It is not proof that the knowledge does not exist. Try synonyms, adjacent terms, singular/plural forms, `widen_outside_kb=true`, or `scope="vault"` before saying there is no relevant material. `scope="kb"` (the default) searches the knowledge base and nothing else. `widen_outside_kb` is off by default: set it to true to also reserve up to `limit - 1` slots for curated vault pages outside the knowledge base, which is what surfaces a terse tracker or handbook whose title is the query. Reserved hits carry `outside_kb: true`. Earlier releases widened on every `scope="kb"` recall; the reserve is now something the caller asks for, so the default costs nothing for the callers that never read it. Use page recall for conclusions, unit recall for exact observations, and mixed recall when both are useful. An empty query with structured filters is a filter-only lookup. Set `explain=true` only to inspect ranking: BM25, cosine, RRF contributions, reranker values, and final rank are different labelled metrics, never confidence. See [first-class semantic language](semantic-language.md). Save durable conclusions when the conversation lands on one: a decision, solved problem, diagnosed failure, reusable pattern, stable project fact, or conclusion that future agents should find. Save a concise compiled note, not a transcript. Capture raw material separately when provenance matters. Capture a stable preference, recurring routine, historical baseline, or durable affiliation only when both stability or recurrence and reusable comparison, interpretation, or decision value are clear. Put a facet or affiliation on a uniquely resolved Entity; otherwise write one concise compiled observation. Use Records only for an observed measurement accepted by a compatible existing collection. Fleeting preferences, one-off activity, incidental associations, trivial metrics, and tentative claims stay quiet; this never authorizes creating an Entity, collection, or schema. A concise observation or narrow Entity facet follows `proactive_capture`; a new Entity or your own affiliation edge follows `proactive_capture`; accepting a queued relation requires `link_acceptance`; merge or substantial curation requires confirmed `restructure_execution`. ## Simple actions for agents Use the simple product actions as the first mental model. Product commands are what agents should call; canonical leaves stay underneath as implementation routes. | Simple action | User intent | Product command | | --- | --- | --- | | `ask` | "What do I know?", "find what I concluded", "show the context" | `search_memory(detail="compact", rerank=false)`, then `read_page`; use `search_memory(deep=true)` for synthesis | | `create_note` | "remember this conclusion", "save this decision", "write this up" | `create_note`; use `supersede_note` when it supersedes an old conclusion | | `capture` | "save this source", "preserve this receipt", "keep this proof" | `save_source` for raw sources; `save_evidence` or `upload_files` for Evidence | | `review` | "what needs review?", "show stale/disconnected knowledge", "what is unprocessed?" | `list_review_items`; `decide_review_item` for explicit dismiss/snooze/reopen | | `connect` | "what should this link to?", "suggest relations", "show related ideas" | `inspect_memory` with the `connections` operations; entity writes stay explicit through `manage_memory` | | `adopt` | "import/adopt this existing vault safely" | `adopt_vault(mode="scan-only")`; explicit modes for manifest/copy/compile planning | | `maintain` | "check/fix vault health" | Remote tools may audit or dry-run; actual `fix`/`reconcile` writes require the host operator CLI | Do not make the user choose `Sources`, `Evidence`, `Notes`, `Entities`, pack metadata, graph sidecars, or schema terms unless the distinction changes the outcome. With the user, say "ask", "remember", "capture", "review", "connect", "adopt", or "maintain"; use canonical leaf names only when debugging internals. ## Typed relation loop For a request to connect two memories, first call `connect_memory(operation="resolve-relation")`. Reuse a specific truthful registered relation when one fits. `relates_to` and no edge remain valid outcomes; candidate ordering is not a semantic decision. When a reviewed distinction is missing, call `schema_memory(subject="relations", operation="propose-relation")`. Only a separate `save-relations` call with `expected_hash` and `why` changes the registry; never treat a proposal, recurrence count, or queue item as approval. `schema_memory(subject="relations", operation="infer")` is read-only. Its aggregate `census` is privacy-safe evidence: `relation_counts`, `page_counts`, and `denominators` contain counts only. Optional `project`, `page_type`, `date_from`, and `date_to` scope it. Origin dates use `created`, then `captured`; undated pages remain explicit and `updated` is not used as a cohort date. For CLI use, these actions are also available as friendly aliases: ```bash exomem ask "what did I conclude about onboarding?" --json exomem ask "warranty dispute context" --deep --graph-enrich --json exomem ask "battery policy" --category config --result-level mixed --explain --json exomem create_note "# Decision\n\n## Claim\n\nUse simple actions first." --title "Use simple actions first" --json exomem capture "raw article excerpt" --title "Article title" --source-type article --url "https://example.com" --json exomem capture "receipt text" --as evidence --scope warranty --category receipts --filename receipt.txt --json exomem review --json exomem review --category relation_debt exomem review snooze exomem://review/0123456789abcdef01234567 --until 2026-08-01 exomem connect --path "Notes/Insights/example" --json exomem maintain --json ``` ## Examples ### Remember this User: ```text Remember this: for the onboarding docs, lead with simple actions, not schema folders. ``` Agent behavior: 1. Recognize a durable project conclusion. 2. Save a concise compiled note. 3. Report the path. ```text Saved -> Knowledge Base/Notes/Research/Exomem/.md ``` ### Find what I concluded User: ```text What did I conclude about Exomem vs built-in memory? ``` Agent behavior: 1. Run `search_memory(query="Exomem built-in memory boundary", detail="compact")`. 2. Cite relevant hits. 3. If results are thin, retry with adjacent terms such as `native memory`, `assistant memory`, `custom instructions`, or `durable governed knowledge`. ### Preserve source User: ```text Save this article as a source and keep the URL. ``` Agent behavior: 1. Use `save_source` for the raw article or excerpt. 2. Keep the URL and capture rationale. 3. Classify on two independent open axes: `source_kind` is what the artifact **is** (`research-report`, `invoice-receipt`, `field-notebook`), `domain` is what it is **about** (`travel`, `marine-biology`). Neither is a closed list — an unfamiliar but meaningful label is accepted and registers itself, so name the label you actually mean instead of falling back. Add `projects` for the work it serves; a source can serve several, and projects never affect where it is stored. 4. Always name a kind. If no known kind fits, name a new one; there is no catch-all, and `other` is retired. 5. Offer to compile a note only if there is a durable conclusion to extract. For one observation or rich unit, use `edit_note` rather than page-wide string editing. For reviewed creation, validate first and commit the unchanged `draft_id`, `draft_hash`, and `draft_token`. When required, echo the returned `relation_review_hash` with `relation_disposition="reviewed_none"` and an explicit `relation_review_reason`; never infer reviewed-none from a missing relation. ### Preserve proof User: ```text Keep this receipt for the warranty case. ``` Agent behavior: 1. Treat it as a proof-bearing record, not a research source. 2. Preserve the original file or text with `save_evidence` or `upload_files`. 3. Report the stored path and any metadata the server returns. ### Adopt a generated artifact Keep every generated file you hand the user. At hand-over, preserve that file's exact bytes once. Under balanced or maximal prominence this uses `proactive_capture`; do not wait for the user to say they chose it. Drafts, previews and variants you never hand over stay ephemeral. The rule covers files you generate and give the user: downloads, attachments and sandbox outputs. It does not cover files you write or edit in the user's own workspace or repository, which already persist there. An explicit save request remains an ordinary requested action. Choose Source or Evidence from purpose before transport: reasoning material is a Source, while a deliverable or proof-bearing final is Evidence. MIME never chooses. Pass the closed `adoption` envelope to `save_source` or `save_evidence`. Use one `key` per hand-over, such as the file name plus a version, and name the handed-over handle in `selected_file_id`. A revision you hand over later is kept beside the first, and identical bytes return `already_stored`. When no usable handle exists, report a non-committing `handoff_required` or `handoff_prepared` state. Do not substitute base64, a textual reconstruction, or a claim that the bytes were saved. A later send or publication is a separate delivery fact. Append it through `record_memory(..., delivery={...})` only after a committed local Evidence receipt and only into one existing compatible Records collection. The delivery envelope maps the caller-authored link, reported-reference, and verification fields; it creates no schema and sets no item values. Reported remote identity is unverified unless matching platform proof establishes remote byte equality. Missing schema may yield a `structural_suggestions` proposal, but creation or change remains confirmed `restructure_execution`; an independently authored edge follows the served promotion class; a queued acceptance remains `link_acceptance`. ### Compile evidence User: ```text Compile the notes from these two sources into what we learned. ``` Agent behavior: 1. Search or read the named sources. 2. Draft a compiled conclusion that links back to the sources. 3. Use `create_note(suggestions=true, response_detail="full")` so the new note connects to prior work. Link suggestions are off by default — they cost a whole retrieval pass on the write path — so the call has to ask for them, and the default compact response would not carry them even once computed. ### Review stale knowledge User: ```text Show me conclusions that may be stale. ``` Agent behavior: 1. Run `list_review_items` with the appropriate review mode. 2. Present candidates as review items only. 3. Ask whether to keep, connect, edit, supersede, archive, dismiss, or snooze. Use `decide_review_item` only for an explicit review decision. Do not auto-decay old knowledge or auto-accept suggested relations. ### Supersede old conclusion User: ```text The old setup recommendation is wrong now; this new one replaces it. ``` Agent behavior: 1. Find and confirm the old compiled page. 2. Use `supersede_note` to write the new conclusion and mark the old page superseded. 3. Surface downstream pages that may need review; do not silently rewrite them. ## Mutation responses and compatibility Successful product mutations now return a compact decisive terminal by default: `ok`, `status="committed"`, `mutated`, `path` or `paths`, `request_id`, `receipt_id`, and `warnings_count`. When the write actually warned, the texts come back as `warnings` — at most 8 entries of at most 300 characters each. `warnings_count` stays authoritative, so fewer entries than the count means the rest were trimmed. Two cases return a count with no `warnings`: an upload receipt, whose warnings are already per-file rows under `files`, and a mutation recovered from a portable receipt, which deliberately retains no leaf content. A compiled-note write may also return `structure_suggestion` of kind `note_cohesion` while the written page has reached a size step that nobody has answered. It carries `units`, `step_units`, `next_step_units`, the review item's `ref` and `fingerprint`, and one `question`: does this page answer more than one independent question? Every value comes from the page named in the same response, so it discloses nothing about any other page. It never changes `status`, `mutated`, `warnings_count`, mutation identity, or replay, and a failure to compute it omits the field rather than affecting the write. The runtime counts size and asks; it never judges the page or reorganises the vault. To keep the page whole, dismiss the item through `decide_review_item` with a reason that starts `intentional:`; it stays quiet until the next size step. To split it, propose a plan through the curation lane and ask the user to confirm the exact plan. A hub by design carries a breadth tag. The same items sit in due-state as a backlog. Use `response_detail="full"` when an agent needs the previous leaf diagnostics nested under `diagnostics`. `response_detail="legacy"` returns the old raw result for temporary compatibility. Detail is presentation-only and does not change replay identity. Busy, acknowledgement-pending, and committed-acknowledgement-uncertain results remain errors. Follow their remediation with the same mutation identity and unchanged payload; never turn an uncertain acknowledgement into a new write. `edit_note` remains one tool. New clients must send `path`, `why`, and a nested `operation` whose `kind` is one of `replace_body`, `replace_tags`, `replace_string`, `batch_replace`, `edit_section`, `patch_frontmatter`, or `fill_row`. The old flat arguments remain runtime-only for at least one release, are deprecated, and must not be generated by new clients. Bootstrap guidance is filtered to the active adapter. Use `active_capabilities.available_product_tools` and its active capability digest for what that MCP/REST/CLI surface can actually call. The canonical MCP tool- surface digest identifies packaged full MCP discovery instead; it is a separate identity. Audit defaults to the read-only `detail="actionable"` view: current blockers, malformed or unregistered relation work, ordinary findings, then a grouped grandfathered backlog with exact counts and bounded samples. Request `detail="full"` for raw enumeration. `legacy_sample_limit` accepts 0 through 50 and changes presentation only. Budgeted audits return findings only from completed categories. Check `metadata.coverage` (also `meta.coverage`) for `corpus_complete`, `completed_categories`, `requested_categories`, and `complete`. For example, `complete=false` with an empty summary means unknown coverage; it does not prove that the vault has no findings. The `budget` block names checks that stopped or did not start. Full detail keeps the same deadline. Every audit report passes fresh authorization before release. If that pass cannot finish, `AUDIT_BUDGET_EXHAUSTED` replaces the entire report. Retry with fewer categories, such as `categories=["broken_wikilink"]`. The error contains no findings, paths, or counts. Unbudgeted local audits keep their existing scope. Compatibility window: compact success is the default; `response_detail="legacy"` and the legacy flat edit shim remain for at least one release. Because these changes alter MCP discovery schemas, deployed connectors must be refreshed and content-read smoke-tested before their new digest is marked verified. ## Client setup | Client | Connection | Behavioral layer | | --- | --- | --- | | Claude Code | Local MCP via setup or manual config | Exomem skill, optional hooks | | Codex CLI | `codex mcp add ...` | `AGENTS.md`, optional hooks, `read_instructions()` fallback | | ChatGPT or hosted chat clients | Remote MCP/connector when supported | Custom instructions plus `read_instructions()` | | claude.ai web/mobile | Remote connector | Custom instructions plus `read_instructions()` | | Cursor, Windsurf, Gemini, generic MCP clients | Stdio or remote MCP config | `read_instructions()` at session start | | Scripts and custom chatbots | MCP, REST, or CLI | Cache `read_instructions()` (REST and CLI: `bootstrap`) per process/session | ## Copyable instruction block Use this block when a client has no loaded Exomem skill. Claude Chat and ChatGPT can load the skills from a plugin. Claude Code and Codex load them through `exomem setup`. Trim the tone line to your preference. ```text Use Exomem for eligible durable preferences, personal baselines, governed knowledge, sources, evidence, decisions, and reusable conclusions. Keep temporary working context in the current conversation. Without a loaded skill, call read_instructions(profile="compact") once per session and follow it. Search for prior projects, decisions, sources, failures, experiments, or domains; skip unrelated chit-chat/control and answered follow-ups. Cite hits. Empty is a scoped miss; retry terms or scope="vault" when absence matters. Save durable conclusions on your own: decisions, solved problems, diagnosed failures, reusable patterns/context, or a method actually carried out with a reported reusable result. A stable preference, recurring routine, historical baseline, or durable affiliation qualifies only with stability or recurrence plus reusable comparison, interpretation, or decision value. Use a uniquely resolved Entity's narrow facet; else one concise compiled observation; Records only for a compatible existing measurement. Fleeting preferences, one-off activity, incidental associations, trivial metrics, and tentative claims stay quiet. Concise observation, narrow Entity facet, new Entity or own edge: `proactive_capture`; accepting a queued relation: `link_acceptance`; merge or structural change: confirmed `restructure_execution`. Save compiled notes, not transcripts; keep raw sources/evidence separate. Use `edit_note` for small corrections, `supersede_note` for supersession. ``` ## Codex CLI `exomem setup` now wires Codex the same way it wires Claude Code — MCP registration, all ten skills, and hooks — so the usual answer is simply: ```bash exomem setup ``` It detects Codex from `codex` on PATH or a `~/.codex` directory, registers the server via `codex mcp add` (falling back to a backed-up, diffed merge into `~/.codex/config.toml`), and installs the skills into `~/.codex/skills/`. Codex **does** load Agent Skills from disk, so the instruction block above is no longer required there — it remains the fallback for clients that have neither skills nor hooks. To do the steps individually: ```bash exomem install-skill --client codex exomem install-hook --client codex codex mcp add exomem --env EXOMEM_VAULT_PATH="/path/to/vault" -- exomem --transport stdio ``` `--transport stdio` is not optional: the server defaults to HTTP, so a config that omits it starts a web server on port 8765 instead of speaking MCP. Check deployed Claude Code and Codex hooks: ```bash exomem install-hook --check ``` The continuation portion uses one client-neutral, stdlib-only core with thin Claude/Codex envelope and output adapters: | Lifecycle event | Claude Code | Codex CLI 0.144.3 | | --- | --- | --- | | `PreCompact(manual|auto)` | structural checkpoint | structural checkpoint | | `SessionEnd` | structural checkpoint | unsupported; no Exomem registration | | `SessionStart(compact|resume)` | validated reinjection | validated reinjection | It runs locally without MCP, REST, a model, Exomem CLI, a vault path, or an MCP credential. A checkpoint contains only bounded structural recovery evidence: repository/worktree state, bounded paths, content-free artifact hashes and checkbox profiles, and path-bound transcript byte-slice hashes. It never parses or stores transcript records, conversation/tool/system output, compaction summaries, secrets, or artifact/task text. Reinjection is advisory and never turns checkpoint data into an automatic Exomem write. State is per client and collision-resistant under `~/.claude/.cache/exomem-continuation/` or `~/.codex/.cache/exomem-continuation/`. `CLAUDE_CONFIG_DIR` and `CODEX_HOME` relocate the respective client roots; `EXOMEM_HOOK_HOME` overrides either root for isolated installs. Current state is accepted only for the exact client/session/root and transcript provenance, and only for 30 days. A validated previous generation may be reinjected as an explicit `rollback`; corrupt, foreign, stale, truncated, or oversized state stays silent. Metadata-only logs contain no environment values or absolute paths. Set `EXOMEM_CONTINUATION_DISABLE=1` in the environment that launches the client to bypass checkpoint writes and reinjection without deleting state. Reload or restart the target client after installation and accept any local-hook trust prompt. `install-hook --check` validates exact supported registrations and matchers, deployed hashes, legacy entries, runtime permissions/age/status, and logs; before the first write event, absent runtime state is a warning, not a failure. Re-running installation performs a narrow migration: only exact legacy `kb_continuation_checkpoint.py` and `kb-continuation-checkpoint.sh` basenames are retired, unrelated hook order is preserved, user-owned Codex `SessionEnd` handlers stay untouched, and changed valid config is backed up and replaced atomically. Malformed config fails closed. `install-hook --uninstall` rolls the whole thing back: it removes only the entries this installed and then the scripts it deployed, `--keep-scripts` unwires the config alone, and where the config is deployed by yadm alternates it prunes the `##os.*` sources as well — without that, the next alternate selection regenerates the deployed file and the hooks return. The local state is inert afterward and can be deleted independently. Codex reads repository instructions from `AGENTS.md`. Put the instruction block there, or keep an equivalent policy. Restart Codex sessions after changing MCP or hook config. ## Generic stdio MCP clients Use the standard stdio config shape: ```json { "mcpServers": { "exomem": { "command": "exomem", "args": ["--transport", "stdio"], "env": { "EXOMEM_VAULT_PATH": "/path/to/vault" } } } } ``` After connecting, ask the agent to call: ```text read_instructions(profile="compact") ``` ## Hosted chat clients Hosted clients usually cannot use local filesystem hooks or load the repo's Claude Code skill. To set one up: 1. Connect Exomem through the remote MCP or connector support the client offers. 2. Paste the learning instruction below into the account-level or project-level custom instructions. 3. If the client has no loaded Exomem skill, add the instruction block above after it. ```text Use Exomem as the memory for my work. Before you start a task, recall what Exomem holds about the systems, projects or topics it touches. As you work, save each reusable fact you establish (how something is structured, a pitfall, a method that worked) as one concise observation, and update an existing note when one covers it, so a later session does not have to find it again. ``` The agent then recalls what Exomem holds before a task and saves what it learns. The learning instruction is your own request, so it goes where the client reads your instructions. With the instruction block it is longer than a 1,500-character field, so where the client caps a field, give each text its own field. `exomem setup` offers the same text for Claude Code (`CLAUDE.md`) and Codex (`AGENTS.md`). Leave it out at the `light` and `off` prominence levels: they save only when you ask. For ChatGPT Personal Plugins, follow the exact OAuth-only settings and tool-surface refresh gate in [remote-quickstart.md](remote-quickstart.md#chatgpt-personal-plugin-oauth-only). If the hosted client cannot reliably call `read_instructions()` on its own, start a new chat with: ```text Call Exomem read_instructions(profile="compact") once, then use that contract for this chat. Do not search the KB unless this turn touches my prior projects, notes, decisions, sources, failures, experiments, or domains. ``` ## Performance guidance | Use case | Tool shape | Meaning | | --- | --- | --- | | Normal lookup | `search_memory(detail="compact", rerank=false)` | Cheap routing recall | | Reasoning | `search_memory(deep=true)` | Bounded context assembly for synthesis | | Diagnostics | `search_memory(detail="compact", include_timings=true, rerank=true)` | Explain latency and ranking behavior | When reranking is active, optional `rerank_max_candidates` bounds the fused prefix sent to the scorer. It must be between the effective normalized result limit and 300. The retrieval profile reports `candidate_limit_requested`, `candidate_limit_effective`, `scorer_input_count`, and `unscored_tail_count`; the tail keeps fused order. This is a work bound, not a hard latency budget. Resource mode is separate from search knobs: | Mode | Meaning | | --- | --- | | `quiet` | Low-resource CPU mode; avoid warm-up and release models when idle | | `normal` | CPU-first default; keyword/BM25 recall is ready first | | `performance` | Explicit opt-in for GPU-capable steady-state work; models preload at startup and stay resident, so no request pays a model load | Do not interpret a slow diagnostic search with rerank enabled as "Exomem is slow" without checking timings, resource mode, cache state, and whether a model was cold. ## Verification After setup: ```bash exomem doctor exomem install-hook --check ``` Then ask the client to call `read_instructions(profile="compact")`. A good response includes a `contract_version`, server compute policy, tool defaults, and the search/save workflow. Ask one known vault question next and confirm it uses `search_memory` before answering. For remote connectors, use [remote-quickstart.md](remote-quickstart.md). For the memory boundary, see [vs-built-in-memory.md](vs-built-in-memory.md). After a durable-auth upgrade, keep the existing connector URL and complete its one final GitHub login. New conversations should reuse the stored Exomem bearer; a repeated login prompt is a failed client-compatibility gate, while a `503` means the session authority is unavailable and should not trigger reauthorization.