Skip to content

fix(home): Home reaches environments it has only a peer link to - #82

Merged
eyeveil merged 3 commits into
mainfrom
fix/home-peer-link-routing
Nov 10, 2026
Merged

eyeveil merged 3 commits into
mainfrom
fix/home-peer-link-routing

Conversation

@eyeveil

@eyeveil eyeveil commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

Why

Home on the Mac had a reachable, full-access peer link to a Windows T3, but t3_thread_read with that environment failed with "Environment … is not connected to this desktop", and t3_environment_list left 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 through PeerForwarding.

What changed

  • In 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 through PeerForwarding when 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.
  • Home's t3_environment_list adds 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

  • New McpToolAccess.test.ts cases: 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.
  • An independent review asked to keep Home's changes off the peer path and to skip expired or disabled links; both are in the second commit.
  • McpToolAccess, core, homeRouting, project handlers, PeerForwarding and src/home tests pass, except "thread search links identify the environment that returned them" in core.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.

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.
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Nov 10, 2026
@greptile-apps

greptile-apps Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 2/5

[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.

Findings

  1. P1 Home loses automatic watches ▶
  2. P1 Security Home bypasses its read-only rule ▶
  3. P2 Disabled peers appear connected ▶
Fix 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.

Summary

Adds peer-link fallback for Home tools when the desktop cannot reach the named environment.

  • Home's fleet tools can reach peer-only environments.
  • Home's environment list includes peer-only environments.

Reviews (1) · Last reviewed commit: "fix(home): Home reaches environments it ..." · Reviewed by Greptile

Comment thread apps/server/src/mcp/McpToolAccess.ts Outdated
Comment on lines 444 to 445
if (fleetTool && (target === undefined || !(yield* homeUsesPeerLink(target)))) {
return yield* here({ ...params, environmentId });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 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.

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.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread apps/server/src/mcp/McpToolAccess.ts Outdated
Comment on lines 444 to 445
if (fleetTool && (target === undefined || !(yield* homeUsesPeerLink(target)))) {
return yield* here({ ...params, environmentId });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security 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.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +38 to +41
const peerLinks = yield* Effect.serviceOption(PeerLinks.PeerLinks);
const linked = Option.isNone(peerLinks)
? []
: yield* peerLinks.value.list.pipe(Effect.orElseSucceed(() => []));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
@eyeveil
eyeveil merged commit 3447195 into main Nov 10, 2026
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant