Repository navigation
fix(home): Home reaches environments it has only a peer link to - #82
Conversation
Home's thread, project and capability tools went to the desktop fleet route, which knows only the desktop's connections, so an environment reachable only through a peer link failed with "is not connected to this desktop". Those tools now use the peer link when the desktop cannot reach the environment, and t3_environment_list lists peer-linked environments.
[Medium impact] The change extends Home's fleet workflows to environments reached through existing peer links. Fix Home's read-only check and automatic launch watches before merging. FindingsFix with agent prompt### Issue 1
apps/server/src/mcp/McpToolAccess.ts:444-445
When Home launches a thread through a peer-only link, this branch skips the local `t3_thread_launch` handler that saves Home's watch. The peer receives an ordinary linked-client call, so its handler does not save that watch either. The launch succeeds, but Home's saved watches omit the new thread, despite the promise that launched threads are already watched. Preserve the watch when adding the peer route.
### Issue 2
apps/server/src/mcp/McpToolAccess.ts:444-445
Home's peer route skips `readHomeChangeCaller`, which makes Home read-only outside full-access/default mode. For example, Home in approval-required mode can now call `t3_thread_launch` through a full-access peer link and request an approval-required thread. The ordinary `startsThreads` checks accept that mode because it does not exceed Home's limit, so Home can start work when it should be read-only. Apply the Home change check before forwarding write calls.
**How this was verified:** Peer-only Home calls skip `runAsHome`, while the launch checks allow requested modes equal to the caller's mode instead of requiring full-access/default.
### Issue 3
apps/server/src/mcp/toolkits/home/handlers.ts:38-41
`t3_environment_list` now marks reachable peers as connected even when Linked environments is turned off. `PeerLinks.list` probes addresses without checking that setting, but `PeerForwarding.call` refuses every call when it is off. After a user disables the feature with links still saved, Home can choose a peer reported as connected and receive a refusal on every call. Check `PeerLinks.enabled` before advertising peer access.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.SummaryAdds peer-link fallback for Home tools when the desktop cannot reach the named environment.
Reviews (1) · Last reviewed commit: "fix(home): Home reaches environments it ..." · Reviewed by Greptile |
| if (fleetTool && (target === undefined || !(yield* homeUsesPeerLink(target)))) { | ||
| return yield* here({ ...params, environmentId }); |
There was a problem hiding this comment.
When Home launches a thread through a peer-only link, this branch skips the local t3_thread_launch handler that saves Home's watch. The peer receives an ordinary linked-client call, so its handler does not save that watch either. The launch succeeds, but Home's saved watches omit the new thread, despite the promise that launched threads are already watched. Preserve the watch when adding the peer route.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/server/src/mcp/McpToolAccess.ts
Line: 444-445
Comment:
**Home loses automatic watches**
When Home launches a thread through a peer-only link, this branch skips the local `t3_thread_launch` handler that saves Home's watch. The peer receives an ordinary linked-client call, so its handler does not save that watch either. The launch succeeds, but Home's saved watches omit the new thread, despite the promise that launched threads are already watched. Preserve the watch when adding the peer route.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
Note
Written by claude-opus-5-5 on behalf of eyeveil
Addressed in decbc07: only Home's reads (capabilities, project list, thread search, list, read, wait) take the peer path now. t3_thread_launch keeps the fleet route, so its watch is saved as before; on a peer-only environment it fails with the fleet error instead of starting an unwatched thread.
There was a problem hiding this comment.
Thanks — this resolves the concern. t3_thread_launch remains on Home’s fleet route, so it no longer starts through a peer path that skips Home’s watch registration. The documented fleet error for peer-only launches is an intentional tradeoff.
| if (fleetTool && (target === undefined || !(yield* homeUsesPeerLink(target)))) { | ||
| return yield* here({ ...params, environmentId }); |
There was a problem hiding this comment.
Home bypasses its read-only rule
Home's peer route skips readHomeChangeCaller, which makes Home read-only outside full-access/default mode. For example, Home in approval-required mode can now call t3_thread_launch through a full-access peer link and request an approval-required thread. The ordinary startsThreads checks accept that mode because it does not exceed Home's limit, so Home can start work when it should be read-only. Apply the Home change check before forwarding write calls.
How this was verified: Peer-only Home calls skip runAsHome, while the launch checks allow requested modes equal to the caller's mode instead of requiring full-access/default.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/server/src/mcp/McpToolAccess.ts
Line: 444-445
Comment:
**Home bypasses its read-only rule**
Home's peer route skips `readHomeChangeCaller`, which makes Home read-only outside full-access/default mode. For example, Home in approval-required mode can now call `t3_thread_launch` through a full-access peer link and request an approval-required thread. The ordinary `startsThreads` checks accept that mode because it does not exceed Home's limit, so Home can start work when it should be read-only. Apply the Home change check before forwarding write calls.
**How this was verified:** Peer-only Home calls skip `runAsHome`, while the launch checks allow requested modes equal to the caller's mode instead of requiring full-access/default.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
Note
Written by claude-opus-5-5 on behalf of eyeveil
Addressed in decbc07: no change tool takes the peer path for Home any more, so every Home change still goes through runAsHome and readHomeChangeCaller. The test table includes a t3_thread_send that stays on the fleet route with only a peer link.
| const peerLinks = yield* Effect.serviceOption(PeerLinks.PeerLinks); | ||
| const linked = Option.isNone(peerLinks) | ||
| ? [] | ||
| : yield* peerLinks.value.list.pipe(Effect.orElseSucceed(() => [])); |
There was a problem hiding this comment.
Disabled peers appear connected
t3_environment_list now marks reachable peers as connected even when Linked environments is turned off. PeerLinks.list probes addresses without checking that setting, but PeerForwarding.call refuses every call when it is off. After a user disables the feature with links still saved, Home can choose a peer reported as connected and receive a refusal on every call. Check PeerLinks.enabled before advertising peer access.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/server/src/mcp/toolkits/home/handlers.ts
Line: 38-41
Comment:
**Disabled peers appear connected**
`t3_environment_list` now marks reachable peers as connected even when Linked environments is turned off. `PeerLinks.list` probes addresses without checking that setting, but `PeerForwarding.call` refuses every call when it is off. After a user disables the feature with links still saved, Home can choose a peer reported as connected and receive a refusal on every call. Check `PeerLinks.enabled` before advertising peer access.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
Note
Written by claude-opus-5-5 on behalf of eyeveil
Right, fixed in the latest commit: Home's t3_environment_list lists no peer-linked environment and marks no desktop entry connected through a link while PeerLinks.enabled is false. The read routing already required it.
Review follow-up: launches, sends and other changes keep the fleet route, which registers Home's reports and checks its mode. An expired link or linked environments turned off keep the fleet route's error.
…nts are off Also provides the Home services the environment list test needs, and updates the fork's thread search link expectation to the titled link upstream now returns.
Why
Home on the Mac had a reachable, full-access peer link to a Windows T3, but
t3_thread_readwith that environment failed with "Environment … is not connected to this desktop", andt3_environment_listleft it out. Home's thread, project and capability tools always take the desktop fleet route (FleetBroker), which knows only the desktop app's connections, so a peer link was never used for Home. Ordinary threads already reach peer-linked environments throughPeerForwarding.What changed
McpToolAccess.routed, Home's read tools (orchestrator_capabilities,t3_project_list,t3_thread_search,t3_thread_list,t3_thread_read,t3_thread_wait) that name another environment go throughPeerForwardingwhen a live, unexpired peer link exists, linked environments are on, and the desktop cannot reach that environment. The desktop route still wins when it reaches it.t3_environment_listadds peer-linked environments the desktop does not list, and marks a desktop entry connected when its peer link is reachable.Scope
Fork-only Home routing. Home's changes (launch, send, interrupt, organize, update, project writes, pending-request responses) keep the fleet route, because that route registers Home's report loop and enforces Home's full-access rule; on a peer-only environment they still fail with the fleet error. Tools outside Home's fleet list still refuse another environment for Home, as before.
Verification
McpToolAccess.test.tscases: Home reading another environment through only a peer link (was "saw environmentId", now forwarded), an expired link and a send keeping the fleet route, and Home's environment list including a peer-only environment. The read and list cases fail without the change.McpToolAccess,core,homeRouting, project handlers,PeerForwardingandsrc/hometests pass, except "thread search links identify the environment that returned them" incore.test.ts, which fails the same way on fork main.Model and harness: Claude Opus 5.5 (lead, implementation) via Claude Code in T3 Code.