Upgrade guide
Upgrade to trw-mcp 7.0 and trw-memory 4.0
This release cuts the MCP surface from 51 tools to 15, hardens the memory store, and moves embedding work into the memory daemon. It covers everything since trw-mcp 6.1.0 and trw-memory 3.1.0. Upgrade both packages together.
What you get
Better tool picks
51 MCP tools became 15, with 13 on by default. In our tool-selection eval (30 prompts per client, one run each), the first TRW call was the right one 73% of the time on Claude Code, up from 30%, and 80% on Codex, up from 0%.
A safer memory store
Fixes three data-integrity bugs from earlier trw-memory releases, a recall crash on a default install, and a daemon crash that left clients unable to start a new one.
Faster sessions, lighter server
trw-mcp keeps one session open to the memory daemon, so trw_session_start p95 fell from 718–856 ms to 390–462 ms on one machine. The MCP server no longer loads torch or an embedding model; the daemon does that work.
A tighter network story
Models download only when you run trw-mcp models fetch or the installer, never at runtime. No embedding vector leaves your machine, and your platform key goes only to hosts you trust.
Before you start
- Remove trw-memory’s
local_onlysetting (orMEMORY_LOCAL_ONLY) if you set it. trw-memory 4.0 refuses to start while it is present, in any config source and at any value, so a leftover never silently turns sync back on. Where sharing must stay off, setsync_enabled: falseandlearning_sharing_enabled: falseexplicitly and checkrbac_mode. - Remove
encryption_enabled(orMEMORY_ENCRYPTION_ENABLED) if you set it. Encryption at rest is not available in trw-memory 4.0 and is planned for a later release; 4.0 refuses the setting withEncryptionAtRestUnsupportedError. Protect the store with disk encryption (FileVault, LUKS) and its owner-only file permissions.
Upgrade steps
Do these in order.
Install both packages together
trw-mcp 7.0 needs a trw-memory 4.x daemon, and a 4.x daemon refuses a 3.x client, so upgrade both at once. Drop
[embeddings]only if you run keyword-only recall; the installer adds it by default.terminalpip install -U "trw-mcp==7.0.0" "trw-memory[embeddings]==4.0.0"Stop the running memory daemon
One daemon serves each machine, and an old one keeps serving until it exits. Its pid is in
daemon.jsonin the memory directory ($TRW_USER_DIR/memory, else$XDG_DATA_HOME/trw/memory, else~/.trw/memory) and in anydaemon_version_mismatcherror. Stop it; the next memory call starts a 4.0 daemon.A 4.0 daemon will not start when its memory directory, or a parent of it, is owned by another user (other than root) or is group- or world-writable without the sticky bit. The refusal names the directory and goes to
daemon-start.log. Fix the permissions or pointTRW_USER_DIRat a trusted path.terminalkill "$(python3 -c "import json, pathlib; print(json.load(open(pathlib.Path.home() / '.trw/memory/daemon.json'))['pid'])")"Refresh each project
This rewrites the hooks, skills, agents and instruction files, several of which named tools that no longer exist. Use
--ide allfor every client, and--dry-runto preview.terminaltrw-mcp update-project --ide <id>Fetch the models
trw-memory 4.0 loads the default embedding model at one pinned revision and never downloads at runtime, so a cache filled by an earlier release may not satisfy it.
terminaltrw-mcp models fetchReconnect every MCP client
Each client runs its own
trw-mcpover stdio, and one started before the upgrade keeps running the old code. Run/mcpin Claude Code; restart the session in other clients.Run the doctor
The retrieval row shows what recall is using and how many stored vectors sit outside the active embedding space. If that number is not zero, run
trw-mcp memory reembed --jsonand check thatstatusisok. The newstray_serversrow prints akillline for each oldtrw-mcpserver that no client will use again.terminaltrw-mcp doctorCheck stores written by an earlier trw-memory
If you ran any trw-memory release before 4.0, run the integrity check on each store and look for
memory.db.corrupt.*.bakfiles in the memory directory. See "Check your stores" below.Rebuild the code index
Delete the old
.trw/code-index/chunks.json(it can be several GB, and 7.0 never opens it), then runtrw-mcp code indexwithout--paths. The index rebuilds once after upgrading, and a--pathsupdate of an index built by an older release is refused with that same remedy.trw_codesearch and symbol modes answerindex_missinguntil the build has run.terminaltrw-mcp code indexTurn on dispatch if you use it
If your agents hand work to other coding CLIs, set
dispatch_tools_exposed: truein.trw/config.yaml. It is off by default and is the only switch fortrw_dispatch.
The short version, per client
pip install -U "trw-mcp==7.0.0" "trw-memory[embeddings]==4.0.0"
trw-mcp update-project --ide <id> # or --ide all; add --dry-run to preview
trw-mcp models fetchThe client ids are antigravity-cli, claude-code, codex, copilot, cursor-cli, cursor-ide, grok and opencode. Then stop the old daemon, reconnect every client and run trw-mcp doctor. The installer’s --upgrade upgrades the packages and caches the models, but it never stops the memory daemon, and it runs update-project only when the deployed framework is out of date.
The new tool surface
- Eleven tools are always on:
trw_session_start,trw_init,trw_status,trw_recall,trw_learn,trw_checkpoint,trw_deliver,trw_build_check,trw_review,trw_prd_validateand the newtrw_code. Four sit behind a flag in.trw/config.yaml:trw_sendandtrw_inbox(comms_enabled, on by default),trw_assess(assess_enabled) andtrw_dispatch(dispatch_tools_exposed). - The surface is flat. Per-task packs, the discoverable and operator-only tiers, per-call grants and tools hidden by run phase are gone. Calling a tool whose flag is off answers
tool_not_in_surfacewith anenable_withfield naming the flag. - Removed tool names have no aliases; a call to one is an unknown-tool error. The replacement commands take the old arguments as flags and print one JSON document with
--json. - On Claude Code the always-on tools load up front, so no tool-search round-trip comes before
trw_session_start. LeaveENABLE_TOOL_SEARCHunset for that; an explicitENABLE_TOOL_SEARCH=truedefers them again.
Now a mode of a tool that stays
- Removed tool
trw_code_search- Use instead
trw_code(mode="search", query=...)
- Removed tool
trw_code_symbol- Use instead
trw_code(mode="symbol", query=<name>), exact matches first
- Removed tool
trw_before_edit_hint- Use instead
trw_code(mode="hint", files=<path>)
- Removed tool
trw_before_edit_hint_batch- Use instead
trw_code(mode="hint", files=[...])
- Removed tool
trw_delivery_status- Use instead
trw_status(delivery=<delivery_id>); needs no active run
- Removed tool
trw_submit_feedback- Use instead
trw_status(feedback={category, subject, message})
- Removed tool
trw_profile_explain- Use instead
trw_status(detail="surface"), ortrw-mcp profile explain
- Removed tool
trw_graph_related- Use instead
trw_recall(graph_id=<learning id>)
- Removed tool
trw_heartbeat- Use instead
trw_checkpoint(heartbeat=true)
- Removed tool
trw_pre_compact_checkpoint- Use instead
trw_checkpoint(pre_compact=true)
- Removed tool
trw_peers- Use instead
trw_inbox(action=...): enroll, list, heartbeat, announce, withdraw, discover
- Removed tool
trw_dispatch_status- Use instead
trw_dispatch(action="status", target=<job id>)
- Removed tool
trw_agent_work_evidence- Use instead
trw_dispatch(action="evidence", target=<run path>)
- Removed tool
trw_validate_agent_work_evidence- Use instead
trw_dispatch(action="validate_evidence", target=...)
| Removed tool | Use instead |
|---|---|
trw_code_search | trw_code(mode="search", query=...) |
trw_code_symbol | trw_code(mode="symbol", query=<name>), exact matches first |
trw_before_edit_hint | trw_code(mode="hint", files=<path>) |
trw_before_edit_hint_batch | trw_code(mode="hint", files=[...]) |
trw_delivery_status | trw_status(delivery=<delivery_id>); needs no active run |
trw_submit_feedback | trw_status(feedback={category, subject, message}) |
trw_profile_explain | trw_status(detail="surface"), or trw-mcp profile explain |
trw_graph_related | trw_recall(graph_id=<learning id>) |
trw_heartbeat | trw_checkpoint(heartbeat=true) |
trw_pre_compact_checkpoint | trw_checkpoint(pre_compact=true) |
trw_peers | trw_inbox(action=...): enroll, list, heartbeat, announce, withdraw, discover |
trw_dispatch_status | trw_dispatch(action="status", target=<job id>) |
trw_agent_work_evidence | trw_dispatch(action="evidence", target=<run path>) |
trw_validate_agent_work_evidence | trw_dispatch(action="validate_evidence", target=...) |
Now a trw-mcp command
- Removed tool
trw_delivery_recover- Use instead
trw-mcp delivery recover;--action resumealso needs--new-pid
- Removed tool
trw_probe- Use instead
trw-mcp probe run
- Removed tool
trw_probe_budget_status- Use instead
trw-mcp probe budget
- Removed tool
trw_meta_tune_propose- Use instead
trw-mcp meta-tune propose(Linux only, as before)
- Removed tool
trw_meta_tune_rollback- Use instead
trw-mcp meta-tune rollback
- Removed tool
trw_query_events- Use instead
trw-mcp telemetry events
- Removed tool
trw_surface_classify- Use instead
trw-mcp telemetry classify
- Removed tool
trw_surface_diff- Use instead
trw-mcp telemetry surface-diff
- Removed tool
trw_mcp_security_status- Use instead
trw-mcp telemetry security
- Removed tool
trw_channel_stats- Use instead
trw-mcp telemetry channel-stats
- Removed tool
trw_pipeline_health- Use instead
trw-mcp telemetry pipeline-health, and atrw-mcp doctorrow
- Removed tool
trw_code_index_update- Use instead
trw-mcp code index
- Removed tool
trw_codebase_risk_report- Use instead
trw-mcp code risk
- Removed tool
trw_prd_create- Use instead
trw-mcp prd create(the/trw-prd-readyskill runs it)
- Removed tool
trw_prd_diff- Use instead
trw-mcp prd diff
- Removed tool
trw_adopt_run- Use instead
trw-mcp run adopt
- Removed tool
trw_instructions_sync- Use instead
trw-mcp instructions sync
- Removed tool
trw_claude_md_sync- Use instead
trw-mcp instructions sync(it was an alias)
| Removed tool | Use instead |
|---|---|
trw_delivery_recover | trw-mcp delivery recover; --action resume also needs --new-pid |
trw_probe | trw-mcp probe run |
trw_probe_budget_status | trw-mcp probe budget |
trw_meta_tune_propose | trw-mcp meta-tune propose (Linux only, as before) |
trw_meta_tune_rollback | trw-mcp meta-tune rollback |
trw_query_events | trw-mcp telemetry events |
trw_surface_classify | trw-mcp telemetry classify |
trw_surface_diff | trw-mcp telemetry surface-diff |
trw_mcp_security_status | trw-mcp telemetry security |
trw_channel_stats | trw-mcp telemetry channel-stats |
trw_pipeline_health | trw-mcp telemetry pipeline-health, and a trw-mcp doctor row |
trw_code_index_update | trw-mcp code index |
trw_codebase_risk_report | trw-mcp code risk |
trw_prd_create | trw-mcp prd create (the /trw-prd-ready skill runs it) |
trw_prd_diff | trw-mcp prd diff |
trw_adopt_run | trw-mcp run adopt |
trw_instructions_sync | trw-mcp instructions sync |
trw_claude_md_sync | trw-mcp instructions sync (it was an alias) |
Deleted
- Removed tool
trw_ordering_compare- Note
- Deleted
- Removed tool
trw_cross_repo_ordering- Note
- Deleted
- Removed tool
trw_replay_outcomes- Note
- Deleted, with the
TRW_ALLOW_REPLAYvariable
- Removed tool
trw_request_tool_access- Note
- Deleted with per-call grants
- Removed tool
trw_skill_discovery- Note
- Deleted with the discoverable tier
| Removed tool | Note |
|---|---|
trw_ordering_compare | Deleted |
trw_cross_repo_ordering | Deleted |
trw_replay_outcomes | Deleted, with the TRW_ALLOW_REPLAY variable |
trw_request_tool_access | Deleted with per-call grants |
trw_skill_discovery | Deleted with the discoverable tier |
Retired settings
TRW_OFFLINEis removed and ignored. Runtime model loads never download;platform_contact_enabled: false(orTRW_PLATFORM_CONTACT_ENABLED=false) turns off the update check and the team-sync pull; uploads stay behindplatform_telemetry_enabled, off by default.- trw-memory’s
local_onlyis removed and refused at startup (see "Before you start"). - trw-memory’s
encryption_enabledis refused, and the[encryption]extra is gone. - The
[bm25]extra is gone: keyword ranking is part of the base install. Dropbm25from anypip install "trw-memory[...]"line. - These trw-mcp keys have no effect and print a one-line notice:
phase_exposure_enabled,tool_access_grant_max_ttl_seconds, the sevenskill_*discovery and retirement keys,memory_store_path,max_cluster_size,audit_pattern_promotion_threshold,wal_checkpoint_idle_interval_seconds,pipeline_health_bandit_probe_enabledandpipeline_health_bandit_stale_days. - The profile key
allowed_tools_by_phasefails validation. Delete it. - New keys:
platform_contact_enabled,code_index_boundsanddispatch_fallback_clients.
The daemon version check
- trw-memory 4.0 changes the daemon API: callers send text, never vectors. Both sides now check the major version, so a mismatch fails fast with a clear message instead of a confusing tool error.
- A 4.x daemon refuses a call from a 3.x client (as under trw-mcp 6.1) with
daemon_version_mismatch, its pid and the fix. A 4.x client refuses a daemon of another major before any call, naming both versions and the pid to stop. - A daemon refusal now fails
trw_learninstead of storing the learning unchecked.
The store schema moves to 8
- The first trw-memory 4.0 open of a 3.1 store migrates it from schema 6 to 8 in one transaction: the retired wiki’s link table is dropped (your entries are untouched) and the quarantine review log gains a
namespacecolumn. - Before migrating a store that holds rows, 4.0 writes a snapshot beside it at
backups/memory.db.pre-schema-8.<UTC time>. If the snapshot cannot be written, the migration does not run and the store stays as it was. - The migration is forward-only: a 3.x build then refuses the store with
SchemaDowngradeErrorrather than misread it. To go back to 3.1, stop every process using the store and copy the snapshot over the store file; writes made after the migration are not in it.
Models
trw-mcp models fetchdownloads the daemon’s embedding model and the re-ranker and exits 1 if a download did not land. It needstrw-memory[embeddings]. The installer uses the same fetch.- The default model,
BAAI/bge-small-en-v1.5, is pinned to one Hub revision; the loader, the cache check and the fetch all use it. - Without a cached embedding model, the daemon’s recall and store run keyword-only and the reply names
trw-mcp models fetch. The in-processMemoryClientraisesModelNotCachedError.
Fixed in trw-memory 4.0
Store corruption when two processes share a store
Affected every trw-memory release from at least 0.11.0 through 3.1.0. Permission hardening opened and closed the store file on each backend open, which on macOS and Linux releases every SQLite lock the process holds on it, so a second process could write at the same time. 4.0 sets permissions by name and never opens an existing store for it.
Lost first writes to a new store
Affected trw-memory 2.0.0, 3.0.0 and 3.1.0. Lock contention on a brand-new store was treated as corruption, so the store was moved aside while other connections were still writing to it. 4.0 retries a busy store and never treats contention as corruption.
A passing open error set a healthy store aside
Affected every release from 1.0.0 through 3.1.0. Errors such as running out of file descriptors, a full or read-only disk, or a schema change sent a healthy store to recovery, which moved it aside and started an empty one. 4.0 fails the open and leaves the file alone; only definite corruption triggers recovery.
Recall crash on a default install
Affected 2.0.0, 3.0.0 and 3.1.0: recall could fail with NameError: BM25Okapi. Keyword ranking is now part of the base install.
A crashed daemon stranded every client
On macOS the daemon could abort while two threads encoded at once, and clients kept reading its pid as live. Models now run on CPU on macOS, a zombie daemon reads as not running, and a client reaps the daemon it starts.
Check your stores
# Default location; use $TRW_USER_DIR/memory or $XDG_DATA_HOME/trw/memory if either is set
sqlite3 ~/.trw/memory/memory.db 'pragma integrity_check'
ls -l ~/.trw/memory/memory.db.corrupt.*.bak- Check the user store and any project store (
<project>/.trw/memory/memory.db). Anything butokmeans damage: stop every process using the store, then runtrw-memory restore --from-snapshot latest --db <path>, or--from-coldto rebuild from the YAML copy of each learning. - A
memory.db.corrupt.*.bakleft by trw-memory 1.0.0 through 3.1.0 may be a healthy store that a passing open error set aside, and one whose timestamp matches the store’s first use points to the lost-writes bug. Open it read-only before deleting it (sqlite3 -readonly <file> "select count(*) from memories") and copy back by hand any rows the live store lacks. Only the newest five backups are kept by default.
Bounded reviewer lanes
- A reviewer lane (the default for the code-review and audit roles) gets exactly
trw_recallandtrw_codefrom TRW, enforced by the server. - Its host tools are bounded too: a Codex reviewer no longer inherits your other MCP servers or ChatGPT apps, and a Claude reviewer’s own tools are only Read, Grep and Glob.
- Only Claude and Codex have a reviewer launch, so a reviewer role on another client is refused.
--posture defaultrestores an unbounded child and prints a warning.
Other changes you may notice
- Your platform key goes only over https to
api.trwframework.com, to hosts you list in the user-level~/.trw/config.yamlplatform_trusted_hosts, or to a loopback host. A project’s tracked config can still name another host, but that host gets requests without the key. The update check runs at most once a day per process. - The code index is bounded by the new
code_index_bounds. A crossed bound answersindex_bound_exceeded;missing_indexis nowindex_missing, and a build never enters a nested worktree, clone or submodule. - The stdio server exits when its client dies, even if another process still holds the pipe.
trw-mcp memory migrate --applyrefuses a source store that has SQLite sidecar files beside it (-wal,-shmor-journal), more than one hard link, or a symlinked path component, and refuses the copy if the store changes while it runs. Stop the clients writing that store so SQLite checkpoints it, then rerun. Do not delete the sidecars.- CLI dispatch can fall back to another client, but only one you list (
--fallback-clientsordispatch_fallback_clients). Readclientandfallback_notein the result. trw_assessanswers can carry an optionaladvicefield near a decision boundary.- For SDK users:
trw_memory.bandit,trw_memory.code_indexandtrw_memory.migrationare deleted, and trw-mcp’s in-process embedder and vector-store APIs are gone.
Known issues
- After a bulk write of about 5,000 rows or more, closing a
MemoryClientcan raiseTimeoutErrorwhile background graph updates drain. The store still closes intact, and its WAL is applied on the next open. trw-memory 3.1.0 behaves the same; a fix is planned for 4.1. - SDK only: a
DaemonClient(keep_session=True)whose event loop ends while it holds an idle session never closes that session until the client is garbage-collected or the process exits. Callawait client.retire()before the loop ends. trw-mcp is not affected. - If
trw_learnfails after the daemon accepted a duplicate merge (for example, its local YAML write failed on a full disk), retry thattrw_learnbefore another learning merges into the same one; a different merge in between can undo the first merge’s recurrence count. A fix is planned for 7.1. trw-memory restorechecks once, before it replacesmemory.db, that no daemon is running. Stop every process using the store, not just the daemon, before you restore.trw-mcp doctorand thetrw-mcp memory migratepreview can report a stale row count if a writer starts while they read a store. Re-run to confirm the number.- Automatic recovery of a genuinely corrupt
memory.dbdoes not yet check whether another process still has the store open. Stop the other clients before you reopen a store reported as corrupt.