Migration guide · claude-mpm → trusty-mpm
Coming from claude-mpm
trusty-mpm is a Rust meta-harness for Claude Code sessions, driven by one binary called tm. If you already run a PM-style multi-agent setup, the way
you start a session barely changes. What changes is everything underneath it: a supervising
daemon instead of a per-session process, tmux-hosted sessions you can walk away from, and
agents deployed where they cannot leak into your other tools.
- Binary
- tm, trusty-mpm
- Install
- tctl install trusty-mpm
- Daemons
- mpm, memory, search
- Platforms
- macOS 12+, Linux
Read this first
trusty-mpm is not a version of claude-mpm
They are unrelated codebases. trusty-mpm is not a fork, a port, or a rewrite of claude-mpm — there is no shared code, the languages differ (Rust and Python), the maintainers differ, and they ship through different channels (crates.io and Homebrew, versus PyPI). What they share is an idea: a project-manager session that delegates work to specialised agents.
The similar names cause real confusion, including for Claude Code sessions asked what they are running under. trusty-mpm keeps a canonical answer in its own repository — WHAT-IS-TRUSTY-MPM.md — and that document, not a shell probe, is the thing to quote.
What carries over
The shape of the work is the same. A PM session orchestrates and delegates; specialised
agents do the implementing; skills are reusable instruction packs; an output style decides
how the PM writes back to you. If those four words already mean something to you, you know
how to drive tm.
That parity is deliberate rather than incidental. tm launch runs the full deployment sequence — instructions, agents, skills, MCP config — into the project
and then starts or attaches the session in your current terminal, which is the same single-command
experience you already have. The source comment on that subcommand says it plainly: it behaves
like running claude-mpm.
| Concept | Where it lives under tm |
|---|---|
| PM delegation model | Unchanged. The PM orchestrates and delegates; it does not write code itself. |
| Agent roster | Composed and deployed by tm install and by each session launch. |
| Skills | Deployed alongside the agents, plus a project tier under the project's own .claude/skills. |
| Output styles | Three bundled ids — trusty-mpm, trusty-mpm-teacher, trusty-mpm-research. Selected with /config or the outputStyle settings key. |
Install
Two lines. The bootstrap puts tctl — the install control plane —
on your PATH; tctl install trusty-mpm then resolves what tm needs at
runtime and brings those daemons up too. No Rust toolchain is required on a supported platform.
shell
curl -sSf https://raw.githubusercontent.com/bobmatnyc/trusty-tools/main/install.sh | sh tctl install trusty-mpm tm --version
Homebrew and cargo install from a checkout both work; the other install paths are on the home page. macOS 12 or later and Linux are supported. Windows is not.
The bootstrap script verifies every downloaded tarball against its published SHA-256 checksum. The script itself is unsigned — read it before piping it to a shell if you need higher assurance.
A supervising daemon, not a process per session
claude-mpm runs inside the session it manages: start it, and its lifetime is that session's lifetime. trusty-mpm inverts that. A long-lived daemon holds the project registry and the session roster, and sessions are things it configures, launches, and supervises. Close a terminal and the daemon still knows what is running; restart the daemon and the roster survives, because it is on disk rather than in a process.
Two more daemons come with it. Together they are what a session reads from and writes to, and each one is also an MCP server, so a session reaches them through tool calls rather than by shelling out.
| Daemon | Transport | What it holds |
|---|---|---|
trusty-mpm | 127.0.0.1:7880 | Registered projects, the session roster, and the relayed hook feed. A separate supervisor process watches sessions and publishes its fleet snapshot to a file the daemon reads. |
trusty-memory | Unix socket | Memory palaces — long-term recall organised per project, over an HNSW vector index, a redb store, and a knowledge graph. |
trusty-search | 127.0.0.1:7878 | Named code indexes, one per project, kept fresh by a file watcher. One install per machine. |
Every one of those is local-only. trusty-mpm and trusty-search bind loopback HTTP and additionally reject requests whose origin is not the machine itself; trusty-memory's daemon has no network listener at all — its transport is a Unix domain socket, reachable only to processes on the same host. Either way, a page you happen to have open cannot reach them.
memory and search
Registered as LaunchAgents and controlled through tctl start / stop / restart, which drive launchctl underneath.
They come back after a reboot without you doing anything.
the tm daemon
Not launchd-managed. It ships its own tm start / stop / restart, and tctl shells out to
those. Worth knowing before you go looking for a plist that does not exist.
Addresses are resolved from each daemon's discovery file rather than assumed, so a daemon that rebinds to a different port is still found. When one is unreachable the caller gets an error, not a silent timeout.
Sessions live in tmux
A tm session is a tmux session. That is not a convenience wrapper you can opt out of — it is how the daemon can keep a session alive while no terminal is attached to it, and how several sessions run at once without one window per session on your screen.
Names are derived rather than random. A session gets tm-<project>-NN — an explicit hint if you gave one,
otherwise the repository name, otherwise the directory's own name — with a per-project
serial so two sessions on the same project stay distinguishable. When a session does get its
own git worktree, the worktree is named after the session, so a path like .worktrees/tm-trusty-tools-01/ tells you which session owns it without
consulting anything.
| Command | What it does |
|---|---|
tm launch | Deploys instructions, agents, skills and MCP config, then starts or attaches the session here. |
tm connect | Starts or attaches the tmux-hosted session and nothing else — no deployment step. |
tm ls | On a terminal, an interactive picker over the live fleet. Piped or with --json, a plain list. |
tm attach <target> | Finds a session by id, name prefix, or project path and opens the dashboard focused on it. |
tm tui | A terminal dashboard across every live session. |
Sessions also pause and resume — tm sessions pause and tm sessions resume — and finish with tm sessions decommission, which removes the session's worktree
and branch together rather than leaving either behind.
Agents deploy per project, not into your global config
This is the difference most likely to surprise you, and it comes from a real incident. A
shared global ~/.claude/agents is a single namespace every
Claude Code tool writes into, and in July 2026 one tool's agents leaked into another tool's
sessions. The fix was a rule: trusty-mpm never depends on the user's real ~/.claude, and never writes your live checkout.
The mechanism is one environment variable. tm launches Claude Code with CLAUDE_CONFIG_DIR pointed at a directory tm owns, so every ~/.claude path Claude Code would otherwise read resolves inside
that directory instead. Your real ~/.claude — and whatever hooks, MCP servers, and agents another
tool put there — is excluded outright rather than merged on top. Project-scoped content
lands in the checkout's own .claude/ inside a workspace tm controls.
| Surface | claude-mpm | trusty-mpm |
|---|---|---|
| Agents and skills | The real ~/.claude, shared | A tm-owned config dir, plus the project's own .claude/ |
| Hooks and MCP servers | The real ~/.claude, shared | The same tm-owned dir; the real global is not merged |
| Per-session state | — | The project's .trusty-mpm/, holding the instructions the session
actually received |
A side effect worth knowing
Because the real global is excluded, a customisation you added to ~/.claude for claude-mpm does not follow you into a tm session.
That is the point of the isolation, not a bug in it — but it does mean a hand-written agent
or hook you rely on has to be reinstated on tm's side rather than inherited.
Memory and search per project
Memory is a palace: a named store scoped to a project rather than to a conversation, holding prose an assistant wrote and can recall later, alongside a knowledge graph of structured triples. A session reaches it through MCP tool calls at an address resolved from the daemon's own discovery file — never a hardcoded port, which is what used to make this silently fail when the daemon rebound.
Search is scoped the same way, and more tightly than you might expect. When a session is
provisioned, its project gets a search index derived from the project's path, and that index
id is pinned into the session's own .mcp.json. Every search the
session runs is therefore already scoped — there is no ambiguity for the daemon to guess at,
and a query cannot return results from the last project you worked on. When the session is
decommissioned the index is marked for collection, so indexes do not accumulate.
Migrating your kuzu-memory data
If the memory server you were running is kuzu-memory,
trusty-memory migrates it for you rather than leaving you to re-enter anything. trusty-memory migrate takes two targets, and they are independent:
one rewrites configuration, the other moves data. Most people want both, in that order.
kuzu-memory — the configuration
Scans every .claude/settings.json and settings.local.json under your home directory, drops any kuzu-memory or kuzu_memory entry from the mcpServers block, and inserts a canonical trusty-memory one in its place. Unrelated keys survive, each
write is atomic with a .bak alongside it, and a file already
carrying a trusty-memory entry is left byte-for-byte alone — so running
it twice is safe.
shell — look first, then write
trusty-memory migrate kuzu-memory --dry-run trusty-memory migrate kuzu-memory
kuzu-data — the memories themselves
Reads a kuzu-memory store.redb and imports it into a palace:
every entity becomes a drawer, every relation becomes a knowledge-graph triple. There is no
default source path — --from and --palace are both required, and the command errors naming the missing
one rather than guessing. The palace is created if it does not exist yet. Re-running it changes
nothing: drawer ids come from a stable hash of the entity id and the palace name, and an existing
triple is skipped rather than duplicated.
shell
trusty-memory migrate kuzu-data \ --from ~/.open-mpm/memory/store.redb \ --palace your-project --dry-run
--dry-run prints the schema it found and the plan without
writing. --limit <N> caps how many entities are imported,
which is the way to try it on a slice before committing to the whole store. Drop --dry-run to run it for real.
One class of triple does not come across
Four predicates — is_alias_for, has_convention, is_fact, and is_shorthand_for — put a fact on the surface injected into
every turn of every session, and the importer refuses them outright. A bulk import of a
legacy file is not somebody deciding a standing rule should be in front of every session,
so a relation whose type collides with one of the four is logged and skipped while the
rest of the import continues. Ordinary relation types — relates_to, mentions, derived_from, part_of, alias_of — are unaffected. If one of the four really was a
standing rule, re-assert it with kg_assert, which is the
deliberate path and carries the real gate.
Where the work happens
By default a session runs on your project's main checkout — several sessions sharing one checkout is the normal arrangement rather than a hazard. What keeps that safe is a write boundary the harness enforces rather than asks for: a session standing in a main checkout may write documents and configuration there, and an agent it dispatches that needs to change source is granted its own git worktree instead.
tm launch --worktree opts the whole session into its own worktree
when you want the live checkout left completely alone.
The migration, step by step
Nothing here uninstalls claude-mpm. The two can coexist — they read different configuration directories, so neither sees the other's agents — and you can migrate one project at a time.
-
Install trusty-mpm.
The two lines above.
tctlbrings up the memory and search daemons as part of the same run. -
Deploy the framework.
tm installcomposes and writes the agent roster, the skills, the hook registrations, and the output styles into the tm-owned config directory. This is the step that makes a session find a full roster rather than a partial one. -
Bring your kuzu-memory data across — only if you ran it.
trusty-memory migrate kuzu-memoryrepoints the MCP config, thentrusty-memory migrate kuzu-data --from <store.redb> --palace <name>imports the memories. Both take--dry-run, and both are safe to re-run. The full section covers what each one touches and the one class of triple it declines to import. -
Register the project.
From the project directory,
tm project initregisters it with the daemon. Registration rather than inference is what makes the same directory resolve to the same project across sessions and across restarts. -
Clear a stale output style.
If a project or global
settings.jsonstill carries anoutputStyleleft over from claude-mpm, the session will not be running under trusty-mpm's instructions at all.tm doctor's output-style check reports exactly this, and a freshtm launchrewrites the setting correctly. -
Verify before you start work.
tm doctorruns the full diagnostic and needs a reachable daemon.tm validateruns the same deployment diff against the filesystem with no daemon at all and exits non-zero when something is missing, which makes it the one to put in a script.tm healthis the one-line answer. -
Start a session.
tm launchin the project directory. From there it should feel familiar — andtm lswill find it again after you close the terminal.
shell — the whole thing
tm install trusty-memory migrate kuzu-memory # only if you ran kuzu-memory cd ~/your-project tm project init tm doctor tm launch
Everything tm can do
The daemon, the dashboard, the hook relay, and remote control from Telegram or Slack.