claude_code_vs CLAUDE.md

A set of project instructions for Claude Code, an AI coding assistant, working inside a native Visual Studio 2026 extension. It explains the project's purpose, architecture, collaboration rules, technology choices, and limits.

In plain words
What is it for?
Use it when developing, reviewing, or extending this Visual Studio extension and when explaining its architecture or development process.
Why use it?
It gives future coding work the context needed to stay within the project's design and scope. It helps prevent changes that duplicate Claude Code's existing agent features or violate agreed working rules.

Instructions file

Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

agentmods
npx agentmods add instructions/firish/claude_code_vs/claude-md
Clone the repo
git clone --depth 1 https://github.com/firish/claude_code_vs
Per session 11,196 This file is loaded in full into every session.
When invoked 11,196 The same file — it is already loaded in full.
Security scan A 0 findings. Scan, not verified.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5 $0.11196 $0.11196
Opus 5 $0.05598 $0.05598
Sonnet 5 $0.02239 $0.02239
Haiku 4.5 $0.01120 $0.01120

Measured 2d ago against content hash c1e72b335432, method: parsed. Prices are Anthropic first-party input rates as of 2026-08-30, from the pricing page.

Security

Grade A, and why

claude_code_vs CLAUDE.md scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 2d ago.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

CLAUDE.md · 202 lines

How it starts

The opening of the file, as written. The whole thing — 202 lines — stays where its author put it; the contents beside it link to each section on GitHub.

CLAUDE.md

Operating context for Claude Code when working in this repo. Future work and release plan live in ROADMAP.md.

What this is

A native Visual Studio 2026 extension that launches the real claude CLI and implements Claude Code's IDE-integration protocol (lockfile + localhost WebSocket speaking MCP/JSON-RPC 2.0). The CLI does all agent work; this extension provides the IDE half: a native diff window with accept/reject and automatic selection + diagnostics context. We do not reimplement the agent, and we do not build skills/plugins/hooks - those come from the CLI for free.

If you ever find yourself adding an LLM API call, an agent loop, or a tool the CLI already provides, stop - that's out of scope.

Working agreement (how we collaborate here)

  • Build in chunks, then teach. Run free on a defined chunk of work (a phase or a well-scoped task), then - before moving on - explain everything the user needs to know/learn about what was built. The user is shipping this and learning the domain (VS SDK, the Claude Code IDE protocol) along the way, so keep code and decisions explainable and don't bury rationale.
  • Ask before design decisions with tradeoffs. When a fork has real tradeoffs (not a choice with an obvious default), surface it with a recommendation and let the user decide. Decisions clearly load-bearing in the existing code don't need re-asking.
  • Ask when an instruction is unclear rather than guessing and running.

