Skip to content

Cross-workspace delegation runs Pi in Supervised when the caller is in Auto #272

Closed

Description

@henrychu04

Summary

A task delegated to a linked workspace inherits the caller's runtime mode without checking which modes the target provider offers. When the caller runs in Auto and the task targets Pi (which offers Supervised, Auto-accept edits and Full access, but not Auto), the thread on the other workspace is stored as auto. RuntimePolicy then runs it as approval-required, so Pi asks before every edit, write and command.

The same delegate_task within one workspace steps down to the closest supported mode (Auto-accept edits). The cross-workspace path skips that step. The behaviour comes from upstream code; the fork carries it unchanged.

Code path

  1. apps/server/src/peer/RemoteDelegation.ts:243: when runtimeMode is omitted or inherit, the mode is left out of the forwarded t3_thread_launch and "left to the other side".
  2. On the target, the hub caller is a linked client. clientModeCeiling (McpInvocationContext.ts) caps it at min(link access, calling agent's mode). t3_thread_launch (mcp/toolkits/project/handlers.ts:193) starts from the project's defaultRuntimeMode (default full-access) and falls back to the ceiling. McpToolAccess.startsThreads and resolveRuntimeMode get no target, so nothing checks the provider's supported modes.
  3. orchestration-v2/RuntimePolicy.ts providerRuntimeMode: a mode outside the provider's supportedRuntimeModes becomes approval-required.
  4. Pi receives T3_PI_RUNTIME_MODE=approval-required (mcpInjection.ts, which also maps auto to approval-required), and its tool_call hook asks for everything except read-only tools.

By contrast, local delegate_task (OrchestratorMcpService.ts:2220) passes the resolved target to resolveRuntimeMode, which steps an inherited unsupported mode down to the most permissive supported one (delegatedTaskModes.ts:66). For an explicitly requested unsupported mode it fails with "would run as approval-required".

A plain t3_thread_launch with a Pi modelSelection from an Auto caller takes the same unchecked path (from code reading; not reproduced separately).

Reproduction (throwaway scratch tests, not committed)

Server chain: the t3_thread_launch handler with a linked client (linked: true, narrowedTo: auto), then RuntimePolicy.layerFromProjectStore with Pi's snapshot modes, then buildPiRpcLaunch. The calling agent is in Auto in every row.

link access B project default delegate_task runtimeMode stored on B provider policy T3_PI_RUNTIME_MODE
full-access full-access (omitted) auto approval-required approval-required
full-access auto (omitted) auto approval-required approval-required
auto full-access (omitted) auto approval-required approval-required
auto auto (omitted) auto approval-required approval-required
full-access / auto auto-accept-edits (omitted) auto-accept-edits auto-accept-edits auto-accept-edits
auto-accept-edits any (omitted) auto-accept-edits auto-accept-edits auto-accept-edits
full-access / auto / auto-accept-edits any auto-accept-edits auto-accept-edits auto-accept-edits auto-accept-edits
approval-required any (omitted) approval-required approval-required approval-required
approval-required any auto-accept-edits — runtime_mode_escalation_denied —

resolveRuntimeMode("auto", undefined, {Pi target}) gives auto-accept-edits (local path). resolveRuntimeMode("auto", undefined) gives auto (remote path).

Pi hook (loadMcpBridge from mcpBridge.testkit.ts), showing which tool calls ask:

T3_PI_RUNTIME_MODE read / grep / ls edit / write bash
approval-required runs asks asks
auto-accept-edits runs runs asks
full-access runs runs runs

Workaround

Have the calling agent pass runtimeMode: "auto-accept-edits" to delegate_task explicitly. The link's access must be at least Auto-accept edits. An explicit mode also skips the target project's default.

Fix direction (upstream)

Resolve the remote launch's mode against the target provider's supported modes, as local delegate_task does. For example, t3_thread_launch could pass the resolved provider's supportedRuntimeModes to resolveRuntimeMode. Per the fork's working practices this stays unfixed here unless upstream fixes it; close this issue with the upstream commit.

Not checked live with a real Pi in two workspaces.

Activity

  1. added
    bugSomething isn't working
    upstreamAlso in upstream, or waiting on an upstream change
    needs-live-checkMerged fix not yet confirmed on the real Coder setup
    on Oct 28, 2026
  2. henrychu04 commented on Oct 28, 2026

    @henrychu04
    OwnerAuthor

    Upstream triage (upstream/main 9826dbb, 2026-10-28)

    Reproduced on a clean upstream checkout with throwaway tests, which were deleted afterwards.

    Linked environments end to end

    Built on RemoteDelegation.test.ts's harness: a laptop and a box served over HTTP, a real peer link at full-access, a real delegate_task from the laptop parent, and the box's ThreadLaunchService mocked to capture the launch. The stored mode then goes through RuntimePolicy.layerFromProjectStore with each driver's provider-level modes (Pi status.ts; Grok, Fx, Muse status.ts / acpSupport.ts).

    parent mode target stored on box provider runs as same-environment delegate_task gives
    auto pi auto approval-required auto-accept-edits
    auto grok auto auto auto
    auto fx auto auto auto
    auto muse auto approval-required approval-required
    auto-accept-edits pi auto-accept-edits auto-accept-edits auto-accept-edits
    auto-accept-edits grok / fx / muse auto-accept-edits approval-required approval-required
    full-access pi / grok / muse full-access full-access full-access
    full-access fx full-access approval-required auto
    auto, explicit runtimeMode: "auto" pi auto (accepted) approval-required refused: "does not offer runtime mode auto, so it would run as approval-required"

    For Pi, buildPiRpcLaunch then sets T3_PI_RUNTIME_MODE=approval-required.

    The linked path differs from same-environment delegation wherever the inherited mode is missing but a broader mode than Supervised is offered: Auto→Pi and Full access→Fx. An explicit unsupported mode is accepted instead of refused.

    t3_thread_launch with a Pi model (handler harness)

    caller stored mode
    linked peer (link full-access, agent narrowed to auto) auto
    external MCP client approved at auto, no link (upstream only) auto

    Both run as approval-required. No peer link is needed to reach it.

    Cause and history

    • fix(server): delegated Muse tasks no longer ask approval for every command pingdotgg/t3code#18065 (a4a1a80, 2026-10-10, "delegated Muse tasks no longer ask approval for every command") fixed exactly this for same-environment delegate_task. resolveRuntimeMode takes the target's supportedRuntimeModes, and docs/orchestration-v2/orchestrator-mcp-server.md states the rule: "When the target lists runtimeModes, an explicit runtimeMode outside that list is refused, and an inherited mode steps down to the broadest mode the target offers."
    • feat(server): delegate_task to a linked environment pingdotgg/t3code#16719 (594f1ce, 2026-10-27, linked-environment delegate_task) came later. It resolves explicit modes against the parent only (resolveRuntimeMode(parent.thread.runtimeMode, input.runtimeMode), no target) and leaves omitted modes to the other side. There, t3_thread_launch → McpToolAccess.startsThreads → resolveRuntimeMode(caller.limits.runtimeMode, requested) also has no target, and so does the project-default step in toolkits/project/handlers.ts. fix(server): delegated Muse tasks no longer ask approval for every command pingdotgg/t3code#18065's rule therefore never applies on the linked path, nor to any t3_thread_launch.
    • Upstream's composer (resolveCompatibleRuntimeMode, bd84b17) shows such a thread as Supervised, so the UI is accurate there. The mode is just narrower than the parent's and than what same-environment delegation would give.

    Fix direction for upstream

    Apply pingdotgg#18065's target check where the launch resolves its mode. t3_thread_launch (startsThreads and the project-default step) could pass the resolved modelSelection's provider supportedRuntimeModes to resolveRuntimeMode. That covers the linked delegation, the forwarded launch and local launches in one place. Optionally, the laptop side could also check an explicit mode against the target's runtimeModes from orchestrator_capabilities with environmentId.

    Not reported upstream yet.

  3. henrychu04 commented on Oct 28, 2026

    @henrychu04
    OwnerAuthor

    Upstream PR: pingdotgg#26682. It applies pingdotgg#18065's target-mode check in t3_thread_launch, which covers linked delegate_task, forwarded launches and local launches. Close this issue with the upstream commit once it lands and is synced.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingneeds-live-checkMerged fix not yet confirmed on the real Coder setupupstreamAlso in upstream, or waiting on an upstream change

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions