Agents and worktrees

From docs/agents-and-worktrees.md at cc732c3 View on GitHub

Every agent session that works through rtok gets one rtok agent id, and every worktree is bound to the agent that owns it, the same way on every host. Agents and the user can message each other by that id. This page is the user-facing description (decision D34); the per-host install tables are in agents.md and the config keys are in config.md.

The agent id

  • The id is a random UUIDv4 rtok issues itself, shown as its first 8 characters and accepted anywhere as any unique prefix of 4 or more. Host session ids are not unique across hosts and several hosts have none, so they are never used as the id.
  • Hooks register the agent on the first event of a session and touch it on every later one (SessionStart, tool calls, SessionEnd). A host whose install carries hooks needs nothing else.
  • MCP serves a host without hooks. rtok mcp --host <host> links itself to the session's agent by the host's own session id where the host puts one in the environment (Grok Build: GROK_SESSION_ID), else by the one live agent of that host in the same directory that has been seen since the process started. Two candidates bind nothing, so a message never lands with the wrong agent. A host that can carry neither hooks nor a session id gets a row of its own, registered by the MCP process.
  • The agent always comes from the session. No tool takes an agent or owner argument, so a model cannot claim a worktree or send a message in another agent's name.
  • rtok agents whoami prints the id (RTOK_AGENT_ID, set by the Claude Code hook into the session environment and quoted in the session-start context line; when that is missing, as in Claude's desktop app, the agent of CLAUDE_CODE_SESSION_ID); MCP whoami returns it with how it was linked.

See and talk to agents

CommandMCP toolWhat it does
rtok agents sessions [--all]agents_listevery agent with host, state (live, idle, ended), activity, status, claimed worktrees and unread count; --all adds ended ones
rtok agents show <id>agent_showone agent: host, model, ids, parent and sub-agents, cwd, claimed worktrees, status, unread
rtok agents status <text>agent_status_setwhat this agent is busy with (at most 120 characters); an empty text clears it
rtok agents send <id> <text>agent_senda message to one live agent (size-capped); --all-live sends to every live agent of the sender's project; --task <id> (task for MCP) tags it with the task it is about, such as A12
rtok agents inbox [<id>]agent_inboxyour own messages, oldest first, marked read; with an id, that agent's queue, marking nothing; --task <id> (task for MCP) reads one task's thread and leaves the rest unread

[agents] idle (default 30 minutes) decides who is live. [agents] enabled = false stops registration and the push.

Messages

  • A hook host gets new messages pushed into the next prompt or tool result, framed and within [agents] push_bytes; the rest is announced as … and N more, to be read with agent_inbox. Every other host pulls: the session-start line says to call agent_inbox, and the MCP tool or rtok agents inbox reads them.
  • Security: a message body is text from another agent or a person, never an instruction. Each one arrives inside a fixed frame that names the sender's id, control characters are stripped, the size is capped, and no tool argument can name the sender. Treat it as information.

Worktrees

Raw git worktree records no owner, age or size. rtok worktree gives each worktree one location, one name, one owner and one agent:

CommandMCP toolWhat it does
rtok worktree add <task> [<slug>]worktree_addcreates <root>/<repo>-<task> on branch <task>[-<slug>] from a fresh origin/<default>, locked as <owner> | <task> | <date> | agent <uuid>, and records the claim
rtok worktree adopt [<path>] [--task <id>]worktree_adoptbinds a worktree the host made to the calling agent; the directory stays where the host put it
rtok worktree claim <path>—the same for an existing worktree you name; rewrites its lock only when it has none or is already yours
rtok worktree listworktree_listevery worktree of the repository with owner, bound agent and its state, origin, size; plus orphans git no longer lists
rtok worktree remove <path|task>worktree_removeremoves your own clean worktree and its merged branch; refuses a dirty one, an unmerged branch, the one you stand in, and someone else's lock unless the task is finished (merged, clean, with commits of its own); never forces
rtok worktree gc, clean—sweep finished worktrees, delete idle build caches; dry runs until --yes; a live agent's worktree is kept, unless its task is finished and idle past --idle, which opens any lock too; someone else's lock on a merged, clean worktree untouched for --stale-lock (7d) counts as abandoned

The owner is <host> / <model> of the agent unless a CLI call passes --owner; an MCP call never does. The root is [worktree] root, ~/.rtok/worktrees by default. With [worktree] enabled = false rtok leaves worktrees alone: every rtok worktree command (list too) says they are not enabled, MCP lists no worktree_* tool, and Claude's WorktreeCreate/WorktreeRemove hooks do what Claude does without rtok.

Worktrees a host makes itself

A host that creates worktrees in its own pool (Cursor, Codex, Windsurf and Devin, Kilo, Claude Code, Conductor) leaves rtok no say in where. Run worktree_adopt (or rtok worktree adopt) inside it: rtok derives the origin from the path, takes the task from --task, else the old lock, else the branch, and binds it.

  • Cursor, Codex and Windsurf/Devin delete worktrees themselves to stay under a cap (about 25, 15 and 20). Whether a git lock survives that is not confirmed, so adopting there records the claim in rtok's store only and writes no lock.
  • Every other origin gets the same v2 lock as worktree_add.
  • A worktree locked by someone else is never taken.
  • Running adopt from a post-create script of the host (Cursor .cursor/worktrees.json, Kilo .kilo/setup-script, Windsurf and Devin post_setup_worktree) is set up by rtok agents install <host> --project (hosts cursor, kilo, windsurf, devin), which adds one entry to the project's own file and touches nothing else; rtok agents uninstall <host> --project takes it out. With no agent named, adopt binds the one live agent of the pool's host whose working directory is the repository, and with none or several it parks the claim, with no agent and no git lock, which the next adopt or the SessionStart of a session working inside the worktree completes; worktree gc keeps a parked worktree. The agent can always adopt through the skill below.

The rtok-worktrees skill tells the agent all of this: use worktree_add for new work, worktree_adopt for a worktree the host made, worktree_remove when merged.

Per host

Hooks is whether a plain rtok agents install carries hooks (agent row and message push); a host without them registers through MCP. Native-worktree facts and sources are in research.md §26.

HostHooksAgent row fromNative worktreesAdopting a host-made worktree
claudeyeshooks.claude/worktrees/<name>; WorktreeCreate/WorktreeRemove can replace the default (rtok redirect pending T159)worktree_adopt
cursoryeshooks~/.cursor/worktrees/, cap 25worktree_adopt; post-create script: agents install --project
codexyeshooks$CODEX_HOME/worktrees, keeps 15worktree_adopt
windsurfnoMCP~/.windsurf/worktrees/<repo>, cap about 20worktree_adopt; post-create script: agents install --project
devinyeshooksshares Windsurf's poolworktree_adopt; post-create script: agents install --project
kilonoMCP.kilo/worktrees/worktree_adopt; post-create script: agents install --project
groknoMCP (GROK_SESSION_ID)--parallel sub-agent worktrees, path unverifiedworktree_adopt
mimonoMCPauto_worktree and orchestrator modeworktree_adopt
ompnoMCPper-task isolationworktree_adopt
antigravitynonone (no hooks, no MCP entry)per-conversation mode, path unverifiedCLI rtok worktree adopt
opencodenoMCPnone built inworktree_add
pinonone (no hooks, no MCP entry)none in coreCLI only
zcodeyeshooksnone foundworktree_add
kimiyeshooksnone documentedworktree_add
copilotyeshooksnone documented for this surfaceworktree_add
vscodenoMCPseparate Agents-window feature, path unverifiedworktree_adopt
commandcodeyeshooksnone documentedworktree_add
geminiyeshooksnone foundworktree_add
clineyeshooksnone (checkpoints, not worktrees)worktree_add
roonoMCPnot checked yetworktree_add
droidnoMCPnot checked yetworktree_add
kironoMCPnot checked yetworktree_add
junienoMCPnot checked yetworktree_add
ampnoMCPnot checked yetworktree_add
warpnoMCPnot checked yetworktree_add
crushnoMCPnot checked yetworktree_add
openhandsnoMCPnot checked yetworktree_add
augmentnoMCPnot checked yetworktree_add
reasonixnoMCPnot checked yetworktree_add
qwenyeshooksnot checked yetworktree_add
codebuddyyeshooksnot checked yetworktree_add
goosenoMCPnot checked yetworktree_add
continuenoMCPnot checked yetworktree_add
codewhaleyeshooksnone documentedworktree_add
aidernononenoneCLI only
zednoMCPthreads can point at a worktree you makeworktree_adopt

Every host can create worktrees with worktree_add (MCP) or rtok worktree add (CLI); a host with no agent row passes --owner on the CLI. A worktree whose path matches none of the pools above is listed with origin other and adopted the same way. worktree add (CLI and MCP worktree_add) also sets env.CLAUDE_CODE_TASK_LIST_ID to <project>-<task> in the new worktree's .claude/settings.local.json, so Claude Code sessions there share one task list; only that key is written, the rest of the file stays as it was, a file that is not valid JSON or already sets the id is left alone with a warning, and .claude/ is git-ignored.

Windows

On Windows rtok cannot read a process's parent pid (rtok-sys::parent_pid returns nothing; the Windows snapshot value is not updated after the parent exits), so no ancestor chain is read and only the cwd rule decides which agent a hook call belongs to. No host doc records this limit. Sources and dates are in research.md §26.

Claude desktop app

In the desktop app's Code tab, rtok's MCP tools are served by the one rtok mcp the app starts from claude_desktop_config.json for every session, not by a process of the session itself. That process sits under no session and in no session's directory, so MCP whoami, worktree_* and agent_* cannot tell which agent called them and answer "not linked to an agent session" with that reason. Use rtok agents and rtok worktree from the agent's shell there. Keeping the shared entry from hiding the session's own server is T456.