Architecture (where things live)

  • src/ClaudeCodeVS.Protocol/ - lockfile writer, WS server, MCP/JSON-RPC framing.
  • src/ClaudeCodeVS/Tools/ - one IIdeTool per tool: the 12 IDE-protocol tools (openDiff, openFile, getDiagnostics, …) plus the debugger surface - DebugTools.cs (reads) + DriveTools.cs (gated drive) - plus the semantic surface - SemanticTools.cs (the 8 vs-semantic Roslyn navigation tools, incl. vs_get_selection + vs_decompile) - plus the test surface - TestTools.cs (list/run/rerun-failed/debug/hunt/catch, on vs-debug) - plus the build surface - BuildTools.cs (vs_build + vs_read_output, also on vs-debug).
  • src/ClaudeCodeVS/CodeModel/ - RoslynReader (the semantic-model reader: search/find-references/go-to-definition/find-implementations/call-&-type-hierarchy over the live VisualStudioWorkspace, plus FindTestMethodsAsync = Roslyn test discovery). The static-analysis twin of Debugging/DebuggerReader; backs the vs-semantic MCP server. Roslyn binds in-proc (unlike ClrMD) - VisualStudioWorkspace is the supported extension entry point.
  • src/ClaudeCodeVS/Testing/ - the test-runner: TestRunner (drives VS's Test Explorer engine in-proc via MEF IRequestFactory - list/run/debug/flaky-hunt/catch), HuntState (async background flaky-hunt registry), TestResultCallback (the Reflection.Emit'd internal ITestWindowDataCallback that captures real per-test results). Backs the test tools on the vs-debug server; see the Test-integration section.
  • src/ClaudeCodeVS/Building/ - SolutionBuilder: drives the IDE's own build (async SolutionBuild.Build(false) + BuildState poll, never the UI-freezing Build(true) that TestRunner uses internally) and assembles the report. Backs vs_build; see the Build-integration section.
  • src/ClaudeCodeVS/Diff/ - diff rendering + Accept/Reject InfoBar + write-back + tab registry.
  • src/ClaudeCodeVS/Editor/ - selection service + TextViewListener MEF component + Error List reader + RDT helpers + OutputWindowReader (Output-window pane reads, GUID-addressed for build/debug/general because pane NAMES are localized; backs vs_read_output and the raw-log half of vs_build).
  • src/ClaudeCodeVS/Attachments/ - AttachmentService (SelectionService-pattern static, Attach(server) from BridgeHost): the panel attach tray's engine. Stages pasted screenshots/dropped files (in-workspace = referenced in place; else copied to <ws>\.claude\attachments\ behind a self-ignoring * gitignore, 7-day prune) and pushes each as an at_mentioned notification so the reference lands in the CLI composer. ONE framework for all formats: image/pdf/text read directly, BMP transcoded to PNG, everything else (xlsx/mp4/zip) mentioned with a 🧰 needs-tool label - never hard-rejected. Per-item token estimates ((w×h)/750 images, bytes/4 text). UI = the 📎 card in ClaudeToolWindowControl (drop target, Paste button, chips: click = re-mention, ✕ = remove-and-delete-copy). A directory stages mention-only (no read, copy or estimate - folder @-mentions are first-class in the CLI, which walks the tree), which is what Solution Explorer's Add to Chat (ContextActions.AddSelectionToChatAsync, issue #30) routes selected files AND folders through - the tray buys it chips, re-mention and flush-on-connect for free. References (WasCopied=false: those files/folders, in-place drops, and the editor actions' ranged mentions via MentionFileAsync) dedupe on path+range and re-send the existing chip. Dropped/pasted FILES also dedupe on the original path + its last-write time (FindBySource, checked before any copying), so re-attaching an out-of-workspace file re-mentions its chip instead of staging foo-2.png, foo-3.png - a file edited since staging still comes in fresh, because the staged copy froze the old bytes. Only contentless pastes (clipboard image, composer text) never dedupe: they have no source file, so each one is genuinely new. The tray is workspace-scoped: WorkspaceWatcher clears it whenever the workspace actually changes (solution/folder open or close) - chips carry workspace-relative mention paths and live in that workspace's staging folder, so they must not survive into the next one.
  • src/ClaudeCodeVS/Capture/ - WindowCapture: the Win32/GDI capture core behind the vs_capture_window / vs_capture_screen tools (Tools/CaptureTools.cs, gated by BridgeStatus.AllowScreenCapture - the third safety toggle). PrintWindow(PW_RENDERFULLCONTENT) + blank-frame fallback (foreground → 350ms settle → re-rect → region copy, the path GPU browsers need). One shared eligibility predicate (visible + not DWM-cloaked + titled; min 200×120 filters browsers' taskbar-preview proxy HWNDs) backs BOTH the title matcher and the error's visibleWindows list so they never disagree; minimized matches error "restore first". Captures stage via AttachmentService.StageCapturePng (chip + feed line, Sent=true so never auto-mentioned) and return the PATH - never MCP image blocks (~10-20× token waste, upstream #31208 - bot-closed as stale, NOT fixed). Reference: docs/VISION.md.
  • src/ClaudeCodeVS/Debugging/ - DebuggerReader (EnvDTE reads: break state, stack, locals, threads, object-graph expansion, $exception, processes) + DebuggerDriver (EnvDTE/IVsDebugger drive: continue/step/breakpoints/session, break-on-thrown via EnvDTE90.Debugger3, attach/detach + the await-break engine).
  • src/ClaudeCodeVS/Hooks/ - hook installer (PermissionHookInstaller) + McpInstaller (registers BOTH the vs-debug and vs-semantic MCP servers) + embedded scripts: vs-permission-hook.ps1, vs-usage-hook.ps1, vs-debug-context-hook.ps1, vs-notify-hook.ps1 (Notification hook -> POST /notify -> in-IDE "Claude needs your input" notification), vs-mcp-shim.ps1 (one shim, parameterized by -Route so it backs both servers: /mcp = vs-debug, /mcp-semantic = vs-semantic).
  • src/ClaudeCodeVS/Ui/ - dockable panel (BridgeStatus state, ClaudeToolWindowControl WPF, ReasonDialog) + Notifier (turn-finished / needs-input notifications: ONE main-window InfoBar, superseded by the next, + a bounded taskbar flash when VS is backgrounded; turn-end rides the existing Stop hook's /usage POST via IdeWebSocketServer.StopReceived - no extra hook; gated by the panel's Notify toggle, default ON) + UpdateNotice (the once-per-MARQUEE-release "what's new" InfoBar: normally DISARMED - MarqueeVersion = null, releases ship silently; arming is an editorial act on headline/behavior-changing releases only: set the constant + rewrite MarqueeNoticeText in both resx, disarm again next release; latched per-user in the VS settings store, written only after the bar actually rendered).
  • src/ClaudeCodeVS/Resources/ - UI localization (issue #20): Strings.resx (neutral English) + Strings.zh-Hans.resx (Simplified Chinese, maintained by Claude - the maintainer doesn't read Chinese) + Strings.cs (hand-written nameof-keyed accessors). Culture follows VS's display language (IUIHostLocale, read at package init). See convention #6 and the Localization section - every new user-facing string lands in all three files in the same change.
  • src/ClaudeCodeVS/Terminal/ - VsTerminalLauncher.cs: launches claude inside VS's own native Terminal tool window via Microsoft.VisualStudio.Terminal.ITerminalService (undocumented, no NuGet package - reflection-loaded from the install dir at runtime, same pattern as the TestWindow integration in Testing/TestRunner.cs). Falls back to the external cmd.exe console (BridgeHost.LaunchClaudeAsync) on any failure OR a ~10s stall (raced timeout + linked cancellation - a cold ServiceHub must not leave the Launch button dead), since this surface could change or vanish across a VS update. The cached "Claude Code" terminal profile is deregistered right after launch (RemoveCachedProfile) so the profile dropdown stays clean; the panel's External console button (BridgeStatus.LaunchExternalAction -> LaunchClaudeAsync(forceExternal: true)) skips the native path for users who want a standalone/VS-surviving window. User-facing reference (with notifications + attachments): docs/QOL.md.
  • BridgeHost.cs - wires everything together; owns the /permission handler and CLI launcher.
  • spike/ - Phase 0 standalone console harness (net8.0), kept for protocol regression testing.
  • src/ClaudeCodeVS.ClrMdWorker/ - out-of-process ClrMD worker exe (net48/x64): waitchains/asyncstacks/heapstats/threadpool/roots/heapdiff commands emit JSON; bundled in the .vsix under ClrMdWorker\ and shelled out by Debugging/ClrMdReader.cs (ClrMD can't load in-proc in devenv — Immutable binding conflict). To iterate on a ClrMD read, run the worker exe directly against a target PID (no VS needed).
  • src/ClaudeCodeVS.DataBpComponent/ - the managed data-breakpoint Concord (DkM) debug-engine component (net472): an IDkmCallStackFilter + IDkmDataBreakpointHitNotification registered via .vsdconfig (a DebuggerEngineExtension VSIX asset). Arms DkmPendingDataBreakpoints from the request thread and streams changes over file-IPC; driven by Debugging/DataBreakpointBridge.cs + the vs_set/get/remove_data_breakpoint tools (Tools/DataBpTools.cs).

Read the full file on GitHub · 202 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. 2d ago First seen · 202 lines · 11,196 tokens per session scan A c1e72b335432

Subscribe to this mod's changes

claude_code_vs CLAUDE.md is an instructions file published in the GitHub repository firish/claude_code_vs (79 stars, last pushed 6d ago), licensed MIT. It adds 11,196 tokens to every session, about $0.0560 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.