feat(relay-node): fork a session into a new spawned agent (spawn-fork:v1)
Summary
Lets a person fork one of their agents' sessions from the Agent Relay phone app. The phone sends the existing node spawn action with a new fork_from: "<agent>" input. The node starts a new headless agent in the same folder from a copy of the source conversation, using each harness's native fork, so it really continues the session and doesn't just replay a summary. The original agent keeps running.
- Claude:
claude -p ... --session-id <new> --resume <source> --fork-session. The fork runs in the source transcript'scwd. - Codex: app-server
thread/forkinstead ofthread/start. The fork runs in the source thread's directory. Archived or unowned threads are refused. - Capability: nodes advertise
relay:spawn-fork:v1(kindcapacity) withmetadata.harnessesandmetadata.machine. Older nodes would ignorefork_fromand start an empty agent, so clients must check for the capability first. - Who may fork: only the computer's verified owner (
spawn_fork_refusedotherwise). A fork may not name a different folder from its source (spawn_invalid_input). - Other errors:
spawn_fork_not_found(the agent isn't on this node; clients try the next installation on the same machine),spawn_fork_unsupported, andspawn_fork_unavailable(the source lookup timed out after 10 seconds). - First message: the fork is told it is a fork of @source with its own name, followed by the optional task.
Based on main. It was stacked on #2139, which has since merged.
The iOS client is on AgentWorkforce/relay-desktop branch review/cursor-ios-fork-session (relay-desktop takes no pull requests; it lands through its review flow). Its agent-relay-node pin moves only after this merges.
Test Plan
- Tests added/updated:
wire(fork_from parsing, capability advertisement),spawn::fork(owner check, folder rule, not found, unsupported, timeout, first task), Claude arguments for--resume --fork-session, and Codexthread/forkagainst the fake app server -
cargo test --lib -- spawn:: codex:: harness::claude harness::codex: 703 passed after the review fixes.cargo fmt --checkis clean; clippy is clean on the touched files - Core-level tests for the owner check and the 10-second lookup timeout (follow-up)
- Manual:
claude -p --resume <src> --fork-session --session-id <new>produced a new session that remembered the source conversation - iOS UI tests (iPhone 17 Pro, iOS 27 simulator, offline fixture backend): the three placements, the full fork flow, and a computer that cannot fork all pass
Screenshots
Three candidate placements for the fork entry point (iOS). The header button is the current default:
| 1. Header button beside Call | 2. Actions menu (⋯) | 3. Swipe on the agent row |
|---|---|---|
![]() | ![]() | ![]() |
The flow:
| Fork sheet | Forked agent continues | Both agents in the roster | Computer on an older relay |
|---|---|---|---|
![]() | ![]() | ![]() | ![]() |
Video of the whole iOS experience (96 seconds: a computer that can't fork, the full fork flow, then each placement):
The recording uses the app's offline UI-test fixture backend, not a live node.
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.






