You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: Threads launched into another project via t3_thread_launch can't be waited on, read, sent to, or interrupted by the launching thread #15125
I searched existing issues and did not find a duplicate.
I included enough detail to reproduce or investigate the problem.
Area
apps/server
Steps to reproduce
Register two projects, A and B.
In a thread in project A, have the agent call t3_thread_launch with projectId set to B (workspaceStrategy: {type: "root"}, any model, a short message). The launch succeeds and returns a threadId.
From the same project-A thread, call t3_thread_wait, t3_thread_read, t3_thread_send, t3_thread_interrupt and t3_thread_configuration with that threadId, and t3_thread_search for its title.
Expected behavior
The launching thread can follow the thread it just created. At minimum it should be able to wait on it, read its result and interrupt it. Ideally it can also send follow-ups.
t3_thread_launch's own description says to "retain threadId and use t3_thread_read/t3_thread_wait to follow preparation". That instruction can't be followed when projectId points to another project.
If cross-project management is out of scope on purpose, an agent can still start runs that it can never observe or stop. The launch tool should at least say so.
Actual behavior
The launch works and the thread runs in project B. Every follow-up tool returns thread_not_found for the caller's project, and search leaves the thread out. As a result, the launching agent cannot read the result, send a follow-up, or interrupt a long or runaway run. The only option is the sidebar.
The same sequence works when the thread is launched into the caller's own project (launch, wait, read, send, wait, read).
This follows up on #6945 (cross-project launch, closed as delivered by #2829). That proposal also suggested an optional projectId on t3_thread_list / t3_thread_read.
macOS, T3 Code (Nightly) desktop. The calling thread used the Claude provider and the launched thread used the Codex provider. Reproduced on two separate launches.
Logs or stack traces
t3_thread_launch {projectId: <B>, workspaceStrategy: {type: "root"}, message: "..."}
-> {"threadId":"mcp:<id>","projectId":"<B>","status":"preparing"}
t3_thread_send / t3_thread_wait / t3_thread_read / t3_thread_interrupt {threadId: "mcp:<id>"}
-> {"_tag":"OrchestratorMcpFailure","code":"thread_not_found","message":"Thread mcp:<id> was not found in project <A>."}
t3_thread_configuration {threadId: "mcp:<id>"}
-> {"_tag":"OrchestratorMcpFailure","code":"thread_not_found","message":"The thread was not found in the calling project."}
t3_thread_search {query: "<title>"}
-> {"matches":[]}
Workaround
Manage the launched thread by hand from the sidebar, or start the conversation from inside project B.
Filed by Claude (Opus 5.5) at the user's request, after reproducing the problem.
Thanks for the clear repro, @ycmjason! This reproduces on current main. It's the follow-up that Discussion #6945 left for later after launch shipped in #2829 (merged), not a duplicate of that discussion.
What happens
t3_thread_launch accepts another project's projectId, and a scratch: true launch also lands in a different project. The new thread runs there, but the follow-up tools only look in the calling thread's project:
t3_thread_read, t3_thread_wait, t3_thread_send, and t3_thread_interrupt look up the target using the caller's projectId. If it isn't there, they return thread_not_found with Thread <id> was not found in project <caller>.
t3_thread_configuration uses the same lookup and reports The thread was not found in the calling project.
t3_thread_search drops matches from other projects, so the result is { matches: [] }.
t3_thread_list never lists other projects.
That project boundary is intentional. Thread management stays inside the calling project, and the descriptions for read, send, interrupt, list, and search all say so. The one cross-project exception is a thread the user attached as context, and that's read-only. An agent can't attach a thread itself to widen its own access.
What's actually wrong
The launch instructions don't match that boundary. The t3_thread_launch description and the injected orchestration instructions tell the agent to keep the returned threadId and follow it with t3_thread_read and t3_thread_wait. They also say to check t3_thread_list before retrying a lost response. Those calls only work when the new thread stays in the caller's project, which is why your same-project sequence works. For an explicit projectId or a scratch launch they fail.
That has two consequences:
If a launch response is lost, checking t3_thread_list won't show the first thread, so the agent can start a second one.
The launching thread can't interrupt a long or runaway run it started.
Possible directions
Make the launch instructions accurate. t3_thread_launch and the orchestration instructions should say that read, wait, list, send, and interrupt only see the calling project, so a thread launched into another project or into scratch can't be followed or stopped from the launching thread.
Keep the project boundary in general, but let the launching thread wait on, read, and interrupt the specific threads it launched. Send, search, and list would stay project-scoped unless that's explicitly opened up, and user-attached reads would stay as they are.
A maintainer will decide on the direction. Until then, your workaround is the right one: manage the thread from the sidebar, or start the conversation inside the target project.
Thanks for the quick triage! I'd vote for direction 2. Starting a run you can't follow or stop is the bigger problem, and fixing the docs alone doesn't solve it.
Some context on why cross-project management matters to me: some of my projects are tightly coupled, so work in one often needs a follow-up in another. I'd also like one "No project" thread to act as a hub that launches and drives work across all my projects. Direction 2 covers most of that. If fuller cross-project access (send/list, opt-in or permission-gated) is worth considering, I'm happy to open an Ideas discussion for it rather than widen this issue.
Hit the same thing today on 0.0.46-nightly.20261003.2623: an orchestrator thread in project A launched a build thread into project B with workspaceStrategy: worktree; the launch succeeded, then t3_thread_wait and t3_thread_read both returned thread_not_found … in project A. The first launched run also failed during provider startup, and the launching thread had no way to see that.
Launcher-scoped access would be enough for this case: let a thread read / wait on exactly the threads it launched, without widening access to the rest of the other project. The user-attached-context exception works for reads, but it needs the user in the loop for every launched thread.
Adding a use case for direction 2, with one extension: t3_thread_send to launched threads.
I run an orchestrator thread that launches one worker thread per ticket (each in its own worktree via t3_thread_launch + workspaceStrategy) to build a stacked PR chain. After the bottom PR merges, the orchestrator sends each worker an exact rebase command, bottom-to-top, waiting for each to confirm before messaging the next. It also relays operator requests to the workers that own the affected branches.
Read/wait/interrupt let it observe workers, but restacking and relaying need t3_thread_send. Without it, the orchestrator has to live in the same project as its workers, which rules out running it from a hub thread. Scoping send to threads the caller launched (same rule as read/wait/interrupt) would keep the project boundary for everything else.
Hit this today with t3_thread_send, on Windows desktop 0.0.46-nightly.20261003.2632. Adding it because #15550 covers read, wait and interrupt but leaves send out on purpose.
What happened
A thread in project A launched a top-level thread into project B with t3_thread_launch and projectId: 43caff20-a17a-488e-9014-0a120eb4313e. The launch returned threadId: mcp:687c5a78-1fe9-4440-9c75-b8236ebe5ec0. A few minutes later the user approved a follow-up instruction, and the launching thread tried to relay it:
t3_thread_send {threadId: "mcp:687c5a78-1fe9-4440-9c75-b8236ebe5ec0", message: "..."}
-> {"_tag":"OrchestratorMcpFailure","code":"thread_not_found","message":"Thread mcp:687c5a78-1fe9-4440-9c75-b8236ebe5ec0 was not found in project a1221c99-acfd-46b5-bfca-481fc98bc223."}
The only way through was asking the user to paste the message into the other thread by hand.
If send stays project-scoped on purpose, say so in the t3_thread_launch result for a cross-project launch. Then the agent knows the thread is fire-and-forget before it tells the user it will follow up.
Fixed by #15219, which just landed on main. T3 MCP thread tools now resolve a threadId anywhere in the environment instead of only the calling project, so a thread launched into another project can be read, waited on, sent to, interrupted, and configured by the launching thread (still capped by the caller's own runtime and interaction modes). t3_thread_search keeps defaulting to the caller's project but now takes an explicit projectId. Closing; please reopen if it still reproduces on a build that includes #15219.
Activity
juliusmarminge commentedon Oct 3, 2026
Note
Grok responding on behalf of Julius.
Triage
Thanks for the clear repro, @ycmjason! This reproduces on current
main. It's the follow-up that Discussion #6945 left for later after launch shipped in #2829 (merged), not a duplicate of that discussion.What happens
t3_thread_launchaccepts another project'sprojectId, and ascratch: truelaunch also lands in a different project. The new thread runs there, but the follow-up tools only look in the calling thread's project:t3_thread_read,t3_thread_wait,t3_thread_send, andt3_thread_interruptlook up the target using the caller'sprojectId. If it isn't there, they returnthread_not_foundwithThread <id> was not found in project <caller>.t3_thread_configurationuses the same lookup and reportsThe thread was not found in the calling project.t3_thread_searchdrops matches from other projects, so the result is{ matches: [] }.t3_thread_listnever lists other projects.That project boundary is intentional. Thread management stays inside the calling project, and the descriptions for read, send, interrupt, list, and search all say so. The one cross-project exception is a thread the user attached as context, and that's read-only. An agent can't attach a thread itself to widen its own access.
What's actually wrong
The launch instructions don't match that boundary. The
t3_thread_launchdescription and the injected orchestration instructions tell the agent to keep the returnedthreadIdand follow it witht3_thread_readandt3_thread_wait. They also say to checkt3_thread_listbefore retrying a lost response. Those calls only work when the new thread stays in the caller's project, which is why your same-project sequence works. For an explicitprojectIdor a scratch launch they fail.That has two consequences:
t3_thread_listwon't show the first thread, so the agent can start a second one.Possible directions
t3_thread_launchand the orchestration instructions should say that read, wait, list, send, and interrupt only see the calling project, so a thread launched into another project or into scratch can't be followed or stopped from the launching thread.A maintainer will decide on the direction. Until then, your workaround is the right one: manage the thread from the sidebar, or start the conversation inside the target project.
ycmjason commentedon Oct 3, 2026
Thanks for the quick triage! I'd vote for direction 2. Starting a run you can't follow or stop is the bigger problem, and fixing the docs alone doesn't solve it.
Some context on why cross-project management matters to me: some of my projects are tightly coupled, so work in one often needs a follow-up in another. I'd also like one "No project" thread to act as a hub that launches and drives work across all my projects. Direction 2 covers most of that. If fuller cross-project access (send/list, opt-in or permission-gated) is worth considering, I'm happy to open an Ideas discussion for it rather than widen this issue.
kkolodziej7 commentedon Oct 3, 2026
Hit the same thing today on
0.0.46-nightly.20261003.2623: an orchestrator thread in project A launched a build thread into project B withworkspaceStrategy: worktree; the launch succeeded, thent3_thread_waitandt3_thread_readboth returnedthread_not_found … in project A. The first launched run also failed during provider startup, and the launching thread had no way to see that.Launcher-scoped access would be enough for this case: let a thread
read/waiton exactly the threads it launched, without widening access to the rest of the other project. The user-attached-context exception works for reads, but it needs the user in the loop for every launched thread.cameronmolen commentedon Oct 4, 2026
Adding a use case for direction 2, with one extension:
t3_thread_sendto launched threads.I run an orchestrator thread that launches one worker thread per ticket (each in its own worktree via
t3_thread_launch+workspaceStrategy) to build a stacked PR chain. After the bottom PR merges, the orchestrator sends each worker an exact rebase command, bottom-to-top, waiting for each to confirm before messaging the next. It also relays operator requests to the workers that own the affected branches.Read/wait/interrupt let it observe workers, but restacking and relaying need
t3_thread_send. Without it, the orchestrator has to live in the same project as its workers, which rules out running it from a hub thread. Scoping send to threads the caller launched (same rule as read/wait/interrupt) would keep the project boundary for everything else.AngeloTadeucci commentedon Oct 5, 2026
Hit this today with
t3_thread_send, on Windows desktop0.0.46-nightly.20261003.2632. Adding it because #15550 covers read, wait and interrupt but leaves send out on purpose.What happened
A thread in project A launched a top-level thread into project B with
t3_thread_launchandprojectId: 43caff20-a17a-488e-9014-0a120eb4313e. The launch returnedthreadId: mcp:687c5a78-1fe9-4440-9c75-b8236ebe5ec0. A few minutes later the user approved a follow-up instruction, and the launching thread tried to relay it:The only way through was asking the user to paste the message into the other thread by hand.
Ask
t3_thread_sendto threads the caller launched, same rule as read, wait and interrupt in fix(server): launching threads can follow threads they launch into another project #15550.t3_thread_launchresult for a cross-project launch. Then the agent knows the thread is fire-and-forget before it tells the user it will follow up.juliusmarminge commentedon Oct 5, 2026
Note
Grok responding on behalf of Julius.
Fixed by #15219, which just landed on main. T3 MCP thread tools now resolve a
threadIdanywhere in the environment instead of only the calling project, so a thread launched into another project can be read, waited on, sent to, interrupted, and configured by the launching thread (still capped by the caller's own runtime and interaction modes).t3_thread_searchkeeps defaulting to the caller's project but now takes an explicitprojectId. Closing; please reopen if it still reproduces on a build that includes #15219.