Ordered procedures for the recurring tasks in this repo. Each entry is how to do it, the gotcha that bites, and how to verify you got it right.
Where things live:
| Doc | Answers |
|---|---|
CLAUDE.md |
Always-loaded rules, project map, conventions |
ARCHITECTURE.md |
Per-file non-obvious behavior — why the code is like that |
SKILLS.md (this file) |
Repeatable procedures — how to perform a task |
AGENTS.md |
Condensed build/style brief for non-Claude agents |
| I need to… | Skill |
|---|---|
| Finish a code-changing session | Ship a release |
| Build and run the fast checks | Build & test |
| See a change running in real VS | Debug in the Exp hive |
| Push to the marketplace | Publish |
| Wire up another AI CLI | Add a new AI provider |
| Add a persisted option | Add a new setting |
| Add a XAML control or partial class | Add a new UI file |
| Send text to the agent / touch provider UI / focus the terminal | Pre-flight gates |
| Know which doc to update | Keep docs in sync |
Mandatory for every session that modifies code. Bump the MAJOR by one, minor always .0
(176.0 → 177.0). Do not resume 10.x-style minor bumps.
Properties/AssemblyInfo.cs—AssemblyVersionandAssemblyFileVersionto177.0.0.0(both, four parts).source.extension.vsixmanifest—Version="177.0"in the<Identity>tag (two parts).README.md— add### Version 177.0at the top of## Version History.
Verify: ./test.cmd. VersionConsistencyTests makes this rule executable — it asserts
AssemblyVersion == AssemblyFileVersion, that the short form matches the manifest and the
newest README heading, and that the minor is .0. A missed file fails the suite, and
publish.cmd runs it as a gate.
Release-note style (README only — the one section where prose discipline matters):
- Short and business-focused. One sentence per bullet, two max.
- Describe the user-visible feature or fix, not the implementation.
- Avoid: code/file/class/method names, internal selectors, paths, constants, line numbers,
JS snippets, framework jargon (
CoreWebView2,INPUT_RECORD,NavigationCompleted), step-by-step "how it works", PR-style root-cause analysis. - Keep: what the user gets ("auto-confirms proxy block screens"), opt-in/opt-out status, and the menu or setting name they interact with.
- Technical detail belongs in the commit message and
ARCHITECTURE.md.
Other README sections (Features, System Requirements, Provider Menu, Updating…): edit the exact line affected and nothing else. New provider → one row. Reworded feature → one word. Do not rewrite paragraphs, add subsections, reorder, or restructure tables. README is reference doc; keep it slim.
# Release
'/c/Program Files/Microsoft Visual Studio/18/Enterprise/MSBuild/Current/Bin/MSBuild.exe' ClaudeCodeExtension.sln -p:Configuration=Release -v:minimal
# Debug
'/c/Program Files/Microsoft Visual Studio/18/Enterprise/MSBuild/Current/Bin/MSBuild.exe' ClaudeCodeExtension.sln -p:Configuration=Debug -v:minimal
./test.cmd # build Tests/ + run the unit suite (seconds, no VS)- From WSL bash, shell out via
powershell.exe -NoProfile -Command "& '<exe>' ..."rather thancmd.exe. - Scripts probe VS 2026 (
...\18\Enterprise) first, then fall back to VS 2022. test.cmdcovers version/package guards and pure helpers (parsers, formatters, path/session logic).SKIP_TESTS=1bypasses thepublish.cmdgate.- The test project has no
Release|Any CPU.Build.0entry, so the Release rebuild inpublish.cmddoes not build it. - Anything needing a live VS — terminal embedding, provider round-trip, settings dialog — has no automated coverage. Exercise it by hand in the Exp hive.
./deploy-exp.cmd # build Debug + deploy to Exp
./deploy-exp.cmd -release # Release instead
./deploy-exp.cmd -run # deploy, then launch devenv /rootsuffix Exp with the solutionF5 / Ctrl+F5 inside Visual Studio does the same for Debug and Release: the csproj sets
VSSDKTargetPlatformRegRootSuffix=Exp and turns on DeployExtension for builds inside VS,
because the VSSDK targets default DeployExtension to false and F5 would otherwise open a
clean Exp instance with no extension in it. Command-line builds (test.cmd, publish.cmd)
keep the default and deploy nothing.
Gotchas:
- Close the Exp instance before deploying — otherwise it keeps running the previous build.
- First deploy into a hive that never had the extension fails with
VSSDK1031 ... could not be found. The script recovers by runningdevenv /rootsuffix Exp /updateconfigurationand retrying. - Each deploy lands in a version-named folder, so a version bump leaves the old one behind and
the hive can silently keep loading the older assembly with no error anywhere. The
RemoveStaleExpDeploymentscsproj target deletes sibling version folders after every deploy.
Any phrasing — "publish the app", "publish to marketplace", "ship it" — means one thing:
./publish.cmd # from the repo rootDo not invoke MSBuild or marketplace APIs by hand; publish.cmd is the authoritative
automation. It runs test.cmd → Clean → Rebuild Release → publish the VSIX through
VsixPublisher.exe with publishManifest.json, falling back from VS 2026 to VS 2022 tool
paths. Success is detected via the VsixPub0038 log marker, which works around the
VsixPublisher telemetry crash in VS 18.
publishManifest.json holds the marketplace metadata: publisher dliedke, category coding,
free, Q&A enabled, README.md as the overview.
Publishing is outward-facing and hard to reverse — confirm with the user before running it unless they just asked for it.
ClaudeCodeModels.cs— add to theAiProviderenum; add a settings property if needed. Never renumber existing ordinals (6 is retiredQwenCode); persisted user settings depend on them being stable.ProviderManagement.cs— detection method, cache logic, install instructions, notification flag, menu handlers,UpdateProviderSelection(),ProviderContextMenu_Opened().Terminal.cs— command building inStartEmbeddedTerminalAsync()(both the CMD and WT paths),providerTitleswitch,InitializeTerminalAsync(),RestartTerminalWithSelectedProviderAsync(),UpdateAgentButton_Click(),Get{Provider}Command().TerminalIO.cs— Enter-key behavior inSendEnterKey(); add toisOtherWSLProviderif WSL.UserInput.cs— add to theisWSLProvidercheck for WSL path conversion.Detach.cs— add to theGetCurrentProviderName()switch.ClaudeCodeControl.xaml— context menu item, plus a settings item if the provider has flags.SessionHistory.cs— updateIsClaudeCodeSessionHistoryProvider()if it supports JSONL transcripts; callRefreshSessionHistoryButton()fromUpdateProviderSelection().ModelCatalog.cs— add aModelCatalogSourcesentry if the CLI can list its models (plus a parser inAgents/ModelCatalog.csif no existing shape fits), and teachGetModelLaunchFlag/GetLiveModelSwitchCommandhow the pick is applied. Skip this and the agent gets no model menu at all.README.md— one row/line each in Features, System Requirements, AI Provider Menu, Updating.CLAUDE.md— one row in the Supported AI Providers table.
For native mode, also add an IAgentSession adapter under Agents/ — see
ARCHITECTURE.md → Native Mode — Agent Sessions for the contract and the
streaming-duplication traps.
Models/ClaudeCodeModels.cs— add the property to the settings class with its default. Defaults must match what a fresh install should do; the JSON is merged over them.- Surface it —
ClaudeCodeControl.SettingsDialog.cs(pick the right tab) or the ⚙ menu. - Apply it on load in
ClaudeCodeControl.Settings.cs(LoadSettings()re-runs, so make the apply idempotent). ARCHITECTURE.md→ Data Models & Settings — add it to the Key settings list with its default and a one-line description.
Persistence is JSON at %LocalAppData%\ClaudeCodeExtension\claudecode-settings.json via
Newtonsoft.Json. Note that SaveSettings() deliberately preserves provider/model/effort fields
from disk during normal operation so parallel VS instances don't clobber each other — if your
setting is per-instance selection state, follow that pattern.
XAML control — both files go in UI/, and the csproj needs two entries:
<Page Include="UI\Foo.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
...
<Compile Include="UI\Foo.xaml.cs">
<DependentUpon>Foo.xaml</DependentUpon>
</Compile>Partial class of ClaudeCodeControl — goes in Controls/, named
ClaudeCodeControl.<Area>.cs, plus a plain <Compile Include="..."> entry.
Every .cs file needs the copyright header:
/* ***********************
* Application: ClaudeCodeExtension
* Autor: Daniel Carvalho Liedke / Claude Code
* Copyright © Daniel Carvalho Liedke 2026
* Usage and reproduction in any manner whatsoever without the written permission of Daniel Carvalho Liedke is strictly forbidden.
* Purpose: <description>
* ***********************/Namespaces: ClaudeCodeVS for controls/models, ClaudeCodeExtension for the package.
Check these before writing the code, not in review. Full text in ARCHITECTURE.md →
Cross-Cutting Rules.
Sending text to the agent (v82.0) — use SendTextToAgentAsync(), never
SendTextToTerminalAsync(). Native mode has no console, so a direct terminal call silently
sends nothing. Exceptions that stay console-only: slash commands, CLI self-updates, plugin
installs. Any new console-scraping logic must bail out when IsNativeModeActive.
Provider-dependent UI (v24.0) — checkmarks, tool-window captions, model/usage menu
visibility, detached-tab caption, visible-agent "active" labels: read _currentRunningProvider
when a terminal is alive, falling back to _settings.SelectedProvider only before launch.
Focusing the terminal (v26.0) — never SetForegroundWindow(terminalHandle) or bare
SetFocus(terminalHandle). Use FocusTerminalForInputAsync(), FocusTerminalForInput(), or
FocusTerminalWindow(). Low-level hook focus checks stay Win32-only on cached root-window
state — do not touch WPF/WinForms controls from the hook thread.
Bumping Newtonsoft.Json — don't. It's pinned to 13.0.3, the version VS itself loads
(issue #112). PackageVersionGuardTests enforces it.
| You changed | Update |
|---|---|
| Any code | Version in the 3 sources + README release note (Ship a release) |
| Non-obvious behavior in a tracked file | That file's section in ARCHITECTURE.md |
| A model, enum value, or setting | ARCHITECTURE.md → Data Models & Settings |
| A new provider | Supported AI Providers table in CLAUDE.md + README sections |
| A new file or folder | Project Structure tree in CLAUDE.md |
| A repeatable procedure | This file |
CLAUDE.md is always loaded — keep additions to it minimal and push detail into
ARCHITECTURE.md or here. Deep per-file explanation never goes in CLAUDE.md; its table maps
files to ARCHITECTURE.md sections, so update the section, not the table.