Repository navigation
[Bug]: File links in agent output always resolve against the thread's project, not the repo the file is in #10553
Description
Activity
Triage
Confirmed. Relative file chips in agent markdown are always joined onto the thread project (or its worktree). Nothing checks that the result exists, and nothing tries the environment’s other project roots. Absolute paths already work.
What the code does
ChatViewpassesmarkdownCwd={gitCwd}(the thread’sworkspaceRoot/ worktree) intoChatMarkdown. Both markdown links and auto-linked inline code go throughresolveMarkdownFileLinkTarget→resolvePathLinkTarget, which joins any relative path onto that cwd. The chip tooltip and Copy full path use that already-resolvedtargetPath.The existing click-time workspace-index rescue (
findWorkspaceBasenameMatch/needsWorkspaceBasenameLookup) only runs for slash-free names (categories.ts, notrules/categories.ts), andprojects.searchEntriesis scoped to that cwd. Acdinside Bash is not tracked.Related, not a duplicate
- [Bug]: File chips for files created outside the project root fail to open: "Failed to read workspace file 'docs/X.md' in '<root>'" #8251 / fix(web): resolve slashed file-chip paths through the workspace index #8254: agent cwd is a subdirectory of the same project. fix(web): resolve slashed file-chip paths through the workspace index #8254 still searches only the thread workspace index, so it would not resolve a file that only exists in another registered project.
- feat(mobile): long-press file references for path and open actions #9258 (merged): mobile does render file chips.
resolveFileChipTargetinapps/mobile/src/features/threads/fileChipMenu.tshas the same join-against-workspaceRootbehavior. A fix should cover mobile too.
Suggested fix
Keep chat rendering cheap. At action time (open, copy full path, reveal, tooltip):
- Try the thread project join first.
- If that path does not exist, probe other project roots in the same environment (
useProjects()is already available inChatMarkdown). - One unique hit → use it. Ambiguous / none → keep the current join (or offer a picker).
Do not try to reconstruct Bash
cdin the orchestrator. Prefer a cheap exists/stat overprojects.readFile. Watch the case where the thread project happens to have a file at the same relative path — today’s join would still win and stay wrong.Workaround still holds: ask the agent for absolute paths.
Labels:
bug,via-triage(removeneeds-triage)- addedbugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.via-triageFiled through npx t3 triageFiled through npx t3 triage
on Sep 7, 2026 Claude Code-specific request: please have T3 automatically pick up and display the active Claude working directory in the thread, similar to the
cwd/workspace.current_dirfields Claude Code provides to status lines. The UI should distinguish that current directory from the original project directory.When a reply contains a relative file link or file chip, Open, Copy full path, and Reveal should use and show the directory that actually makes the reference valid. Please do not silently resolve every link against the thread's original project root. If more than one known root contains the same relative path, let the user choose the target.
A displayed session CWD alone may not identify a file inspected through a temporary
cdinside one Bash call. Where T3 has the originating tool's CWD, use that for the link. This is the cross-repository case here. #8251 / #8254 cover the related case within one workspace.
Before submitting
Area
apps/web
Steps to reproduce
/repos/app-aand/repos/app-b.app-aproject.cd ../app-b && cat src/api/rules/categories.ts.`rules/categories.ts:7`or[categories.ts](rules/categories.ts).Expected behavior
The chip points at the file the agent actually read, in
/repos/app-b.Actual behavior
Every relative reference is joined onto the thread's own project root, so the chip resolves to
/repos/app-a/rules/categories.ts. That file does not exist. Clicking opens the wrong path, and "Copy full path" copies it.This happens for both markdown links and auto-linked inline code spans. It is the same for any agent that steps outside the thread's workspace during a turn.
Impact
Minor bug or occasional failure
Version or commit
main @ latest
Environment
macOS, web client (also applies to desktop, which wraps web). Mobile does not render these chips.
Logs or stack traces
Workaround
Ask the agent for absolute paths. Absolute references link correctly.
Notes
resolveMarkdownFileLinkTargetinapps/web/src/markdown-links.tsends withresolvePathLinkTarget(pathWithPosition, cwd), wherecwdis always the thread's project root. Nothing downstream checks whether the resulting path exists, so a relative reference from another checkout silently produces a link into the wrong repo.The prose itself carries no repo, and the agent's real working directory came from a
cdinside a Bash call, which is not tracked. Resolving this properly seems to need an existence check against the environment's other project roots, most likely at click time so chat rendering stays free.