Skip to content

Read project customizations on the host's own filesystem - #331527

Closed
Ryan Ewen (RyanEwen) wants to merge 2 commits into
microsoft:mainfrom
RyanEwen:fix/project-customizations-remote-namespace
Closed

Read project customizations on the host's own filesystem#331527
Ryan Ewen (RyanEwen) wants to merge 2 commits into
microsoft:mainfrom
RyanEwen:fix/project-customizations-remote-namespace

Conversation

@RyanEwen

Copy link
Copy Markdown
Contributor

Fixes #331526.

In a remote window the agent host reads project-scope customizations off a URI it cannot resolve, so it finds none. The symptom users hit is that a new chat offers no workspace slash commands until a turn has run.

The window hands the session its working directory in the client's namespace. A diagnostic build of the host logged, for a fresh chat in a dev container:

workingDirectory = vscode-remote://dev-container+<hex>/workspace/printstream
userHome         = file:///home/node

The host runs inside that container and its file service only answers for file:, and getSessionCustomizations passes the working directory straight to four disk scans (agents/skills/commands, rules, MCP servers, hooks). Each returns empty rather than raising, so the customizations are absent with nothing in the log.

Fix

A conversion beside the other agent-host URI helpers, applied only to reads the host performs itself:

export function toHostLocalUri(resource: URI): URI {
	if (resource.scheme !== Schemas.vscodeRemote) {
		return resource;
	}
	return URI.file(resource.fsPath);
}

The path is the part both namespaces agree on, which materialize already relies on by handing the SDK workingDirectory.fsPath as its cwd. This applies the same reading to the host's own disk access.

Deliberately narrow:

  • Only vscode-remote:. Stripping the authority off any other scheme would name a local file that is not there rather than the resource meant. A local window compares file: to file: and is untouched.
  • Only host-side reads. workingDirectory and workingDirectories are unchanged for everything else; anything sent back to the client, or compared against client-supplied URIs, keeps the namespace the client uses.

Verification

  • Unit tests for the conversion: the remote rewrite, a file: no-op, a non-remote scheme left alone, and that the client authority never leaks into a host read.
  • Verified live in a dev-container window. Before: 17 suggestions in a fresh chat, none of them the project's six commands. After: 23, with all six present and no turn run.
  • An equivalent command placed in ~/.claude/commands/ was offered before the first turn both before and after the fix, which isolates the failure to project scope rather than to the suggestion pipeline.
  • The file: URI shape this produces is one the client already resolves: a user-scope command, which has always been surfaced as a host-local file: URI, resolves and runs end to end. So project entries now arrive in a shape with a working precedent rather than a new one.

What is not covered

The conversion is unit-tested and the wiring is verified live, but there is no unit test asserting that getSessionCustomizations passes the converted form, because that needs a fully constructed session and the existing tests stub the method rather than exercise it. I would rather say so than imply coverage that is not there.

The Codex customization scan takes working directories the same way and joins onto them, so it looks like the same shape. I have not reproduced it there and have left it out of this change.

AI disclosure: this description and the code it proposes were written with the assistance of AI.

Copilot AI balanced review requested due to automatic review settings August 18, 2026 18:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR ensures the agent host reads project customizations from the correct filesystem when the client window is connected to a remote (e.g., dev container) by translating vscode-remote://... working directory URIs into host-local file: URIs.

Changes:

  • Added toHostLocalUri helper to reinterpret vscode-remote://... URIs as file: URIs for host-side disk reads.
  • Updated ClaudeAgentSession customization discovery/scanning to use host-local working directory URIs.
  • Added unit tests for toHostLocalUri behavior and invariants.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/vs/platform/agentHost/test/common/agentHostFileSystemProvider.test.ts Adds focused tests for toHostLocalUri conversion and non-conversion cases.
src/vs/platform/agentHost/node/claude/claudeAgentSession.ts Uses host-local working directory URIs for customization discovery/scans to fix “silent empty reads” in remote windows.
src/vs/platform/agentHost/common/agentHostUri.ts Introduces toHostLocalUri utility and documents intended behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/vs/platform/agentHost/common/agentHostUri.ts
@vs-code-engineering

Copy link
Copy Markdown
Contributor

📬 CODENOTIFY

The following users are being notified based on files changed in this PR:

TylerLeonhardt

Matched files:

  • src/vs/platform/agentHost/node/claude/claudeAgentSession.ts

A window connected to a remote hands the session its working directory in
the client's namespace, so in a dev container the primary root arrives as
`vscode-remote://dev-container+<hex>/workspace/repo`. The agent host runs
inside that container and its file service only answers for `file:`, so
every project-scope disk scan reads a URI it cannot resolve.

It fails quietly: the scan returns empty rather than erroring, so project
agents, skills, commands, rules, MCP servers and hooks are all simply
absent. User-scope ones keep working because `userHome` is already
host-local, which makes the symptom look like `.claude/commands`
specifically. Slash commands appear to recover after the first turn, but
only because the SDK then supplies its own list; the disk scan never
starts working.

The path is what both namespaces agree on, which materialize already
relies on by handing the SDK `workingDirectory.fsPath` as its cwd. This
applies the same reading to the host's own reads, and only to those:
anything sent back to the client keeps the namespace the client uses.

Scoped to `vscode-remote:`. Stripping the authority off any other scheme
would name a local file that is not there rather than the resource meant.
`URI.file` builds from the path alone, so the conversion silently dropped
`query` and `fragment`. Working directories carry neither, but the helper
is exported and general, and `fromAgentHostUri` returns URIs that do carry
a query, so the loss would have been waiting for the first such caller.

Also trims the comments this change added. The repository allows 1-2 short
sentences of JSDoc and at most one line inline, and these ran to twelve and
fourteen lines. The reasoning belongs in the commit and the pull request,
which is where it now lives.
@RyanEwen

Copy link
Copy Markdown
Contributor Author

Superseded by #333683. That PR now maps the roots inside _watchCustomizations itself rather than at the call site, which covers the project-customization read path this PR addressed along with the other two callers. Closing to keep the set smaller; see #333174 for the grouping.

AI disclosure: this comment and the related code were written with the assistance of AI.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Agent host cannot read project-scope customizations in a remote window: slash commands are missing until the first turn

6 participants