はじめに
VSCodeでClaude CodeにIssue対応を任せていると、以下のようなことをしたいなと思いました。
- Claudeが1つのIssueを作業している間、ローカル環境で別のIssueも並行で進めたい
- メインのVSCodeでは devサーバーを起動したまま別作業をしており、邪魔されたくない
- Claudeの作業が終わったら、すぐローカルのブラウザで動作確認したい。OKならそのままPRを作ってほしい
- クラウドで完結するAIもあるが、使い慣れているVSCodeを使って差分の閲覧と検証もしたい。
解決アプローチとして、gitのworktreeという機能とカスタムスラッシュコマンドを用いた。 git worktreeを使うと、1つのリポジトリから複数の独立した作業ディレクトリを作れる(ファイル編集が互いに衝突せず、git履歴は共有)。これをClaude Codeのカスタムスラッシュコマンドで自動化した。
動作イメージ
動作イメージは以下のようになります。
/issue <GitHub Issue番号>で作業してほしいissueを指定(手動)- git worktreeの自動作成(自動)
- VSCodeが別ウィンドウで立ち上がる(自動)
- 新規VSCodeのターミナルが自動で立ち上がり、
/issue-workが実行され作業を開始する(自動)
導入方法
今回作成した、/issueと/issue-workをカスタムスラッシュコマンドとしてClaude Codeが読み込める形にします。
~/.claude/commands/に置けば、全リポジトリ共通で使えます。
カスタムスラッシュコマンドの導入
以下のテキストをコピーして使用します。
/issue(VSCodeランチャー)
---
description: Issue番号からworktreeを作成し、新しいVSCodeウィンドウでClaude作業セッションを自動起動する(ランチャー)
argument-hint: <issue番号>
---
GitHub Issue #$ARGUMENTS の作業環境をセットアップしてください。
あなたの役割は**ランチャー**です。実装はこのセッションでは行いません(実装は新ウィンドウ側の `/issue-work` が担当)。
## 大前提(最重要)
- **現在のチェックアウトはユーザーが別作業中。絶対に触らない。**
現在のディレクトリでのファイル編集・`git checkout` / `git switch` / `git stash` は禁止。
- このコマンドの実行自体が「worktree 用ブランチ作成の許可」とみなしてよい。
## 手順
1. `gh issue view $ARGUMENTS --json title -q .title` で issue タイトルを取得し、**スラッグ**を作る:
- 英数の kebab-case に変換する(例: "Fix login form validation" → `fix-login-form-validation`)
- 日本語タイトルは内容を表す短い英語に意訳する(例: "ログイン画面のバリデーション修正" → `fix-login-validation`)
- 3〜5語・30文字程度まで。記号は除去する
- 以降、worktree 名は `issue-$ARGUMENTS-<スラッグ>`、ブランチ名は `issue/$ARGUMENTS-<スラッグ>` とする
2. `git fetch origin` を実行し、worktree を作成する:
`git worktree add .claude/worktrees/issue-$ARGUMENTS-<スラッグ> -b issue/$ARGUMENTS-<スラッグ> origin/HEAD`
(同名ブランチが既に存在する場合は `-b` を外して既存ブランチで作る)
3. `.env` など gitignore されていて実行に必要なファイルを、メインのチェックアウトから worktree にコピーする。
4. worktree 内に `.vscode/tasks.json` を作成する。これは新ウィンドウで Claude を自動起動するための**使い捨てファイル**(`/issue-work` 側が起動後すぐ削除する):
```json
{
"version": "2.0.0",
"tasks": [
{
"label": "claude-issue-worker",
"type": "shell",
"command": "claude \"/issue-work $ARGUMENTS\"",
"runOptions": { "runOn": "folderOpen" },
"presentation": { "focus": true, "panel": "dedicated" },
"problemMatcher": []
}
]
}
```
5. `code <worktreeの絶対パス>` で新しい VSCode ウィンドウを開く。
6. 以下を報告して終了する:
- worktree のパスと、新ウィンドウで `/issue-work $ARGUMENTS` が自動起動すること
- もし自動起動しない場合(自動タスクが未許可など)は、新ウィンドウのターミナルで
`claude "/issue-work $ARGUMENTS"` を手動実行すればよいこと
このセッションは引き続き別の `/issue <番号>` を受け付けられる(ディスパッチャーとして使い回せる)。
/issue-work(作業役)
---
description: worktree内でIssueの実装〜動作確認待ち〜PR作成まで進める(/issueから自動起動される作業役)
argument-hint: <issue番号>
---
GitHub Issue #$ARGUMENTS に対応してください。
あなたは worktree 内で起動された**作業セッション**です。カレントディレクトリがその worktree です。
## 大前提
- 作業はすべてこの worktree 内で完結させる。worktree の外(メインのチェックアウト)には触らない。
- **push と PR 作成はユーザーの「OK」が出るまで禁止**。
## 手順
1. まず `.vscode/tasks.json` を削除する(自動起動用の使い捨てファイル。PR に混入させない)。
2. `gh issue view $ARGUMENTS` で issue の内容・受け入れ条件を確認する。
3. 依存関係をインストールする(例: `npm install`。worktree は新規チェックアウトなので `node_modules` が存在しない)。
4. 実装する。既存のテスト・lint があれば実行して通す。
5. コミットする(push はしない)。
6. 動作確認の準備として、dev サーバーを**バックグラウンド起動**する。
メインのチェックアウトのサーバーと衝突しないよう、空いているポートを使うこと
(例: `npm run dev -- --port 3001`。3001 が埋まっていれば 3002, 3003…と探す)。
7. 完了したら以下を報告し、**ユーザーの確認待ちで止まる**:
- 確認用 URL(例: http://localhost:3001)と、確認すべき画面・API・操作手順
- 変更内容の要約(何をどう変えたか)
8. ユーザーが「OK」と言ったら:
- dev サーバーを停止する。
- push し、`gh pr create` で PR を作成する(本文に変更概要・動作確認内容・`closes #$ARGUMENTS` を含める)。
9. 修正指摘があった場合は、修正→再コミット→手順7に戻る
(サーバーがホットリロード対応なら起動したままでよい)。
10. PR 作成後、後片付けの案内をして終了する:
- このウィンドウは閉じてよいこと
- worktree の削除はメインのチェックアウト側で
`git worktree remove <この worktree の絶対パス>` を実行すればよいこと
(実際のパスを `pwd` で確認して案内する。ランチャー側の Claude に
「issue #$ARGUMENTS の worktree を消して」と頼んでもよい)
実際の動作
実際の動作原理です。読み飛ばしても問題ありません。
/issue(ランチャー): 環境構築だけ。メインのチェックアウトには一切触らないことを厳命。同じセッションで次々と Issue をディスパッチできる
/issue-work(作業役): 新ウィンドウ側で自動起動され、実装〜確認待ちまでを担当
メインのターミナル(ディスパッチャー)
─────────────────────────────
1. claudeを起動して /issue 17 コマンドを受理
2. ghでIssueタイトル・内容取得
3. worktree 作成(worktree名はIssueの内容から自動命名)
4. .env をメインからコピー
5. 使い捨て tasks.json を仕込む
6. code <worktreeパス> で新ウィンドウ起動
新しいVSCodeウィンドウ(自動で開く)
─────────────────────────────
新しいVSCodeウィンドウでClaudeを自動起動する部分は、VSCodeの自動タスク機能(tasks.json の "runOn": "folderOpen")を利用。
1. フォルダを開いた瞬間、自動タスクでtasks.json を即削除(PR混入防止)
2. npm install(worktreeは新規チェックアウト)
3. 実装 → テスト → コミット
4. 必要があれば、空きポートで dev サーバー起動
今後の展望
- 作業が終わったらpushとPR作成を自動で行ってworktreeも削除して完了するまでを自動化しても良いかもしれないです。AIにpushして欲しくなかったので、今回は含めていません。
- 余談ですが、Claudeが作業完了したときに音を鳴らすようにすると、捗ります。
参考文献
worktree を使用して並列セッションを実行する - Claude Code Docs
並列 Claude Code セッションを個別の git worktree に分離して、変更が衝突しないようにします。--worktree フラグ、subagent の分離、.worktreeinclude、クリーンアップ、および非 git VCS フックについて説明します。