🛠️

Claude Code:コンテキスト節約から生まれた開発環境・運用

に公開

経緯

なぜこんな環境を作ったのか。発端は以下の2点。

  • やり取りが長引くとコンパクションが発生し、AIの回答精度が著しく落ちた。
  • AIを導入してまもなく、あらゆる業務でAIを活用した結果、「お前だけトークンの消費量が異常だ!」とお叱りを受けた。

メンバによって使用量にばらつきがあった時期で、前職からフル活用していた自分だけ突出していたらしい。
また、入社したての時期で、ドキュメントがほぼ存在しないプロダクトの理解にAIをフル活用していた。

この結果、コンテキストを節約するために、自分なりに工夫した結果、こんな環境になった。

設計指針

  • コンテキストを節約する
    • AIに解決させるより、bashで実行させる方がトークンを消費しないよね?と安直に考えたのが意外と良かった。
  • コンテキストを溢れさせない
    • 必要なときだけ読み込む。常駐させない

フォルダ・ファイル構成

~/.claude/
├── CLAUDE.md                        # 一般的な内容のみ。最小限に保つ
├── settings.local.json              # 許可コマンド設定(Read・閲覧系のみ)
├── .env.issue                       # 作業中のIssue状態管理

├── docs/                            # ガイドライン類(rulesから参照)
│   ├── coding_rules.md
│   ├── database_connection.md       # Docker環境でのDB接続方法
│   ├── basic_design_guideline.md
│   ├── detail_design_guideline.md
│   ├── unit_test_guideline.md
│   └── integration_test_review_guideline.md

├── learning/                        # 自社ドメイン知識ベース
│   ├── xxx_functions.md             # 機能仕様(業務で把握したもの)
│   └── xxx_functions_database.md    # DB定義(業務で把握したもの)

├── rules/                           # ルール(内容は書かずdocs/へのリンクのみ)

├── skills/                          # 自動発火するスラッシュコマンド(トリガー条件を記載)
│   ├── database-connection.md       # DB接続方法(Docker環境、DB操作時に自動参照)
│   ├── conflict-check.md            # コンフリクト解決後のソースコード欠損チェック
│   └── requirements.md              # GitHubから要件を取得しIssue用mdに記載

├── agents/
│   └── code-investigator.md         # コード調査専用エージェント

├── commands/                        # 人間が手動実行するスラッシュコマンド
│   ├── start-issue.md               # 作業開始・.env.issue更新
│   ├── commit.md                    # コミット
│   ├── pr-body.md                   # PRボディ生成
│   ├── pr-review.md                 # PRレビュー用worktree作成・IDE起動
│   └── dailyreport.md               # 日報作成

├── bin/                             # スキル・コマンド専用shell
│   ├── start_issue.sh
│   ├── commit.sh
│   └── pr_body.sh

└── lib/                             # 汎用ライブラリ
    ├── env.sh                       # .env.issue の参照ライブラリ
    ├── github.sh                    # gh コマンドのラッパー
    ├── windows.sh                   # WSLパス変換・Windowsユーザ名取得
    └── xlsx.py                      # xlsx参照

skills/ と commands/ の個人的な使い分け

skills/ はトリガー条件を書いておき、条件に合致したときAIが自動で参照する。
commands/ は人間がスラッシュコマンドで明示的に呼び出すもの。

自動発火させたいかどうかで置き場所を分けている。
というか、前はcommandsしかなかったので、その名残というほうが正しい。。。

スキルの例を挙げると、conflict-check はコンフリクト解決後に自動発火し、解決によってソースコードが意図せず消えていないかをチェックする。requirements は「要件詳細確認して」と言われたタイミングで発火し、GitHubから対象Issueに関連する最新の要件ドキュメントを取得して、Issueごとに管理しているmdファイルに要件・TODO(チェックリスト形式)を記載する。

bin/ と lib/ の責務分離

bin/ はスキル・コマンドからのみ呼ばれる処理を置く。
lib/ はコマンドに依存しない汎用ライブラリを置く。

スキルは「判断・生成」を担い、手順が決まっている処理は bin/ のshellに委譲する。AIがやるのはbashでは実現しづらいもの、または実装コストに対してトークン節約の効果が小さいものだけに絞る。

lib/ はClaude Codeが使う汎用機能をライブラリ化したものを置く。GitHubへのアクセス、環境変数の参照、WindowsパスからWSLパスへの変換など、スキルやコマンドを横断して使えるものを追加していく。xlsx.py のようにPythonで書くこともある。共通処理をここに集約することで、各スキル・コマンドをシンプルに保てる。

コンテキスト設計の詳細

節約する

bashで実行できる処理はAIに解決させない。git操作・ファイル更新・ghコマンド実行など、手順が決まっているものはすべて bin/ のshellに委譲する。AIを呼び出すよりbashを実行させる方がトークンを消費しないのでは?と考えたのがきっかけ。

共通処理は lib/ にライブラリ化する。複数のスキル・コマンドで使う処理を切り出すことで、スキルファイル自体も短くなる。

サブエージェントによるコード調査は要約だけ返す。ファイルの相対パスと調査結果を必須フォーマットにしているので、後続タスクで再調査が発生しない。

AIがやるのは「判断・生成が必要なもの」だけに絞る。ブランチ名の提案、コミットメッセージ生成、PRのSummary作成など、bashでは実現しづらいもの、または実装コストに対してトークン節約の効果が小さいものだけにしている。

溢れさせない

rules/ には内容を書かず、docs/ へのリンクだけを書く。ルールに引っかかったときだけ読み込まれる。常駐させない。

learning/ は必須読み込みにしない。ドメイン知識が必要な場面でAIが参照する緩い設計にしている。毎回読み込むとコンテキストを圧迫する。

CLAUDE.md は一般的な内容のみ。毎回読み込まれるため、書きすぎない。

状態管理:.env.issue

複数の開発環境を並行して使うため、作業中のIssue情報を1ファイルで管理している。

# .env.issue
ISSUE_ID_A=123
PROJECT_ID_A=456
PROJECT_NAME_A=example-project
ISSUE_NAME_A=ログイン機能の実装
DETAIL_DESIGN_PATH_A=/path/to/detail_design.md
UNIT_TEST_SPEC_PATH_A=/path/to/unit_test_spec.md

ISSUE_ID_B=789
PROJECT_ID_B=...
...

変数名の末尾にサフィックス(_A / _B)をつけることで1ファイルに集約。
lib/env.sh がカレントディレクトリのパスから現在の環境を自動判定し、サフィックスなしの変数名で値を返す。後続のスキルやコマンドは環境の違いを意識しない。

ワークフロー

/start-issue {issue_id} — 作業開始

bin/start_issue.sh を呼び出し、.env.issue を更新する。

格納される情報:

  • Issue ID / プロジェクトID / プロジェクト名 / Issue名
  • 要件定義や各種ドキュメントのパス

以降のスキル・コマンドはすべて env.sh 経由でこの情報を参照する。

/commit — コミット

bin/commit.sh が以下を順番に実行する:

  1. ブランチ元リポジトリを最新化
  2. git stash(変更を退避)
  3. ブランチ名の提案と作成
  4. git stash apply(popではなくapply)
  5. .env.issue の詳細設計書・作業管理mdを参照してコミットメッセージを生成
  6. git commit
  7. git push -u origin ... のコマンドを人間に提示するだけ

stash apply を使う理由:pop はstashを削除するが、apply は残す。問題が起きたときの保険になる。

pushを人間に委ねる理由:リモートへの反映は取り消しコストが高い。コマンドを提示するだけにして、最終確認を人間が担う。

/pr-body — PRボディ生成

.env.issue に格納された詳細設計書・Issue ID・単体テスト仕様書を参照して、以下の構成のPRボディを自動生成する。
そのまま投稿させてもよいが、個人的に内容を確認してから投稿したいので、このスタイルにしている。

# Summary

# Issue

# Changes

# Test Plan

/pr-review {PR番号} — PRレビュー

PRブランチを git worktree で別ディレクトリに展開し、IDEを起動する。

  • 開発環境を汚さない:worktreeで独立したディレクトリを作るため、作業中のブランチに影響しない
  • 慣れたIDEでレビューする:ターミナル上ではなく、IDEの差分表示やジャンプ機能を使ってレビューできる

レビュー後はworktreeを削除するだけで環境がきれいに戻る。

その他のコマンド

  • /dailyreport — 日報作成

運用で気をつけていること

期待通りじゃない出力が出たら、そのセッションで修正を試みるより、すぐに別セッションを立ち上げてClaude Codeの運用改善の話をするようにしている。

例えば基本設計を作らせていると、要件定義で使われているユビキタス言語を無視して独自の用語を使ったり、章ごとに書き方が揃っていなかったりすることがある。そういう「ズレ」に気づいたタイミングで、CLAUDE.mdやrulesを改善する。

最新のClaude Codeには /btw というコマンドがあり、同一セッション内でも運用の話を切り出せるらしい。ただ業務環境の都合でアップデートを自由に行えないため、現時点では別セッション運用を続けている。

今後やりたいこと

途中経過が不要で最終結果だけ返せばいいものは、まだ改善の余地があると思っている。

  • gitなどのbashコマンドをサブエージェントに委譲
  • 文字列置換はsed/awkを使わせる(ファイルを丸ごと読み込む無駄を省く)

まとめ

コンテキストを節約しつつ、ハルシネーションや結果の揺らぎを防ぐことを意識していたら、気づけばこういう構成になっていた。試行錯誤の途中なので完璧ではなく、独自のこだわりが詰まってるが、現時点での運用をまとめると以上になる。

Discussion