# exomem — local setup (Claude Code, no cloud) `exomem setup --vault "/path/to/your/Obsidian"` does steps 1–6 below for you in one command — see [Set it up in 5 minutes](README.md#set-it-up-in-5-minutes) in the main README. This document is the full-control manual path: each step run by hand, plus GPU/media extras, for anyone who wants to see or customize what's happening under the hood. This is the **local-first** path: run exomem as a **local MCP server inside Claude Code**, pointed at your own Obsidian vault. No OAuth, no Tailscale, no Windows service — none of the remote/mobile machinery in the main [README](README.md). Everything stays on your machine; the only thing that ever leaves is the query Claude sends to Anthropic to answer you. **Works on macOS, Linux, and Windows.** The commands below use a macOS/Linux shell; the few Windows (PowerShell) differences are called out inline. If you're comfortable in Claude Code, this is ~20–30 minutes. > **Just want it working?** One command does all of it — and wires every agent > client on the machine (Claude Code *and* Codex: MCP server, all ten skills, > hooks): > > ```bash > curl -fsSL https://raw.githubusercontent.com/Artexis10/exomem/main/scripts/install.sh | sh > ``` > ```powershell > irm https://raw.githubusercontent.com/Artexis10/exomem/main/scripts/install.ps1 | iex > ``` > > Claude Code alone? `/plugin marketplace add Artexis10/exomem` then > `/plugin install exomem@exomem` installs the skills and hooks. Finish the MCP > route with `exomem setup --stdio`, or point setup at your existing service. > > The manual walkthrough below exists so you can see what those do, and for when > you want to run the steps yourself. > **For Claude Code, exomem is two parts and you want both.** The **MCP server** > (steps 1-5) is the *hands* — product commands such as `search_memory`, > `create_note`, `capture_source`, `preserve_evidence`, and `review_memory`. The > **skill** (step 6) is the *brain* — it tells Claude *when* to save, how to keep > raw sources and evidence separate from compiled conclusions, when to suggest > links, and how to update knowledge safely. Generic MCP clients that cannot load > Skills should call `bootstrap()` once after connecting; that returns the compact > operating contract through MCP. See [docs/ai-assistant-guide.md](docs/ai-assistant-guide.md) > for Codex, hosted chat clients, Cursor/Windsurf/Gemini, and generic MCP setup. --- ## One command (recommended) After step 1 below (clone + `uv sync`), everything else is a single command: ```bash uv run python -m exomem setup ``` It prompts for your vault, **scans it and shows what's already there** — existing notes are never touched; exomem writes only under `Knowledge Base/` — then initializes the KB, picks lean vs hybrid, runs `doctor`, registers the server with Claude Code (or prints the `.mcp.json` snippet if the `claude` CLI isn't on PATH), installs the skill, and offers the optional hooks. Last, it shows Exomem's learning instruction and asks before it adds that text to your Claude Code `CLAUDE.md` and Codex `AGENTS.md`. The text asks the agent to recall Exomem before a task and save what it learns. Re-running is safe: completed steps report `[skipped]`. Setup prefers one already-running authenticated service when `--mcp-url` or `EXOMEM_BASE_URL` is configured, including cwd `.env`; Claude Code and Codex then use the same `/mcp` core. With no service it registers stdio. Force that local fallback with `--stdio`. Existing registrations are preserved unless you confirm replacement or pass `--replace-client-registration`. Non-interactive (scripts/CI): `uv run python -m exomem setup --yes --vault "/path/to/vault" --lean` `--yes` edits no instruction file. Add `--learning-instruction` to place the learning instruction too. ## Not CLI-comfortable? Ask an assistant to drive You do not need to understand Exomem internals to get started. Give Claude Code, Codex, or another terminal-capable assistant this prompt from the cloned repo: ```text Set up Exomem for my local markdown or Obsidian vault. Use the recommended lean path unless I explicitly ask for embeddings. Run the setup wizard, explain each prompt in plain language before I answer it, and do not move or rewrite my existing vault files. After setup, verify with doctor, call bootstrap(profile="compact") if you are not using the Exomem skill, ask one known vault question with `search_memory`, and save one harmless test conclusion so I can see where it lands. ``` The expected first-run verification is concrete: 1. `exomem doctor` passes for the selected vault. 2. The connected assistant can call `bootstrap(profile="compact")`, unless it has already loaded the Exomem skill. 3. A known question about your vault triggers `search_memory` before the answer. 4. A safe test such as "remember that setup succeeded today" writes a compiled note and reports `Saved -> `. Existing vault material remains read-only input. Exomem writes governed knowledge under `Knowledge Base/` unless you deliberately configure a different governed folder. After setup, you can use simple action aliases instead of learning every canonical operation first: ```bash exomem ask "what do I know about this project?" exomem ask "what supports this decision?" --deep --graph-enrich --json exomem create_note "# Setup succeeded\n\n## Claim\n\nExomem setup completed today." --title "Setup succeeded today" --json exomem capture "raw source text" --title "Source title" --source-type other --json exomem capture "receipt text" --as evidence --scope warranty --category receipts --filename receipt.txt --json exomem review --json exomem connect --path "Notes/Insights/example" --json exomem maintain --json ``` These aliases are thin routes over product commands: `ask` -> `search_memory`, `create_note` -> `create_note`, `capture` -> `capture_source`/`preserve_evidence`, `review` -> `review_memory`, `connect` -> `connect_memory`, and `maintain` -> `maintain_memory` unless a fix flag is explicit. The canonical implementation leaves remain underneath for governance and validation, but new users do not need to learn them first. Handing you a generated file is what makes an assistant keep it. A balanced or maximal assistant uses `proactive_capture` to preserve the exact bytes of every generated file it hands you, as it hands it over. Drafts it never hands over stay unwritten, and so do files it edits in your own workspace or repository. The assistant chooses Source or Evidence by the artifact's role, never its MIME type. If the client has no usable handle, it reports a non-committing upload handoff instead of claiming the artifact was saved. Delivery is recorded only after an Evidence adoption receipt and only through an existing compatible Records collection; a reported remote reference is not proof of remote byte equality. The numbered steps below are the **manual path** — exactly what `setup` does under the hood, kept for troubleshooting and for people who prefer explicit steps. --- ## Already have a vault full of notes? That's the normal case, and it's safe: - **Your existing files are never touched.** All writes go under `Knowledge Base/` — a new folder that `setup`/`init` creates *next to* your existing ones. Everything else in the vault is read-only input; `init` refuses to run if `Knowledge Base/` already exists, so re-running can't clobber anything. *(The governed folder is named `Knowledge Base/` by default; set `EXOMEM_KB_DIRNAME` to govern a differently-named folder — e.g. to adopt one your vault already uses.)* - **Your notes stay searchable.** `search_memory` reaches sibling folders when you use `scope="vault"`; `browse_memory` gives Claude a bounded structural report of the whole vault, and `adopt_vault` turns that scan into a safe adoption report with likely knowledge packs and manifest/copy/compile-planning next actions — one call, not one read per file. - **Daily-notes vaults** (a `Daily/` or `Journal/` tree of dated logs): leave them exactly as they are. The Knowledge Base is a *compiled* layer beside your log, not a migration target — exomem never requires frontmatter, links, or restructuring from existing notes. Good first prompts after setup: *"what does this vault look like?"* — Claude answers with `overview`; or *"adopt this vault safely"* — Claude answers with `adopt`, preserving originals and proposing manifest/copy/compile-planning next actions for you to approve. - **Same vault or a separate one?** Same vault is the default: notes and KB in one Obsidian window, cross-search included. Pick a separate vault only when you want hard isolation (e.g. a shared or team-synced vault where a new top-level folder would bother other tooling). Concrete adoption commands after setup: ```bash # readable read-only report: no files created, moved, edited, or deleted exomem adopt # same report as a machine-readable envelope exomem adopt --json # save the report under Knowledge Base/_Adoption/ exomem adopt --mode save-manifest --json # copy only files you explicitly name into governed Sources/Imported/ exomem adopt --mode copy-as-sources \ --selected-paths "Warranty Case/laptop-receipt.md" \ --json # copy selected legacy text if needed, then return a compile plan; # no compiled note is created until you review and call note() exomem adopt --mode compile-selected \ --selected-paths "Warranty Case/laptop-receipt.md" \ --json ``` See [docs/product-model.md](docs/product-model.md) for the simple action model and [docs/knowledge-packs.md](docs/knowledge-packs.md) for the pack schema. --- ## What you need - **Python 3.11+** — check with `python3 --version`. On macOS, `brew install python` if you don't have it (or use the [python.org](https://www.python.org/downloads/) installer). - **uv** — the documented install path uses the repo lockfile. Install from <https://docs.astral.sh/uv/> if `uv --version` fails. - **Claude Code** (you already have this) - An **Obsidian vault** — or just any folder you want to use as one. It needs a `Knowledge Base/` subfolder (we create a minimal one below). - Git, to clone the repo. --- ## 1. Install ```bash git clone <repo-url> exomem cd exomem uv sync # lean: keyword/BM25 search, no heavy deps # for hybrid semantic search, add the extra (~1-2 GB torch + sentence-transformers): # uv sync --extra embeddings ``` > **Lean by default.** `uv sync` is the light path — search runs on > keyword/BM25, no torch, works everywhere. For hybrid semantic search (better > recall on natural-language queries), install the extra: `uv sync --extra > embeddings` — a ~1-2 GB torch download. It's **GPU-accelerated on both NVIDIA > (CUDA) and Apple Silicon (Metal/MPS)**, auto-detected; CPU-only boxes work too, > just slower. Start lean; upgrade anytime by installing the extra and unsetting > `EXOMEM_DISABLE_EMBEDDINGS`. **On a Mac, see "Apple Silicon" in step 4 below.** If you already manage Python environments yourself, `pip install -e .` still works as a fallback; the `uv` path is preferred because it honors `uv.lock` and the repo's configured PyTorch wheel source. Before touching your own vault, you can verify the repo against the public sample vault: ```bash uv run exomem demo --json ``` That read-only smoke runs the path a new install depends on: `doctor`, keyword `find`, `get`, and `audit`. --- ## 2. Bootstrap your Knowledge Base One command lays down the whole structure — `index.md`, `log.md`, the `_Schema/` contract, and the typed `Sources/ Notes/{…} Entities/{…} Evidence/` tree — into your vault: ```bash uv run python -m exomem init --vault "/path/to/your/Obsidian" ``` It refuses if a `Knowledge Base/` already exists, so it won't clobber anything. The shipped `_Schema/` is a **genericized starter contract** — adapt `Knowledge Base/_Schema/project-keys.yaml` to your own projects (or just start writing; the writer auto-registers new project keys as you go). --- ## 3. Point it at your vault The server finds your vault via one env var — the folder that *contains* `Knowledge Base/`: ```bash export EXOMEM_VAULT_PATH="/path/to/your/Obsidian" # the vault root, not the KB folder ``` --- ## 4. (Choose) hybrid vs lean - **Lean / keyword-only (default install)** — `uv sync` + set `EXOMEM_DISABLE_EMBEDDINGS=1`. `find` uses BM25 (stemmed substring + ranking). Instant, no model load, no GPU, works everywhere. The easiest start. Note it's **silent about it** — there's no error when embeddings are off, so "search works" on a lean install means keyword/BM25, *not* semantic. - **Hybrid** — install the extra (`uv sync --extra embeddings`) and leave `EXOMEM_DISABLE_EMBEDDINGS` unset. Adds local vector embeddings + graph on top of BM25 — best recall on natural-language queries. GPU-accelerated on NVIDIA (CUDA) or Apple Silicon (Metal/MPS), auto-detected; CPU works but embeds slowly. The vector index builds as you write (each note is embedded on save); to backfill an existing vault, run `kb reconcile` after installing the extra. Quick check that semantic is live: ask for something using words that *don't* appear in the note — if it still surfaces, embeddings are on. **Apple Silicon (Mac) — full GPU acceleration.** On an M-series Mac exomem uses the **Metal GPU automatically** — no config. bge/CLIP embeddings run on MPS (in fp16), and audio/video transcription runs on Metal via `mlx-whisper` once you add its extra: ```bash uv sync --extra embeddings --extra media --extra media-mlx ``` `select_device()` picks MPS and `get_transcriber()` picks MLX on Apple Silicon on their own. Confirm the accelerated stack is live: ```bash uv run python scripts/verify-mlx.py # expect: GATE: PASS uv run exomem doctor --profile media # torch.device: mps, asr.backend: mlx-whisper ``` Optional knobs: `EXOMEM_MPS_FP16=0` keeps embeddings in fp32; `EXOMEM_TORCH_DEVICE=cpu` forces CPU (e.g. to avoid thermal throttling on a fanless Air during a big backfill); `EXOMEM_MLX_WHISPER_MODEL=mlx-community/whisper-large-v3-turbo` picks a lighter ASR model. Preflight the selected path before wiring Claude: ```bash uv run python -m exomem doctor --vault "/path/to/your/Obsidian" --profile lean # or, after installing embeddings: uv run python -m exomem doctor --vault "/path/to/your/Obsidian" --profile hybrid ``` ### Resource modes The safe default is `normal`: no automatic CUDA residency, no startup model or whole-vault cache preload, and idle reclamation enabled. For gaming or other foreground work, quiet additionally defers expensive indexing: ```bash uv run python -m exomem mode quiet uv run python -m exomem status --resources --json ``` Quiet skips heavy startup warm-up, makes large caches evictable, and defers expensive semantic/CLIP indexing while keeping cheap freshness/inbound/resolver updates live. After foreground work, return to `normal` or run an explicit heal: ```bash uv run python -m exomem mode normal uv run python -m exomem index --vault "/path/to/your/Obsidian" uv run python -m exomem reconcile --vault "/path/to/your/Obsidian" ``` Use `performance` only when you explicitly want GPU-capable bulk/model work. It preloads the models at startup and keeps them resident — idle reclamation still evicts caches, but not the preloaded models, because reloading one costs whichever request arrives next about half a minute. `exomem doctor --profile hybrid` reports that state under `models.residency`: whether a model is loaded, whether its weights are in the local HuggingFace cache, and whether the next load resolves from that cache instead of revalidating it over the network. ```bash uv run python -m exomem mode performance ``` --- ## 5. Add it to Claude Code If an Exomem HTTP service already runs on this machine or behind your tunnel, reuse it instead of starting one model-capable process per Claude session: ```bash uv run python -m exomem setup \ --vault "/path/to/your/Obsidian" \ --mcp-url https://<host>/mcp ``` Authenticate from Claude Code with `/mcp`. For a deliberately local-only installation, setup can create the stdio route for you with `--stdio`. The manual equivalent is: ```bash claude mcp add exomem \ --env EXOMEM_VAULT_PATH="/path/to/your/Obsidian" \ --env EXOMEM_DISABLE_EMBEDDINGS=1 \ -- uv --directory "$PWD" run python -m exomem --transport stdio ``` (Drop the `EXOMEM_DISABLE_EMBEDDINGS` line for hybrid. If you use the pip fallback instead of uv, use the **full path to your venv's `python`**.) Each stdio client/session owns this process. Several active sessions can therefore load several private embedding/Metal runtimes; use the shared HTTP route when a service is already available. Or by hand in `.mcp.json` (project) / your Claude Code settings: ```json { "mcpServers": { "exomem": { "command": "uv", "args": ["--directory", "/path/to/exomem", "run", "python", "-m", "exomem", "--transport", "stdio"], "env": { "EXOMEM_VAULT_PATH": "/path/to/your/Obsidian", "EXOMEM_DISABLE_EMBEDDINGS": "1" } } } } ``` Restart Claude Code; you should see the product `exomem` tools (`bootstrap`, `search_memory`, `read_memory`, `create_note`, `capture_source`, `review_memory`, `maintain_memory`, …). Quick test before wiring: `uv run python -m exomem --transport stdio` should start and wait on stdin without error. --- ## 6. Install the skill (Claude Code best UX) The server gives Claude the tools; **the Exomem Knowledge Base skill is what makes Claude Code use them well** — capture at natural stopping points, file sources to the right folder, and compile notes under the schema. One command installs it straight from the repo into Claude Code's skills folder (no vault path needed — it ships in the package): ```bash uv run python -m exomem install-skill ``` That writes the core skill to `~/.claude/skills/exomem/` and installs the named workflow skills beside it, such as `exomem-continue`, `exomem-capture`, `exomem-research`, `exomem-review`, and `exomem-media`. The workflow skills are short operating loops for common user intents; the core `exomem` skill remains the contract that preserves Sources, Evidence, compiled notes, review, and supersession. See [docs/workflow-skills.md](docs/workflow-skills.md). The core skill uses the same name as the Exomem connector and tools, so it all reads as one product. (If you installed before the rename, this also retires the old `knowledge-base` skill folder.) **Restart Claude Code** so it loads. Useful flags: `--link` symlinks instead of copying so it tracks repo updates as you `git pull` (falls back to a copy if your OS refuses the symlink); `--force` overwrites an existing install; `--target` picks a different folder. Then **make it yours** — the shipped `SKILL.md` / `project-keys.yaml` are a **generic starter** (placeholder projects `personal` / `work`, no machine paths or real tenants). Optionally adapt the **project keys** in your vault's `Knowledge Base/_Schema/project-keys.yaml` (the copy the *server* reads) to your own — or just start writing; the writer auto-registers new keys as you use them. > **What "auto-capture" does and doesn't do.** With the skill loaded, Claude > captures on its own *inside a conversation* when it judges you've hit a > stepping-stone — a decision, a solved problem, a recognized pattern. There's > **no background daemon**: it won't save things while you're away from the chat, > and a fresh thread starts fresh. You can always just say *"save that to kb."* > A stable preference, recurring routine, historical baseline, or durable > affiliation is eligible only when stability or recurrence and reusable > comparison, interpretation, or decision value are clear. A uniquely resolved > Entity receives its facet; otherwise capture one concise compiled observation; > an observed measurement uses only compatible existing Records. Fleeting > preferences, one-off activity, incidental associations, trivial metrics, and > tentative claims stay quiet. 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`. > > **Other MCP clients.** ChatGPT, Codex, Cursor, Gemini, Windsurf, or any client > without Skill support should call `bootstrap()` once after connecting. It returns > Exomem's search/save/upload defaults, the compiled-note write loop, and > performance guidance in a structured MCP response. The copyable standing instruction lives in > [docs/ai-assistant-guide.md](docs/ai-assistant-guide.md). --- ## 7. (Recommended) Make the KB automatic — both directions The skill *tells* Claude to capture at stepping-stones and to consult the KB before answering, but those instructions are passive — over a long conversation Claude tends to forget them, so auto-save quietly never fires (you'll know: `Knowledge Base/log.md` only shows saves you asked for) and prior notes don't get pulled in. This command installs those two reliability nudges plus a local continuation checkpoint for compaction and resume: ```bash uv run python -m exomem install-hook ``` Codex CLI can use the same bundled Exomem hook scripts: ```bash uv run python -m exomem install-hook --client codex ``` If you maintain alternate Claude settings files with yadm, wire each active variant too, for example `--settings ~/.claude/settings.json##os.Msys`. - **Write** — a `Stop` hook that re-checks "is this worth saving?" at the end of each turn, so conclusions get captured on their own. - **Read** — a `UserPromptSubmit` hook that reminds Claude to run `search_memory` first when your message touches something the KB might hold, so it actually behaves as your source of truth. - **Continue** — one shared, stdlib-only checkpoint core with thin Claude and Codex adapters. It records bounded structural evidence before compaction and reinjects it after compact/resume, even when MCP is disconnected, OAuth needs repair, or no vault is configured. It never calls a model, MCP, REST, or the Exomem CLI on the compaction path. | Lifecycle event | Claude Code | Codex CLI 0.144.3 | | --- | --- | --- | | `PreCompact(manual|auto)` | write checkpoint | write checkpoint | | `SessionEnd` | write checkpoint | unsupported; not registered | | `SessionStart(compact|resume)` | validate and reinject | validate and reinject | The checkpoint is deliberately structural-only. It can contain repository and worktree identity, HEAD/dirty status, bounded file paths, artifact hashes and checkbox counts/line numbers, plus a bound hash of a transcript byte slice. It does **not** parse or store conversation messages, tool/system output, compaction summaries, secrets, or artifact/task text. Reinjected context points the agent at files to reopen and advises it to capture durable conclusions later; it never writes checkpoint or transcript data into Exomem automatically. The two nudge hooks are cheap: gated so they stay quiet on ordinary turns/prompts, plus a per-session cooldown. The read hook is still language-agnostic for substantive prompts, but it also suppresses obvious short control/status prompts such as `continue`, `thanks`, `are you done?`, `merge it`, and `restart the server` so the reminder does not churn through routine command flow. They write scripts to `~/.claude/hooks/` and wire the two hooks into your settings.json — restart Claude Code to activate. Triggers log to `~/.claude/exomem-capture-nudge.log` and `~/.claude/exomem-retrieve-nudge.log` so you can see the real rate. For Codex, the same scripts go to `~/.codex/hooks/`, wire into `~/.codex/hooks.json`, and log under `~/.codex/`. Prefer to wire it by hand? `uv run python -m exomem install-hook --print-only` writes the scripts and prints the snippet to paste. The read hook is a nudge, not a forced retrieval policy. The agent should still skip Exomem for unrelated chat, tiny control prompts, or follow-ups where the current conversation already contains the needed KB evidence. To verify the deployed hooks without changing anything: ```bash uv run python -m exomem install-hook --check ``` That checks both Claude Code and Codex by default. Use `--client claude` or `--client codex` to narrow it. The report flags stale deployed hook copies, legacy `kb_*` hook entries, missing config, and the log/cache paths where hook activity should land. Before the first lifecycle event, missing checkpoint state is a healthy warning. Continuation state and metadata-only event logs live under `~/.claude/.cache/exomem-continuation/` or `~/.codex/.cache/exomem-continuation/`; `CLAUDE_CONFIG_DIR`, `CODEX_HOME`, and the test/isolation override `EXOMEM_HOOK_HOME` move scripts, config, state, and logs together. Checkpoints are fresh for 30 days; expired non-current sessions are pruned without following symlinks or deleting a live writer's state. Set `EXOMEM_CONTINUATION_DISABLE=1` before launching the client to bypass all continuation writes and reinjection without deleting existing state. After installation or migration, restart/reload that client and approve/trust the hook if it asks. Re-running `install-hook` migrates only exact legacy `kb_continuation_checkpoint.py` / `kb-continuation-checkpoint.sh` entries, preserves unrelated hooks (including any user-owned Codex `SessionEnd`), backs up changed valid config, and is otherwise idempotent. To roll it back: ```bash uv run python -m exomem install-hook --uninstall ``` That removes only the entries this installed — recognised the same way the idempotent install recognises its own, so a hook you wrote yourself in the same group survives — and then deletes the scripts it deployed. Add `--keep-scripts` to unwire the config but leave the yadm-synced hook tree in place, `--client codex` (or `--client all`) to pick the client, and `--json` for the machine report. Restart the client afterwards; it keeps running the hooks it already loaded. Existing checkpoint state is inert and may be deleted separately. Uninstall also removes the learning instruction that setup placed between its markers in that client's `CLAUDE.md` or `AGENTS.md`, and leaves the rest of the file alone. **If your dotfiles are yadm-managed, the deployed file is not the file that matters.** Where `settings.json` is produced from alternates (`settings.json##os.Msys`, `##os.WSL`, and so on), yadm regenerates it from the source whenever alternate selection runs — and an ordinary `yadm status` is enough to trigger that, so hooks removed from the deployed file reappear with no obvious cause. `--uninstall` finds those sources and prunes them too, then tells you to commit them: until the change is committed, the next machine to sync restores the hooks from the committed copy. A source it cannot parse (a yadm template) is named in the report and exits non-zero rather than being rewritten blind. Below `maximal` the capture reminder fires only on turns that land work (a commit, push, merge, tag, or PR/release create or merge); `EXOMEM_CAPTURE_NUDGE_MIN_CHARS` then sets the `maximal` length gate and what counts as a substantive turn for the episode ask. The episode ask also needs a landing since the last ask or record: a session that never lands work is never asked, and an ask answered without a record waits for the next landing. Tune with `EXOMEM_CAPTURE_NUDGE_MIN_CHARS` / `EXOMEM_RETRIEVE_NUDGE_MIN_CHARS` (and the matching `_COOLDOWN_SEC`), `EXOMEM_RETRIEVE_NUDGE_CONTROL_MAX_CHARS` for the read hook's control-prompt skip ceiling, or disable either with `EXOMEM_CAPTURE_NUDGE_DISABLE=1` / `EXOMEM_RETRIEVE_NUDGE_DISABLE=1`. **Writing in a dense script (Japanese, Chinese)?** Lower the `MIN_CHARS` values — those scripts pack more meaning per character, so the defaults (tuned for English) can under-fire. (These tunables were renamed from `KB_*` to `EXOMEM_*`; the old `KB_*` names are still accepted for back-compat.) **Opt-in: upgrade the read-side reminder to real retrieved content.** By default the `UserPromptSubmit` hook only reminds Claude to run `search_memory` — set `EXOMEM_RETRIEVE_INJECT=1` and it instead fetches the top 3 compact routing stubs (hybrid mode, so a pasted ticket or a sentence with punctuation still finds its pages; keyword mode is an all-tokens gate that real prompts never pass) for the same gated prompt and appends them to the reminder, so relevant prior KB pages are already in context before Claude decides whether to search. It tries a short transport ladder and never blocks on a slow path: REST first (one `POST /api/search_memory`, 4s timeout) — attempted when `EXOMEM_REST_API_KEY` is set in the client's environment **or** persisted in the managed install's `service.env` (`~/.config/exomem/service.env` on Linux, `~/Library/Application Support/Exomem/service.env` on macOS; override the location with `EXOMEM_SERVICE_ENV`). A key read from that file is only ever sent to a loopback host: point `EXOMEM_HOST` elsewhere and the REST rung is skipped for it. Then, only if you also set `EXOMEM_RETRIEVE_INJECT_CLI=1`, an `exomem search_memory --json` subprocess call (~5s timeout, slower — cold Python start). The two rungs share one 8s budget under the hook's 10s timeout, measured on elapsed time: a REST call that dribbles bytes past the budget is abandoned and the CLI rung gets what is left. If neither is configured or reachable, it falls straight back to the plain reminder — no network call is ever attempted unless `EXOMEM_RETRIEVE_INJECT` is on. The stub block is cut by whole lines (600 characters), never inside a path, with a `… N more not shown` marker when a hit was dropped. Each fired nudge writes one line to `~/.claude/exomem-retrieve-nudge.log` (or `~/.codex/...`) naming the lane that answered (`lane=rest|cli|none|off`) and the hit count, so a silent fall-through to the plain reminder is visible. (The legacy `KB_RETRIEVE_INJECT` / `KB_RETRIEVE_INJECT_CLI` names still work too.) **Opt-in: a compiled working set instead of routing stubs.** Set `EXOMEM_RETRIEVE_INJECT=working_set` and the same gated prompt goes to `recall_context` instead of `search_memory`: one `POST /api/recall_context` over the same ladder and the same 8s budget, and the returned working-memory packet *replaces* the reminder under a fixed header that names it as retrieved memory rather than instructions. It carries current state first, then units, then pointers, each with the provenance ref you can `read_memory`, keeping whole items only under `EXOMEM_RETRIEVE_INJECT_MAX_CHARS` (default 4,000 characters) and dropping trailing ones rather than cutting one in half. A packet that abstains as `ambiguous` injects the competing anchors and asks the agent to call again with `anchor` set — it is the only decider of which sense a turn meant; every other abstention leaves exactly the plain reminder, as does any failure. The packet's `continuity` token is kept per client and session beside the continuation checkpoint and handed back on the next prompt, and the checkpoint hook drops it on each session lifecycle event, so consecutive turns do not re-resolve the world but a new session or a compaction starts clean. This mode injects far more per prompt than the stub block does, which is the trade it exists to let you make. (Hooks are local-client only — claude.ai web/mobile can't run them, so there the skill or `bootstrap()` contract stays best-effort: nudge it with *"save that to kb"* or *"check the kb."*) --- ## You're up Try it in Claude Code: *"capture this source and compile an insight from it,"* or *"ask Exomem what I know about X,"* or *"review the KB."* Then run **`exomem maintain --reconcile`** once to sync index counts after manual edits. ## Optional: mobile / claude.ai-web access Want the on-the-go experience — querying your KB from **Claude mobile**? Same engine, just the remote tier. It's not *hard*, but it's genuinely more than the local path, because a phone needs an always-on, publicly-reachable, authenticated endpoint: 1. **An always-on host** — your desktop running 24/7, or a cheap VPS. (Local stdio dies when you close Claude Code; mobile needs it always up.) 2. **A public HTTPS endpoint** — **Tailscale Funnel** (no domain needed — gives a free `*.ts.net` host; the simplest path if you don't own a domain) or **Cloudflare Tunnel** (needs a domain you own in Cloudflare; more burst-tolerant under heavy use). This exposes the server to the internet, so auth becomes mandatory. 3. **A GitHub OAuth app** (client id + secret) wired into the OAuthProxy — claude.ai connectors require OAuth; static tokens aren't accepted. 4. **Lock it to your GitHub login** (the single-user verifier), then run it as a background service with `--transport streamable-http`. On macOS or Linux run `bash scripts/install-service.sh --release`; on Windows run `pwsh -File scripts/install-service.ps1 -Release`. These default to the resource-bounded standard multimodal profile, release commands create the PyPI service environment, load `.env`, doctor-gate, start the OS service, and verify `/mcp` (the main [docs/deployment.md](docs/deployment.md) covers all options, including repo-dev). 5. **Add it as a custom connector** in claude.ai. [docs/deployment.md](docs/deployment.md) documents this path end-to-end. Rule of thumb: the **local path is ~90% of the value for ~20% of the effort**; the mobile tier is the rest — worth it if you genuinely want your KB in your pocket. ### Make the KB proactive in the Claude app (custom instructions) claude.ai (web/mobile) can't run hooks — those are Claude Code and Codex only — so there is nothing there to re-arm the proactive find/capture check each turn, and instruction text alone decays over a long thread. That is why the shipped default on web and hosted is **maximal** prominence, while Claude Code and Codex default to **balanced**: maximal on a hookless client produces roughly the behaviour balanced produces on a hooked one. **[docs/prominence.md](docs/prominence.md) is the full reference** — four levels (`off` / `light` / `balanced` / `maximal`), what each one changes, and a copy-paste block per level for both claude.ai and ChatGPT. Set it on a local install with `exomem prominence <level>`; on web, paste the block. Tune *down* if it is too chatty — you should never have to tune up to get it working. This vault is served by Exomem, an MCP server (formerly kb-mcp). Once added as a connector, its tools appear under whatever name you assign it (e.g. "Knowledge Base"). The Exomem block below is the **balanced** wording, kept here as the inline example; paste it into the Claude app at **Settings → Profile → "What personal preferences should Claude consider in responses?"**: ``` I keep a personal Knowledge Base served by the Exomem MCP. If no Exomem skill is loaded, call bootstrap(profile="compact") once at the start of a new chat and follow it. Exomem prominence: BALANCED. Use Exomem proactively: search first when a turn touches my projects, notes, decisions, or domains (cite what you find; an empty search is a gap, not a dead end). Do not search on unrelated chit-chat, small control prompts, or follow-ups where the current conversation already has the needed KB evidence. Capture durable conclusions on your own — a decision, solved problem, diagnosed failure, recognized pattern, or stable preference, recurring routine, historical baseline, or durable affiliation when stability or recurrence and reusable comparison, interpretation, or decision value are clear. Route a uniquely resolved Entity facet there; otherwise write one concise compiled observation; an observed measurement uses only compatible existing Records. Fleeting preferences, one-off activity, incidental associations, trivial metrics, and tentative claims stay quiet. A concise observation, narrow Entity facet, new Entity or own edge follows `proactive_capture`; a queued relation requires `link_acceptance`; merge or structural change requires confirmed `restructure_execution`. Save a short compiled note, not a transcript, then report one line: "Saved -> <title>". Ask before saving only if type/scope is genuinely ambiguous. Stay quiet on chit-chat; don't narrate empty searches. ``` Optionally paste this separate response-style block too (or trim it to taste): ``` Precise and non-performative: no hype, fluff, or motivational tone; clarity and correctness over filler. Use lists/structure only when they genuinely help; plain prose is fine. Match length to the substance, terse when simple and fuller when it's not. ``` Account-level custom instructions are always in context, so the Exomem block makes Claude reach for the connected KB on its own — the app-side equivalent of the Claude Code hooks. The "do not search" line keeps it from firing on unrelated or already answered turns. For the maximal wording (recommended on web), the lighter levels, and the ChatGPT variants, see [docs/prominence.md](docs/prominence.md). For more client-specific instructions, see [docs/ai-assistant-guide.md](docs/ai-assistant-guide.md).