Make the extension's own vscode:// deep link clickable in chat output (open past sessions)
Summary
Make the extension's own deep link — vscode://anthropic.claude-code/open?session=<id> — clickable in chat output, so results that reference a past session can be opened in one click instead of copy-pasting a raw URL into a browser.
Ideally scope this to links the extension itself produces (a host-rendered "session reference" affordance), not arbitrary model-emitted markdown, so it doesn't widen the prompt-injection surface.
Motivation
I have a custom slash command that does "session archaeology" — it searches ~/.claude/projects/**/*.jsonl for past sessions matching a topic and returns a ranked list. It would be great to render each result as a clickable link that opens that session. The deep-link route already works: pasting vscode://anthropic.claude-code/open?session=<id> into a browser correctly hands off to VSCode and opens the right session.
But there's no way to make it clickable from chat output today.
What I found (why no markdown form works)
The chat panel renders assistant markdown with react-markdown using its default urlTransform. In webview/index.js that's:
function exe(e){ let t=e.indexOf(":"),i=e.indexOf("?"),n=e.indexOf("#"),o=e.indexOf("/");
if(t===-1 || (o!==-1&&t>o) || (i!==-1&&t>i) || (n!==-1&&t>n) || nat.test(e.slice(0,t)))
return e;
return "" } // nat = /^(https?|ircs?|mailto|xmpp)$/
Any URL whose scheme isn't http(s)|ircs|mailto|xmpp gets its href blanked. So every form I tried fails — the href is stripped before it can fire:
[open](vscode://anthropic.claude-code/open?session=<id>)<vscode://anthropic.claude-code/open?session=<id>>(autolink)- bare URL
[open](command:vscode.open?<encoded deep link>)
(The deep-link route itself is valid — this is purely the renderer refusing to emit a non-http href.)
This is an extension choice, not a VSCode limitation
VSCode fully supports opening non-http links from a webview:
- intercept the click and
postMessageto the host, which callsvscode.env.openExternal(Uri.parse(...)); or - render trusted markdown (
MarkdownStringwithisTrusted) wherecommand:links are allowed — which the extension already does in its Monaco-based renderer (r.href.startsWith("command:")handling exists in the bundle).
The chat view just keeps react-markdown's default allowlist.
Security note / suggested scoping
I understand blanking non-http schemes in model-generated text is a sensible anti-injection default — arbitrary clickable command:/vscode:// links in LLM output would be a real risk. So rather than "allow custom schemes in chat markdown," the safe version is a first-party, host-controlled affordance:
- allowlist only the extension's own
vscode://anthropic.claude-code/open?session=…deep link, and/or - expose a structured "session reference" the host renders as a link (so it's not trusting raw model markdown at all).
That keeps arbitrary model-emitted links blocked while making the one first-party link clickable.
Workaround today
Render the URL as inline code so it's one-click-select + copy, then paste into a browser:
vscode://anthropic.claude-code/open?session=<id>
Works, but a real clickable link would be much nicer for tools that surface past sessions.
---
🤖 Authored with Claude Code