Skip to content

A thread started through a below-full-access link stays restricted after the link is re-paired with full access #34761

Closed as not planned

Description

@Aplietexe

What happened

A thread in my WSL environment couldn't start a subagent on my Windows machine. Every tool that touches environment links failed with capability_denied: "This work was started from T3 Code · through a linked environment, so it cannot use this environment's links. A link paired with full access is not limited this way."

I re-paired the link with Full access, reloaded the thread and restarted T3 Code, and kept getting the same error. A new thread I started in the same environment used the link and ran the Windows subagent right away.

Diagnosis

The fence itself is intended (#16695). The problem is that a thread can never leave it, and the error message suggests a fix that only works for new threads.

  • How it got fenced. An agent on the Windows host created the thread with t3_thread_launch through its Windows → WSL link, which was paired with auto access. The WSL server stamped the thread with linkOrigin.access: "auto".
  • The stamp never changes. OrchestrationV2LinkOrigin is "set when the thread is created and never changed", and linkOriginIsFenced is access !== "full-access" (packages/contracts/src/orchestrationV2.ts). callerLinkOrigin checks the stamped origin first (apps/server/src/mcp/linkOrigin.ts). Only thread.create sets it, and forks and delegated children copy it.
  • What it blocks. Listing or linking environments, forwarding any tool with a linked environmentId (including delegate_task, through PeerForwarding.callerLimits), and creating projects.
  • Why re-pairing does nothing. Re-pairing issued a new full-access auth session and left the old auto session unrevoked, and the stamp still points at the old one. Reloading or restarting can't change a stamp stored in the database.
  • The UI misleads. The header says only "From T3 Code · ", and nothing says the thread is restricted. The error's last sentence reads as "re-pair to fix this". The environment's own user was typing in the thread and had no way out.

Possible directions:

  1. At minimum, the error should say that the limit was set when the thread started, that re-pairing only affects new threads, and that a new thread is the way out.
  2. Let the environment's user lift the fence from the thread header, or re-evaluate it once the same peer has been re-paired with full access.

Steps to reproduce

  1. On environment A (here the Windows desktop app's local server), link environment B (here a T3 server in WSL2) with access below Full, for example "Auto". Give B a working full-access link of its own (here B → A).
  2. In a thread on A, ask the agent to call t3_thread_launch with environmentId: <B>.
  3. In the new thread on B, ask the agent to call t3_environment_links, or delegate_task with target.environmentId. It fails with capability_denied.
  4. On A, re-pair B with Full access. Reload the thread and restart the app, then retry step 3. You get the same error.
  5. Start a new thread on B from the app and retry step 3. It works.

Version

0.1.9 (the WSL server where the thread runs, and the Windows desktop app with its local server). main has no change to linkOrigin fencing since v0.1.9.

Environment

Windows 10.0.26300 host (T3 Code Desktop 0.1.9) linked to a T3 server 0.1.9 in WSL2 (Linux 6.18, Node 26.12.1). The agent in the thread was Claude (claude-opus-5-5).

Evidence

# WSL server, statev2.sqlite (read-only): the stuck thread
thread mcp:launch:d99e…  created 2026-11-12T02:01:59Z  createdBy=agent  creationSource=mcp
  linkOrigin = {"sessionId":"f514…","label":"T3 Code · <host>","access":"auto"}

# WSL server, auth_sessions with label "T3 Code · <host>"
f514…  issued 2026-10-31T18:24Z  [orchestration:read, orchestration:operate]                                     revoked_at NULL
ae8c…  issued 2026-11-12T04:05Z  [orchestration:read, orchestration:operate, settings:write, source-control:write]  revoked_at NULL   <- re-pair, full access

# From the stamped thread: t3_environment_links, 6 attempts from 03:46Z to 04:11Z
# (before and after the re-pair at 04:05Z, a thread reload and an app restart)
{"_tag":"OrchestratorMcpFailure","code":"capability_denied","message":"This work was started from T3 Code · <host> through a linked environment, so it cannot use this environment's links. A link paired with full access is not limited this way."}
# t3_environment_link from the same thread:
... so it cannot change projects or environment settings. A link paired with full access is not limited this way.

# From a thread the user started on the WSL server (04:02Z and 04:12Z)
t3_environment_links -> [{"label":"<host>","status":"reachable","access":"full-access"}]
delegate_task with target.environmentId=<Windows> -> Codex child ran on Windows and completed

Related issues

#27004 is also about threads started with t3_thread_launch through a link, but its symptom is sidebar and Lineage visibility, not the fence. The fence came from #16695 (a PR). I found no existing issue about this.

Fix applied or workaround

Nothing was changed on the machine. The user continued in a new thread they started in the WSL environment. Forking the stuck thread doesn't help, because forks copy linkOrigin.

Filed by

Claude Code (claude-opus-5-5) via T3 Code triage. Posted with gh by a user without triage rights, so the via-triage label could not be set.

Activity

  1. juliusmarminge commented on Nov 13, 2026

    @juliusmarminge
    Member

    This is how it is meant to work: immutable state. fork and change permission on the new session

    Closing as not planned.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions