「あれ、さっきどこまでやったっけ...」
Claude Codeで長いワークフローを実行していると、突然のauto-compactで会話コンテキストがリセットされることがあります。 Issue分析が終わって、実装に入ったところで...「今どのフェーズだったか分からない」。
この3分前の自分が何をしていたか忘れる問題、心当たりありませんか?
前回の記事ではSkillsの設計思想と自作方法を解説しました。今回は、そのSkillsを確実に完遂するための状態管理設計に焦点を当てます。
この記事で学べること
- 揮発性問題をファイル永続化で解決するアプローチ
- 状態スキーマの設計パターン
- 復帰ポイント(next_actions)の設計意図
- 人間可読な状態保存の価値
- 自作Skillに状態管理を組み込む際の指針
揮発性の問題:なぜ状態管理が必要か
Claude Codeの会話コンテキストは揮発性です(settings.jsonのhooksで一部の事故は防げますが、記憶の消失自体は防げません)。以下のタイミングでリセットされます:
| トリガー | 状況 |
|---|---|
| auto-compact | トークン上限に達した時 |
| 手動クリア | /clear コマンド実行時 |
| セッション終了 | ターミナルを閉じた時 |
6フェーズのワークフロー(dev-kickoff)を実行する場合、Phase 3(実装)の途中でauto-compactが発生すると、「どこまで終わったか」が分からなくなります。
この問題の本質: AIの記憶は会話に依存しており、会話が消えると記憶も消える。 (人間だって5分前のタスク忘れるのに、AIに期待しすぎでは?)
解決アプローチ:ファイルシステムへの永続化
解決策はシンプルです。ファイルに状態を書き出す。
.claude/
├── kickoff.json # dev-kickoffの進捗状態
└── iterate.json # pr-iterateの進捗状態
Claude Codeの記憶は消えても、JSONファイルは残ります。復帰時にこれを読むだけで「続き」から再開できます。
「JSONに書くだけでしょ?」と思うかもしれません。でも、適当に書くと後で泣きます。私たちが実装したdev-kickoffスキルを例に、設計パターンを解説します。
設計パターン1:状態スキーマの設計
なぜスキーマを定義するのか
「とりあえず必要な情報をJSONに書く」だけでは不十分です。以下の問題が発生します:
- 不整合: フェーズ名が
phase3だったり3_implementだったりバラバラ(過去の自分を恨む瞬間) - 欠落: 必須フィールドが抜け落ちて復帰不能に
- 冗長: 不要なデータが蓄積してファイルが肥大化
設計意図: JSON Schemaで状態の形を厳密に定義することで、一貫性を保証する。
kickoff.jsonの構造
{
"version": "1.0",
"issue": 123,
"branch": "feature/issue-123-m",
"worktree": "/path/to/worktree",
"current_phase": "3_implement",
"phases": {
"1_prepare": { "status": "done", "result": "Worktree created" },
"2_analyze": { "status": "done", "result": "Identified 5 files" },
"3_implement": { "status": "in_progress" },
"4_validate": { "status": "pending" },
"5_commit": { "status": "pending" },
"6_pr": { "status": "pending" }
},
"next_actions": ["Continue implementation"],
"config": {
"strategy": "tdd",
"depth": "standard"
}
}
設計上の重要ポイント
| フィールド | 設計意図 |
|---|---|
version | スキーマ変更時の互換性確保(未来の自分への保険) |
current_phase | 「今どこにいるか」を一目で判断 |
phases[].status | 各フェーズの詳細な状態を追跡 |
next_actions | 復帰時の次アクションを明示 |
config | ワークフロー開始時の設定を保持 |
current_phaseとphasesを両方持つ理由: current_phaseは「今どこか」を即座に判断するため。phasesは「各フェーズがどうなったか」の詳細を保持するため。冗長に見えますが、用途が異なります。
設計パターン2:フェーズ遷移の設計
なぜ5状態が必要か
各フェーズのstatusは以下の5状態を取ります:
| status | 意味 | いつ使うか |
|---|---|---|
pending | 未着手 | 初期状態 |
in_progress | 実行中 | フェーズ開始時 |
done | 完了 | フェーズ成功時 |
failed | 失敗 | エラー発生時 |
skipped | スキップ | 意図的に飛ばした時 |
「doneとin_progress、そんなに区別いる?」と思うかもしれません。
設計意図: この区別がないと、「途中で止まった」のか「完了した」のかが分からない。復帰時に「あれ、実装終わったんだっけ?テスト通ったんだっけ?」となります(経験談)。
状態遷移の流れ
重要な設計判断: フェーズ完了時にcurrent_phaseを自動で次に進める。これにより、「完了したのに次に進んでいない」という不整合を防ぎます。
設計パターン3:復帰ポイントの設計
next_actionsの意図
{
"current_phase": "3_implement",
"next_actions": ["Continue implementation"]
}
current_phaseだけでは「次に何をすべきか」が曖昧です。Phase 3がin_progressのとき、「実装を続けるのか」「レビューを待つのか」「テストを先に書くのか」が分かりません。
設計意図: next_actionsに具体的な次アクションを明記することで、復帰時の判断を不要にする。
auto-compact後のClaudeに「えーっと、何してたんだっけ」と考えさせない。ファイルを読めば即座に動ける状態にしておく。
PR作成後の状態例
{
"current_phase": "completed",
"pr": {
"number": 456,
"url": "https://github.com/org/repo/pull/456"
},
"next_action": "pr-iterate"
}
Phase 6完了後はnext_action: "pr-iterate"を設定。復帰時に「次はpr-iterateを呼べばいい」と即座に分かります。迷う余地がない。
設計パターン4:人間可読な状態保存
なぜJSONだけでは不十分か
auto-compact後、Claudeは状態ファイルを読みます。しかし、JSONは機械向けのフォーマットです。
{"current_phase":"3_implement","phases":{"1_prepare":{"status":"done"},...}}
これを解析するより、人間が読める形式で状態を保存しておく方が効率的です。そして何より、デバッグ時に人間が泣かない。
STATE.mdの設計
auto-compact直前に、JSONをMarkdown形式に変換して保存します:
# Development State
_Auto-generated at 2026-03-26T10:00:00Z_
## Kickoff Status
- **Issue**: #123
- **Branch**: `feature/issue-123-m`
- **Current Phase**: `3_implement`
### Phase Progress
| Phase | Status |
| ----------- | ---------------------------- |
| 1_prepare | ✅ done - Worktree created |
| 2_analyze | ✅ done - Identified 5 files |
| 3_implement | 🔄 in_progress |
| 4_validate | ⏳ pending |
| 5_commit | ⏳ pending |
| 6_pr | ⏳ pending |
### Next Actions
- [ ] Continue implementation
設計意図: Claudeが読むだけでなく、人間(開発者)も状況を把握できる形式にする。「なんかSkillが止まってるんだけど...」というとき、このファイルを見れば一発で分かります。
設計パターン5:イテレーション状態の管理
PRレビューは「1回で終わる」とは限りません。というか、だいたい終わらない。レビュー→修正→再レビューのループを追跡する必要があります。
iterate.jsonの構造
{
"version": "1.0",
"pr_number": 456,
"current_iteration": 2,
"max_iterations": 10,
"status": "in_progress",
"iterations": [
{
"number": 1,
"review": { "decision": "request-changes", "issues": ["Fix typo"] },
"ci_status": "passed",
"fixes_applied": ["Fixed typo"]
},
{
"number": 2,
"review": { "decision": "pending" },
"ci_status": "pending"
}
],
"next_actions": ["Wait for review"]
}
設計上の重要ポイント
| フィールド | 設計意図 |
|---|---|
max_iterations | 無限ループ防止(10回で強制停止。それ以上は人間が見たほうがいい) |
iterations[] | 各回の詳細を履歴として保持 |
fixes_applied | 何を修正したかを記録(同じ指摘を繰り返さない。学習しないAIは困る) |
自作Skillへの応用:skill-creatorに伝えるべきこと
これらの設計パターンを自作Skillに適用したい場合、/skill-creatorに以下を伝えます。スクリプトの実装詳細は気にしなくてOK。設計意図を伝えれば、適切なコードを生成してくれます。
伝えるべき要件
-
揮発性対策が必要
- 「長時間ワークフローでauto-compactが発生する可能性がある」
- 「途中で止まっても続きから再開したい」
-
状態スキーマの設計
- 「フェーズは〇〇、△△、□□の3段階」
- 「各フェーズのstatusはpending/in_progress/done/failedを取る」
-
復帰ポイントの明示
- 「next_actionsフィールドで次にやるべきことを明記する」
-
人間可読な出力(オプション)
- 「auto-compact前にMarkdown形式で状態を出力したい」
具体例
/skill-creator データ移行を3フェーズで実行するSkillを作って。
- Phase 1: バックアップ
- Phase 2: 変換
- Phase 3: 検証
auto-compactが発生しても途中から再開できるように、
.claude/migration.jsonに状態を保存して。
各フェーズのstatusとnext_actionsを持たせて。
skill-creatorは、この指示に基づいて適切な状態管理スクリプトを生成します。あなたがupdate-phase.shの実装を書く必要はありません(そういう時代になりました)。なお、SKILL.md自体を軽量に保つコツはSKILL.mdの書き方と設計パターンで解説しています。
まとめ
Claude Code Skillsの状態管理は、揮発性の会話コンテキストをファイルで永続化することで、長時間ワークフローの確実な完遂を実現します。
5つの設計パターン
| パターン | 設計意図 |
|---|---|
| 状態スキーマ | 一貫性のある状態構造を保証 |
| フェーズ遷移 | 「途中で止まった」と「完了した」を区別 |
| 復帰ポイント | next_actionsで次アクションを明示 |
| 人間可読保存 | デバッグと手動介入を容易に |
| イテレーション管理 | ループ処理の履歴を追跡 |
自作Skillへの適用
- 「揮発性対策が必要」とskill-creatorに伝える
- フェーズ構成とstatus定義を明確にする
- next_actionsで復帰ポイントを設計する
「途中で止まっても、どこまでやったか分かる」。 これが、Skillsを使った開発ワークフローを安心して任せられる理由です。
この状態管理パターンは、git worktreeを使った並列開発の自動タスク分解と統合でも同じ思想で拡張しています。単体ワークフローのkickoff.jsonが、並列パイプラインのflow.jsonへと進化した形です。
(auto-compactが来ても、もう怖くない)



