A comprehensive guide for building VS Code extensions from zero to Marketplace publication. Covers scaffolding with Yeoman, manifest structure, command registration, TreeView and Webview patterns, and packaging with vsce. Includes specific guidance on extension host boundaries, managing generated sections with START/END markers, and centralizing notifications with configurable modes (sound, silent toast, status bar). The troubleshooting tables and done criteria are practical. References are organized by topic but written in mixed English and Japanese, which might slow you down if you're not bilingual. Best suited for developers building their first extension or debugging activation and packaging issues rather than those already deep in complex API work.
npx -y skills add aktsmm/agent-skills --skill vscode-extension-guide --agent claude-codeInstalls into .claude/skills of the current project.
Create, develop, and publish VS Code extensions.
# Scaffold new extension (recommended)
npm install -g yo generator-code
yo code
# Or minimal manual setup
mkdir my-extension && cd my-extension
npm init -y && npm install -D typescript @types/vscode
my-extension/
├── package.json # Extension manifest (CRITICAL)
├── src/extension.ts # Entry point
├── out/ # Compiled JS (gitignore)
├── artifacts/vsix/ # Keep local VSIX archives out of the repo root
├── images/icon.png # 128x128 PNG for Marketplace
└── .vscodeignore # Exclude files from VSIX
npm run compile # Build once
npm run watch # Watch mode (F5 to launch debug)
mkdir -p artifacts/vsix
npx @vscode/vsce package --out artifacts/vsix/my-extension-1.0.0.vsix
Keep local .vsix archives under artifacts/vsix/ instead of the repository root, and prune old local builds on a schedule so release artifacts do not pile up.
.vscodeignore)| Symptom | Fix |
|---|---|
| Extension not loading | Add activationEvents to package.json |
| Command not found | Match command ID in package.json/code |
| Shortcut not working | Remove when clause, check conflicts |
| Topic | Reference |
|---|---|
| AI Customization | references/ai-customization.md |
| Code Review Prompts | references/code-review-prompts.md |
| Code Samples | references/ai-customization.md and references/webview.md |
| TreeView | references/treeview.md |
| Webview | references/webview.md |
| Testing | references/testing.md |
| Publishing | references/publishing.md |
| Troubleshooting | references/troubleshooting.md |
path / Buffer / 生 fs より VS Code API を優先する。Problems と実ビルドの環境差を避けやすい。context.extensionUri と vscode.Uri.joinPath など extension context から解決する。resources/agents|skills|prompts|instructions|hooks|mcp の既知 root と、manifest の chatAgents / chatPromptFiles 宣言を優先して見る。built-in resource とは別の read-only resource として扱い、削除や再インストール導線を混ぜない。console.log に散らさず、Output Channel ベースの logger に集約する。ユーザーがログを開ける導線も command / notification / README のどこかに用意する。package.json の commands、views、configuration、menus を変えたら、コード上の command ID / setting key と同時に確認する。package.nls.json と対象言語の package.nls.*.json を同じ変更で更新する。START / END marker で囲む generated section は単一の SSOT として扱う。公開前にパッケージ名・設定キー・コマンド名を統一:
| 項目 | 例 |
|---|---|
| パッケージ名 | copilot-scheduler |
| 設定キー | copilotScheduler.enabled |
| コマンドID | copilotScheduler.createTask |
| ビューID | copilotSchedulerTasks |
type NotificationMode = "sound" | "silentToast" | "silentStatus";
function normalizeNotificationMode(mode: unknown): NotificationMode {
switch (mode) {
case "sound":
case "silentToast":
case "silentStatus":
return mode;
default:
return "sound";
}
}
function getNotificationMode(): NotificationMode {
const config = vscode.workspace.getConfiguration("myExtension");
if (config.get<boolean>("showNotifications", true) === false) {
return "silentStatus";
}
return normalizeNotificationMode(
config.get<NotificationMode>("notificationMode", "sound"),
);
}
function notifyInfo(message: string, timeoutMs = 4000): void {
const mode = getNotificationMode();
switch (mode) {
case "silentStatus":
vscode.window.setStatusBarMessage(message, timeoutMs);
break;
case "silentToast":
void vscode.window.withProgress(
{ location: vscode.ProgressLocation.Notification, title: message },
async () => {},
);
break;
default:
void vscode.window.showInformationMessage(message);
}
}
function notifyError(message: string, timeoutMs = 6000): void {
const mode = getNotificationMode();
if (mode === "silentStatus") {
vscode.window.setStatusBarMessage(`⚠ ${message}`, timeoutMs);
console.error(message);
return;
}
void vscode.window.showErrorMessage(message);
}
設定値は型注釈だけで信用せず、runtime で既知 enum へ正規化してください。設定ファイルの手編集や migration ずれで無効値が入っても通知経路を壊さないようにします。
supercent-io/skills-template
supercent-io/skills-template
huangjia2019/claude-code-engineering
reactjs/react.dev
reactjs/react.dev