The agent keeps its to-do list in claude-mem
Every session now opens with a work-state section ahead of memory: a rule telling the agent to use claude-mem's work_state_write and work_state_read tools as its canonical to-do list, then whatever is still open in the project. Claude Code gives Claude 5 models no native to-do tool, so until now nothing recorded what was in progress or what was left when a session ended. The rest of the release adds an openai-compatible provider with presets, a Codex subscription provider, Kimi Code and Oh My Pi support, an opt-in quota fallback, and fixes across capture, search, the worker and Windows. Several defaults changed; see Upgrade notes.
Work state
- Two MCP tools.
work_state_writeappends one entry to a named list (fields capped at 2,000 characters as JSON) and replies with what is still open in that list.work_state_readreturns every open item, or one list, and adds done and dropped items whenincludeClosedis true. (#4340) - Lists, items and state. An entry with a
taskfield is a to-do item with astatusoftodo,doing,doneordropped; any other field is state on the list. The latest value of each key wins,nullclears a key, and"status": "done"closes the list. (#4340) - SessionStart leads with it. Context opens with the rule and every open item, each with how long ago it last changed, capped at 3,000 characters (806 when nothing is open); memory is fitted into what remains of the 10,000-character limit. The welcome hint for a project with no observations gets the same lead; the colored terminal preview does not. (#4340)
- Scoped like memory. Writes land under the checkout's primary project key and reads cover every key the checkout reads, so a list started in the main checkout also shows in its worktrees. Writes from projects matched by
CLAUDE_MEM_EXCLUDED_PROJECTSare not saved. (#4340) - Kept in the database, not the repo. Entries go to a new append-only
work_state_entriestable (schema v61), so lists never conflict on merge but are not in git, and reads and writes need the worker. The server runtime's SessionStart does not read this table yet. (#4340)
Upgrade notes
- Observer deadline raised to 3 minutes.
CLAUDE_MEM_LLM_TIMEOUT_MSnow defaults to180000(was30000), and the newCLAUDE_MEM_FIELD_OPTIMIZE_TIMEOUT_MSfor oversized-field condensation (a fixed 30 seconds before) defaults to the same. Asettings.jsonholding exactly the old30000is moved once; any other value is kept. (#4278, #4287, #4136) - New OpenRouter default model. OpenRouter retired
xiaomi/mimo-v2-flash:free, so the default is nowcohere/north-mini-code:free, and a storedCLAUDE_MEM_OPENROUTER_MODELequal to the retired id is rewritten once when the base URL is blank or openrouter.ai. A retired or unknown model now fails with amodel_unavailableerror that names the setting. (#3662) - Subagent observations stay out of SessionStart.
CLAUDE_MEM_CONTEXT_MAIN_AGENT_ONLY(defaulttrue) leaves rows that carry both an agent id and an agent type out of the SessionStart window, in the worker and the server runtime. Search, timeline andget_observationsstill return them; set it tofalsefor the old behavior. (#3310, #4290) - Hooks never block a session. No claude-mem hook exits 2 any more, so an unexpected error or a worker outage no longer drops your prompt, denies a tool call or re-wakes Stop; the session continues without memory. After
CLAUDE_MEM_HOOK_FAIL_LOUD_THRESHOLD(default3) unreachable-worker hooks in a row you get one notice per session to runnpx claude-mem restart, and Claude Code hooks other than Setup exit 0 even when the plugin scripts are missing. (#2892, #3168, #3431) - UserPromptSubmit gets 15 seconds in Claude Code. The hook timeout drops from 60 to 15 seconds, and session init spends one budget,
CLAUDE_MEM_SESSION_INIT_TIMEOUT_MS(10 seconds; 7 on Windows, where longer saved values are cut to 7), across the whole worker round-trip. (#3440, #4299) - The worker refuses unknown host names. As a DNS-rebinding guard, a request whose
Hostis a DNS name other thanlocalhost,*.localhost,host.docker.internal,CLAUDE_MEM_WORKER_HOST, theCLAUDE_MEM_PUBLIC_URLhost or an allowed origin gets a 403; IP addresses still work. If you open the viewer through another host name (a.localname, a reverse proxy), add its origin to the newCLAUDE_MEM_ALLOWED_ORIGINS(comma-separated) and restart the worker. (#3514) - Antigravity users: re-run install. Earlier installs wrote
~/.gemini/config/hooks.jsonin a shapeagyignores, so nothing was captured. Runnpx claude-mem install --ide antigravityto rewrite it inagy's named-hook schema;npx claude-mem antigravity-cli statusreports entries left to migrate. (#4274)
Providers and gateways
- New
openai-compatibleprovider.CLAUDE_MEM_PROVIDER=openai-compatibleruns the observer against any OpenAI/chat/completionsendpoint, configured withCLAUDE_MEM_OPENAI_COMPAT_PRESET,CLAUDE_MEM_OPENAI_COMPAT_BASE_URL,CLAUDE_MEM_OPENAI_COMPAT_MODELandCLAUDE_MEM_OPENAI_COMPAT_API_KEY. Endpoints on localhost or a private network need no key, and a selected but half-configured provider falls back to Claude. (#3942) - Presets.
nvidia-nim,deepseek,groq,together,ollama,lmstudioandvllm(#3942),orcarouter(#3581),opencode-goandopencode-zen(#3623),minimaxandminimax-cn(#3376),api-route(#4325) andopper(#4333). Model ids are passed verbatim, and a leading<think>…</think>block is stripped from replies so inline reasoning is not stored (#3376). - Endpoint settings in the viewer. A new "OpenAI-compatible endpoint (BYOK)" provider option edits the preset, base URL and model (the key stays in
settings.jsonor.env), and the OpenRouter block showsCLAUDE_MEM_OPENROUTER_BASE_URL, read-only while it points at the claude-mem observer. The settings API rejects base URLs that are not http(s). (#3433) - Codex subscription provider.
CLAUDE_MEM_PROVIDER=codex, ornpx claude-mem install --provider codex [--model <id>], runs the observer through the Codex CLI app-server on your ChatGPT subscription; runcodex loginfirst.CLAUDE_MEM_CODEX_MODEL(empty uses Codex's default) andCLAUDE_MEM_CODEX_REASONING_EFFORT(defaultlow) are optional, andCLAUDE_MEM_CODEX_PATH(defaultcodex) can be set only insettings.jsonor the environment. (#3882, #4216, #4318) - Codex throughput. Codex runs up to
CLAUDE_MEM_CODEX_MAX_CONCURRENT_AGENTSrequests at once (default2) and sends consecutive queued observations in one request, up toCLAUDE_MEM_CODEX_OBSERVATION_BATCH_SIZEitems (default8) andCLAUDE_MEM_CODEX_OBSERVATION_BATCH_MAX_CHARScharacters (default32000). The viewer does not expose these three; set them insettings.json. (#4260, #4261) - Codex failures are classified. A request Codex refuses the same way every time becomes a setup error with a remedy instead of an endless retry, app-server internal errors (-32603, -32700) are transient, and an empty reply goes through the normal skip handling. On Windows the default
codexcommand launches thecodex.cmdshim. (#4222, #4316, #4323) - Several keys per provider.
CLAUDE_MEM_GEMINI_API_KEYS,CLAUDE_MEM_OPENROUTER_API_KEYSandCLAUDE_MEM_OPENAI_COMPAT_API_KEYStake extra keys, separated by commas or newlines. A key that hits a rate limit, a spent quota or an auth failure is set aside for 1 minute, 30 minutes or 6 hours and the next key is used; the cmem.ai gateway never uses a pool. (#3941) - Quota fallback provider (opt-in).
CLAUDE_MEM_QUOTA_FALLBACK_PROVIDER(claude,gemini,openrouteroropenai-compatible; empty, meaning off, by default) takes observer work while the selected provider is in a quota cooldown and hands it back once the primary answers its probe.CLAUDE_MEM_QUOTA_FALLBACK_MODELpicks the model for a Claude fallback, both are in the viewer, and authentication failures are never routed around. (#4268, #4306) - cmem.ai trial-expiry fallback works again. Since v13.24.11 a terminal gateway rejection never moved memory to your Anthropic plan. Now
allowance_exhausted,key_invalid,subscription_inactiveor any gateway 401/403 switches to Claude at once and resumes the buffered work there, the SessionStart notice relays the gateway's own message and link, and unattended resumes on the gateway are capped at 3 in a row. (#4276, #4273, #4306) - OpenRouter request options.
CLAUDE_MEM_OPENROUTER_REASONING_EFFORT(none,minimal,low,mediumorhigh; empty sends nothing) sets reasoning for requests to openrouter.ai only (#3001).CLAUDE_MEM_OPENROUTER_EXTRA_BODY(empty by default) merges a JSON object into OpenRouter-provider requests, never to the cmem.ai gateway, and cannot overridemodel,messages,streamor the token caps (#3040). - Gateways that stream by default. Requests to openrouter.ai and custom base URLs send
stream: falsein the worker and the server runtime, so a gateway that streams unless told otherwise no longer fails every observation (#3668, #4317). A litellm "Unable to get json response" reply is retried (#3263), and an OpenRouter reply cut at the output cap is logged with the cap and request id (#3620). - Observer output cap and system prompt. The new
CLAUDE_MEM_OBSERVER_MAX_OUTPUT_TOKENS(default4096) sets the output cap on OpenRouter, openai-compatible, cmem.ai gateway and Gemini observer requests, which now carry the observation schema in the system message (systemInstructionon Gemini). (#3868) - Gemini replies and throttles. The Gemini provider reads the answer parts of a reply instead of a leading reasoning part, which had stored nothing (#4090). A 429 that names only a per-minute limit is retried after Google's delay instead of pausing capture for 30 minutes, read from the structured error details (#4089, #4243).
- Daily caps and region refusals. A per-day 429, such as OpenRouter's
free-models-per-day, counts as a spent daily allowance in the worker and the server runtime (#4089, #4308). Gemini's "User location is not supported" pauses capture aslocation_unsupportedwith advice to choose anotherCLAUDE_MEM_PROVIDER, without rotating through the key pool (#4147, #4308). - HTTP provider errors. On openai-compatible endpoints a context-length refusal recycles the observer generation instead of dropping the batch, a per-minute 429 that links to a billing page stays a rate limit, and a key pool waits for a briefly throttled key instead of arming the 30-minute breaker (#4317). An OpenRouter or openai-compatible request that gets no response names the error code and host, with a Local Network permission hint for hosts on your network (#4115, #4320).
New hosts and harnesses
- Kimi Code CLI.
npx claude-mem install --ide kimi, ornpx claude-mem kimi install|status|uninstall, writes hooks to$KIMI_CODE_HOME/config.tomland the MCP server to$KIMI_CODE_HOME/mcp.json(default~/.kimi-code). Memory is injected on a session's first prompt and after compaction, tool output and failed calls are captured, and Kimi's bookkeeping tools (to-do, task and cron) are skipped. (#3676, #3547) - OMP (Oh My Pi).
npx claude-mem install --ide ompinstalls a hook at~/.omp/agent/hooks/pre/claude-mem.ts(under$PI_CODING_AGENT_DIRwhen set) that records sessions, every prompt, tool results and summaries and injects memory before model calls. Its worker requests time out after 5 seconds. (#3556, #4315) - DeepSeek Harness transcripts (opt-in). The transcript watcher can tail zstd-compressed
*.jsonl.zstdsession logs, and the repository'stranscript-watch.example.jsonhas adshschema and watch entry for~/.dsh/sessionsto copy into~/.claude-mem/transcript-watch.json. (#3691) - OpenCode plugin loads and files sessions correctly. On OpenCode 1.18 the plugin failed with "Plugin export is not a function"; it now loads, tags sessions
opencode, keys them by checkout like other hosts, and records the real prompt (#3803). Memory context is added to each request's system prompt, and captures refused while the worker boots are retried for about 10 seconds (#3208, #4091). - OpenCode configuration. Install registers the claude-mem MCP server in
opencode.json(#3621), stops writing memory into the global~/.config/opencode/AGENTS.mdand removes a block an older install left there, and a failed context fetch is retried after a minute instead of on every system prompt (#4314). - Codex hooks. Codex hook events keep
tool_use_id,agent_idandagent_type, so dedup and the subagent settings apply (#4329). Codex's own helper prompts (task titles, memory consolidation, onboarding) no longer become sessions (#2810), and worktrees at~/.codex/worktrees/<id>/<repo>file memory under<repo>instead of<repo>/<repo>(#3643). - Codex subagent capture (opt-in). Codex hooks do not fire for subagent threads, so set
CLAUDE_MEM_CODEX_SUBAGENT_INGESTION=true(defaultfalse) for a transcript watch scoped to subagent rollouts.CLAUDE_MEM_SKIP_SUBAGENT_OBSERVATIONS=truestill wins. (#3655, #4321) - Antigravity, Qwen Code and the
claudealias. Sources namedagy,antigravityorantigravity-*are recorded asantigravity-cliwith their own viewer badge (#4147), and--ide claudeandhook claude <event>behave likeclaude-code(#2835). A host-sentsubmitted_promptis stored as the prompt, and an empty one no longer stores a[media prompt]row for every tool round in Qwen Code (#4224). - Grok Bot brainbeat webhook (opt-in). Set
CLAUDE_MEM_GROK_BOT_WEBHOOK_URLand claude-mem POSTs each observation that matches the Grok Bot awareness triggers to it, sendingCLAUDE_MEM_GROK_BOT_WEBHOOK_SECRETas a header when set. It is off while the URL is empty. (#3846)
Memory, context and search
- Named environments.
CLAUDE_MEM_PROJECT_ENVIRONMENTS(default[], off) takes a JSON array of{"name", "patterns"}, and folders matching an environment's globs share one project named after it.npx claude-mem project merge <from> <into> [--dry-run]folds one project's memory into another without rewriting rows, runs inside the worker when one is up, and reaches other devices through cloud sync. (#2737, #4297) - Stable project names.
CLAUDE_MEM_PROJECT_NAME_SOURCE=git-remote(defaultpath) names projects by theorg/reposlug of the gitoriginremote (#2827), and outside git an empty.claude-mem-projectfile (or.claude-mem.json) at the project root gives every subfolder the root's name (#3311). Search covers every key a checkout has used, so memory filed under an older name is still found (#4303). - Case-insensitive project keys. Checkouts whose folder names differ only in case share one memory bucket in context, search and folder
CLAUDE.md, including every Chroma path. (#3536, #4301) - Worktree and submodule memory. The startup sweep that folds merged worktrees into their parent project works again and adopts observations from deleted worktree checkouts. A session inside a git submodule uses a
<superproject>/<path>key and reads the superproject's memory. (#3525, #4291) - Opt-in ACT-R ranking. Setting
CLAUDE_MEM_REINFORCE_ALPHA(default0, off) above 0 lets older observations re-confirmed on later days climb into the SessionStart window; the newest quarter of the window always stays by recency. (#3414) - Opt-in near-duplicate dedup. With
CLAUDE_MEM_DEDUP_ENABLED=true(defaultfalse), an observation whose normalized title matches one in the same project, platform and agent scope is merged into it instead of stored again. Near matches are only listed atGET /api/dedup/candidates, andPOST /api/dedup/scanbackfills. (#3063, #4294) - Import Claude Code auto-memory.
npx claude-mem memory ingest [--source <dir> | --all] [--dry-run]stores Claude Code's auto-memory files (~/.claude/projects/<encoded-cwd>/memory/*.md) as observations with no model call, from the checkout you run it in. It skipsMEMORY.md, symlinked notes and notes over 64 KiB, and dedupes re-runs. (#2829, #4322, #4307) - Keyword matching. Multi-word queries now require every word anywhere instead of one exact phrase, punctuation-only tokens are dropped (#4180), and mixed Latin and CJK queries match term by term (#4148). Searches with only
obs_typeorconceptsreturn rows instead of a 400 (#3259). - SQLite fills gaps in semantic search. A category Chroma returns nothing for (common with CJK queries or a tight date window) is refilled from SQLite FTS5 (#3173, #3285), and a query-filtered
build_corpuswithCLAUDE_MEM_CHROMA_ENABLED=falsefalls back to full-text search (#4285). - Results and ordering. Observation results are grouped under day headers (#3693), date-ordered searches merge keyword matches before cutting to the limit (#4174),
timelinecounts depth correctly when rows share the anchor's timestamp (#4104), and broad project filters on large Chroma collections are applied client-side (#3675). - Folder and file lookups. Folder lookups match files stored project-relative and keep exact file matches Chroma did not rank, so opt-in folder
CLAUDE.mdfiles (CLAUDE_MEM_FOLDER_CLAUDEMD_ENABLED) are no longer empty (#3116). Search routes takeprojectsas a comma-separated list or a repeated key and answer other shapes with 400INVALID_PROJECTS(#4304). - Knowledge corpora.
build_corpuskeeps thedateStart/dateEndyou pass and is no longer limited to 90 days of Chroma matches, andrebuild_corpusrefuses a rebuild that would keep half or fewer of a corpus's observations unless called withforce: true. (#4168) - SessionStart from every harness (opt-in).
CLAUDE_MEM_SESSION_START_INCLUDE_ALL_SOURCES=true(defaultfalse), or Include all sources at session start in the viewer, loads recent observations from every harness for the project, not only the one starting. (#4251) - SessionStart fixes. The last session summary shows again when it shares a timestamp with the newest observation (#4103), the terminal preview shows the observations the model received (#4254), and a resumed session such as
claude --resumeis set back to active (#4084). - New
/handoffskill. It writes a HANDOFF.md with the goal, current state, files in play, failed attempts, next steps and memory pointers, so a fresh session can continue. (#3748)
Capture
- Failed tool calls are observations. Claude Code sends a failed tool call (a non-zero Bash exit, or a call you interrupted) to
PostToolUseFailure, which claude-mem now registers; the stored tool use records the error and whether it was interrupted. (#4339) - Skip shell commands by pattern.
CLAUDE_MEM_SKIP_BASH_PATTERNS(empty by default) is a regular expression tested against each Claude CodeBashor Codexexec_commandcommand, for example^(ls|cat|pwd)\b; a match skips the observation. (#3562) - Skip subagent observations (opt-in).
CLAUDE_MEM_SKIP_SUBAGENT_OBSERVATIONS=trueskips every subagent tool call andCLAUDE_MEM_SKIP_AGENT_TYPESskips listed agent types (for exampleworkflow-subagent,Explore), in the hook before any provider request. Both are off by default. (#2741) - Turn off the tool hooks from the environment.
CLAUDE_MEM_DISABLE_TOOL_HOOKS=1makes the PreToolUse and PostToolUse hooks exit at once, andCLAUDE_MEM_DISABLE_OBSERVATION=1orCLAUDE_MEM_DISABLE_FILE_CONTEXT=1turns off one of them. They are read from the hook's environment, not from~/.claude-mem/settings.json. (#3316) - Record Claude Code advisor calls (opt-in). With
CLAUDE_MEM_CAPTURE_ADVISOR_CALLS=true(defaultfalse), the Stop hook stores eachadvisorcall's advice, model and prompt locally at no token cost, readable atGET /api/advisor-callsand never synced. Worker runtime only. (#3165) - Summaries survive a session that ends mid-tool-call. An empty last assistant message no longer skips the summary: the hook reads the transcript, or names the last tools used. (#3184)
- Less observer noise. The default
codemode tells the observer to record a fact once instead of re-confirming it during reviews, retries and polling (#3352), and a prompt that queues no work no longer starts an observer request (#3467). - Faster hooks. The SessionStart worker start runs async while the context hook stays synchronous (#3401), hooks use a valid
CLAUDE_PLUGIN_ROOTinstead of scanning the plugin cache (#3470), and hook processes no longer read viewer assets at import (#3667).
Viewer and settings
- Sessions view. The viewer has Timeline and Sessions tabs. Each session opens a page you can filter by observation category, and you can delete a whole session unless it is still running or holds memories synced from another device. (#3458)
- Delete memories from the viewer. Observation and summary cards have a delete button with a confirmation, deletes are cloud-sync safe, and other open tabs drop the row live. Browser DELETEs are accepted only from the viewer's own page or an origin in
CLAUDE_MEM_ALLOWED_ORIGINS. (#2925, #4288) - Settings saves. A save is validated only on what it changes (#4320), never writes a value that only echoes an environment variable into
settings.json(#4324), and shows the server's reason when it fails (#3474); a body-lessPOST /api/settingsgets a 400 (#3632). - settings.json handling. The installer moves a corrupt
~/.claude-mem/settings.jsontosettings.json.corrupt-<epoch-ms>instead of wiping it, and the worker and viewer refuse to write over one (#3472). When the file'senvblock holdsCLAUDE_MEM_*keys, they win over stale root copies, which the next save removes (#4286). - Links behind a port-forward.
CLAUDE_MEM_PUBLIC_URL(empty by default) sets the browser-reachable base for viewer links in the welcome hint, SessionStart, the per-prompt banner and health notices, for remote sandboxes and dev containers. (#3323) - Theme colors before the theme loads. The fallback colors match the dark theme, and source badges use theme tokens in both themes. (#4328)
Installer and CLI
- Fresh installs load in Claude Code. The npm package ships
.claude-plugin/marketplace.json, so a clean install no longer ends with "Marketplace thedotmack failed to load: cache-miss". (#3441) - Installs that used to abort. npm 11.16+ no longer aborts with EALLOWSCRIPTS (#3258). Worker liveness comes from the PID file, so slow refusals (WSL2) and a port held by another process no longer stop an install before sign-in (#4119), and a port taken again mid-install warns instead of aborting (#4289).
- tree-sitter CLI is provisioned. The installer runs tree-sitter-cli's install step when the binary is missing, so
smart_searchandsmart_outlinework on installs that suppress lifecycle scripts, anddoctorgains a "tree-sitter CLI" row. (#3254) - Old plugin versions are pruned. Install and update remove superseded plugin cache versions, keeping the newest 2, the running worker's and the one Claude Code has registered;
npx claude-mem prune [--dry-run] [--keep <n>]runs it on demand. (#4106) updatekeeps your provider setup. A non-interactive update keepsopenai-compatiblesetups, and Gemini or OpenRouter keys that live only in a key pool or~/.claude-mem/.env. (#4312)doctorandstatusfind cache installs. The CLI resolves the plugin root the way the worker does and prefers the newest complete copy, so working cache installs are no longer reported missing. (#3535)- Externally managed workers.
CLAUDE_MEM_WORKER_AUTOSTART=false(defaulttrue) makes hooks, the MCP server,startand the installer use a running worker but never launch, stop or recycle one. (#2828, #4289) - Smaller fixes. Marketplace installs record the install marker instead of printing "runtime not yet set up" at every Setup (#3113),
/api/importreports rejected rows instead of aborting the batch (#4051), and CMEM Pro trial copy says "up to 14 days" (#4265).
Server runtime
- SessionStart reads the shared server. With
CLAUDE_MEM_RUNTIME=server, SessionStart renders context from the server's rows in one/v1/contextread sized to the host's hook limit, with short display refs that point toobservation_search, andstartno longer probes or spawns a local worker. (#3227, #4112, #4290, #2867) - Server API.
/v1/contextno longer needs aquery: without one it returns the newest observations (50 by default, at most 200) (#4079). Theobservation_addMCP tool now sendscontent, which/v1/memoriesvalidates; every call had failed with a 400 (#4143). - Generation. The
CLAUDE_MEM_SERVER_GENERATION_CONCURRENCYenvironment variable (unset means 1, clamped at 64) sets parallel jobs per lane (#4078), summaries read the session's first and last 500 events (#4137), provider calls time out after 10 minutes (#4123), and empty replies fail at once instead of being retried (#3368). - Custom generation provider.
CLAUDE_MEM_SERVER_PROVIDER=customwithCLAUDE_MEM_CUSTOM_PROVIDER_MODULE=<absolute path>loads your module'screateProvider(helpers)factory at server start. (#3228)
Reliability: worker and hooks
- A wedged worker is reclaimed, on evidence only. A claude-mem worker that holds its port and PID file but stops answering health is replaced once it is older than
CLAUDE_MEM_WEDGED_WORKER_UPTIME_S(default 300) and its identity checks pass; a foreign process on the port is never touched. (#4129) - Port handling. Hooks prove the port is free before spawning (#3219) and wait until a killed worker's port can be bound (#3416). An unbindable port is reported as a boot failure (#4299), and a worker that dies before binding exits 78 and logs its last boot step (#3558).
- PID files. A
worker.pidwhose process is alive but never healthy is removed once the port is free, Bun is also found throughBUN_INSTALL(#3306), and PID namespaces such asbwrap --unshare-pidno longer delete a healthy worker's PID file (#4158). - Self-healing. When Claude Code's auto-updater leaves the
claudeCLI unspawnable, the worker restarts itself, at most 3 times an hour (#3291). The daemon moves its working directory to the data directory, endingEPERMspawns from a launch folder it cannot re-enter (#3252), and an unwritable process registry degrades to memory with one warning instead of crashing (#4142). - Hook output is flushed. Hooks wait for stdout to finish before exiting, so a large SessionStart context read through a pipe is no longer cut off. (#4331)
- Full-text index bloat. Index triggers fire only when indexed columns change, the unused
user_prompts_ftstable is dropped, and existing bloat is merged away once, in small background steps starting a minute after the worker starts. (#3284) - Buffered work resumes. Work paused by an observer deadline resumes with backoff without waiting for another prompt (#4273), and a summary that arrives during an idle shutdown goes to a new observer (#3421).
- Diagnostics.
/api/healthfillsai.lastInteraction(#3197), stopped workers are recognized under Bun and Node (#3447), malformed input and circular log data no longer overflow the stack (#3264), and object log context prints as JSON (#4157).
Reliability: observer and quota
- Budgets follow the model's context window. The observer resolves its model's window (or
CLAUDE_MEM_OBSERVER_CONTEXT_WINDOW), retires a conversation at half of it using measured tokens, caps each tool field at a tenth, and stubs out old tool payloads on HTTP providers (#3625, #2957, #3151). A context-length refusal recycles the conversation and keeps the batch, and retry loops no longer grow history (#3625, #3479). - Replies that are not answers keep their batch. Prose or empty replies get one retry in a fresh conversation (#3624), Claude CLI transport-error text is retried (#3460), drifted XML tags are corrected instead of copied (#3475), and capitalized tags from local models parse (#4113).
- Field condensation. Screenshots (MCP image blocks and
data:imageURLs) are replaced with a marker before condensation, a field over half the context window is truncated without a call (#4327), and a condense reply cut at the token limit is not stored (#4332). - Claude observer. The empty tool list reaches the Claude CLI as
--tools=(#3615),CLAUDE_CODE_TMPDIRis kept (#4162), the default macOS profile can refresh its token (#4153), a signed-out CLI shows in/api/healthand the SessionStart banner (#4154), and the working directory is created before spawn (#4117). - Quota state per Claude account. Rate-limit readings and cooldowns are tagged with the account that recorded them, so switching with
CLAUDE_MEM_CLAUDE_CONFIG_DIRno longer inherits a pause (#4272, #4296). Queues held by a cooldown resume when it ends (#4110). - Quota windows. The
seven_day_overage_includedwindow is tracked and pauses work only when a request is refused on it (#4132, #4293), the five-hour and seven-day windows refresh from the CLI's live figures (#4226), and/api/healthmarks expired windows and stores reset times in one unit (#4072, #4155, #4263). - Accurate outage banners. A quota outage older than 30 minutes shows as a last-known-state note (#4085), expired cooldowns are not shown as active (#4116), and the banner stays out of the observer's own briefing (#4225).
- No lost or misfiled observations. The stall timer pauses while a reply is stored, so a slow store no longer stores a batch twice (#4077), and stored IDs stay paired with their observations when a batch holds an untitled one (#4294).
Reliability: Chroma, transcripts and cloud sync
- Corrupt collections are rebuilt. Only a confirmed HNSW segment error on 2 batches drops a collection, which is then rebuilt from SQLite; a failed drop is retried and a chroma-mcp hung on a read is restarted (#3203, #4295).
doctorreports chroma-mcp exits, the prewarm breaker and dropped collections (#3393). - Slow writes no longer kill chroma-mcp. A timed-out request fails only that call and leaves the row pending, writes get
CLAUDE_MEM_CHROMA_MUTATION_TIMEOUT_MS(default600000), and NUL bytes are replaced before writes. (#3571) - Chroma versions and settings. chromadb is pinned to 1.5.9 (#3384), and the local store now records its writer epoch, so a future downgrade reports vector search unavailable instead of crashing on a newer store (#3466).
CLAUDE_MEM_CHROMA_EMBEDDING_FUNCTION(defaultdefault) picks the embedding function for new collections; the API-backed ones send memory text to their vendor (#3422). - Backfill. Title-only observations are indexed (#4264), partial failures finish as
rows_pendingand retry only the failed rows (#4279), and shutdown stops a backfill instead of reporting it complete (#4120). - Prewarm and locks. A failing uvx prewarm backs off after 5 failures and stops after 20, with
UV_LINK_MODE=copyon Windows (#4111), and a writer lock left by a reused PID is reaped (#4239). - Transcript turns are kept. Transcript-watched sessions such as Codex rollouts record each user turn, so their observations are no longer lost (#3654). A turn the worker did not record is retried from its own line or zstd frame, and records caught mid-write are neither dropped nor duplicated (#4313, #4192, #4193).
- Transcript watcher. A turn with no known working directory waits for one instead of being filed under
~/.claude-mem(#4319), a vanished session file no longer stops the watcher (#3642), and match rules gainall,any,starts_withandnot_starts_with(#4223). - Cloud sync of large prompts. Prompt text is cut to 200,000 bytes before it is read, which ended
SQLiteError: out of memorycrashes, and a prompt too large for one sync body uploads truncated with a marker (#3537). Prompts dead-lettered for size before this are re-queued once (#4311). - Cloud sync pull and status. One pulled operation that can never apply is set aside in
sync_pull_quarantineinstead of stopping the pull, and/api/sync/statusreportspullQuarantine(#4346). Status probes share one request with a 20-second limit, and background pulls wait out the retry delay after a failure (#4330).
Security and privacy
- Opt-in secret redaction. With
CLAUDE_MEM_REDACT_ENABLED=true(defaultfalse), 11 built-in patterns (AWS, GitHub, OpenAI, Anthropic, Slack, Stripe and Google keys, JWTs, PEM private keys and claude-mem's own keys) are replaced with markers before tool data, prompts and the last assistant message are stored.CLAUDE_MEM_REDACT_DISABLED_BUILTINSandCLAUDE_MEM_REDACT_CUSTOM_PATTERNSadjust the set, and server-runtime event bodies and tool log lines are covered too. (#2616, #4298) - Sign-in sends a usage summary. The installer's cmem.ai sign-in request now also carries
install_state(freshorupdate) and a summary of the last 28 UTC days of local memory: per-day observation counts and discovery-token sums only, with no prompts, observation text, paths or project names. The installer prints the same figures as "Your memory so far". (#4266) - cmem account keys stay on the gateway. A
cm_pro_key is sent only to the cmem.ai gateway, from every key pool and the server runtime; before, one placed in a Gemini key setting was sent to Google (#4309, #4276).GET /api/settingsalso masks key pools stored as JSON arrays (#4309). - settings.json is owner-only. Every writer creates
~/.claude-mem/settings.jsonwith mode 0600, and the cloud-sync skill no longer asks you to paste a sync token into chat. (#3498) - Excluded projects stay excluded. Summaries skip unknown sessions and excluded checkouts, so an excluded OpenCode checkout no longer gets a session and an observer call every turn (#4310), and UserPromptSubmit honors
CLAUDE_MEM_EXCLUDED_PROJECTS(#3311). - Less text leaves the machine. Telegram session wrap-ups give file counts instead of paths (#4145), and recalled titles written into Grok Bot memory are stripped of control characters and fenced as untrusted text (#4146).
- Telemetry. New
worker_start_failedandsupervisor_registry_degradedevents, atop_abort_reasonfield,rate_limit,auth,deadline_exceeded,output_retryanddriftinabort_reason, andchroma_zero_resultsinfallback_reason. Telemetry stays opt-out withnpx claude-mem telemetry disable.
Windows
- Worker starts. Workers start through
Start-Process -WindowStyle Hiddeninstead of Node's detached spawn, so no console window opens (#3529). The 2-minute spawn cooldown now starts only when a worker crashed during boot or could not be launched, not after any failed start (#3408). - Ports and locks. The worker's listening socket is no longer inherited by child processes, a
spawn.lockheld by a dead PID is broken (#3309), and a start-token probe that times out no longer removes the PID-reuse guard (#4165). - Launching tools. PATH lookups run
where.exedirectly (#3321), and an observer executable that cannot be spawned (a missing binary, or a.cmdshim Node refuses) is reported once as a setup error, with native.exefiles preferred (#4122). - Dates. When Bun cannot resolve the system time zone, dates fall back to a fixed UTC or ISO form instead of dropping SessionStart context or failing search. (#4126, #4302)
Full Changelog: v13.28.0...v13.29.0