codebase-architecture について
codebase-architectureは、TypeScriptコードベースの構造を設計し、変更コストを下げるスキルです。新規コードベースのアーキテクチャ概要、既存コードの改善、決定した構造の劣化を防ぐガードレールを扱います。
主な機能
- 01新規コードベースのアーキテクチャ概要を設計
- 02既存コードの改善案を順位付けして移行
- 03モジュールとインターフェースの境界を定義
- 04lint、型チェック、CIのガードレールを追加
- 05エージェントのコードベース内の案内を改善
活用シーン
- 01新しいTypeScriptアプリやサービスの構造選定
- 02概念の分散や境界の漏れを軽減
- 03CIで既定のモジュール境界を適用
- 04リポジトリ内の標準パターンをエージェントが発見しやすくする
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mblode/ agent-skills --skill codebase-architectureインストール後、Claude Code で/codebase-architectureを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
evals/evals.jsonevaluation-scenarios.mdreferences/agent-runtime.mdapi-design.mdbrief-conventions.mdcontagion-markers.mddeepening-existing.mddistributed-correctness.mddomain-language.mdenforcement-ladder.mdguardrail-tooling.mdstack-defaults.mdverification-tiers.mdvocabulary.mdwayfinding.md詳細
コードベースアーキテクチャ
TypeScript コードベースの構造を決め、変更のコストが高くなっている箇所を改善し、その構造を維持できるようにします。目指すのは、読者が頭の中で把握できるコードベースです。表面を少なくし、各作業に対する標準的な方法を一つに絞り、動作を最初に探す場所に置きます。
- 対象: フォルダー構成、モジュールインターフェース、リクエストコンテキストとミドルウェアパイプライン、フロントエンド/バックエンドの境界、アーキテクチャ概要、ドメイン用語と意思決定記録、ドメインを踏まえた深化、ガードレールツール、CI ゲート、エージェントのナビゲーション支援。
- 対象外: 新しいリポジトリのスキャフォールディング(Next.js の Turborepo には
scaffold-nextjs、TypeScript CLI にはscaffold-cli)、マルチテナントのドメイン/分離/ルーティング(multi-tenant-architecture)、AGENTS.md 自体の内容(agents-md)、一つの機能の計画(planning)、差分に限定したクリーンアップ(tidy)、ローカル差分の構造レビュー(tidy)、または製品独自の検証 CLI、doctor コマンド、機能マップ(app-verification。名前を明示してください)。
目次
- モード
- 参考資料
- Design モード(新規コードベース)
- Deepen モード(既存コードベース)
- Harden モード(定着させる)
- 検証ループ
- 出力テンプレート
- 注意点
- 関連スキル
モード
成果物ではなく、問題に基づいて選び、どのモードを選んだかを伝えてください。
| モード | 該当する状況 | 出力 |
|---|---|---|
| Design | 新しいアプリ、サービス、または領域に着手していて、構造がまだ決まっていない | アーキテクチャ概要 |
| Deepen | コードは動くものの、変更のコストが高い。概念が散らばっている、境界から漏れている、一つの考えに三つの名前がある | 優先順位付きの改善機会、その後、移行済みの一つのスライス |
| Harden | 構造は決まっているが劣化し続けている、またはエージェントがこのリポジトリで間違った作業を繰り返している | 組み込まれたチェック、目印、手順 |
モードは組み合わせられ、複数を実行するのは普通です。 Design は Harden で終わります。チェックのない契約は単なる提案だからです。Deepen も Harden で終わります。新しい境界が再び劣化しないようにするためです。構造はすでに適切で、強制する仕組みだけが不足している場合は Harden 単独で実行します。エージェントが作業するリポジトリでは、これがよくあるケースです。
二つのモードが同じくらい適切に見える場合は、Deepen を優先してください。「エージェントが古いパターンを使い続けている」という状況は Harden に見えます。しかし、原因が一つの概念が二か所に存在することなら、隔離しても重複を凍結するだけです。Deepen で重複を削除し、その変更が反映されるまで Harden で維持します。古いものを本当に残す必要がある場合に限り、Harden 単独が適切です。
リポジトリに書き込めない場合(チェックアウトがない、読み取り専用の依頼、または変更ではなく質問の場合)、各モードの出力は計画にとどまります。つまり、概要、優先順位付きの改善機会、または段階を示した名前付きチェックです。どのチェックも組み込まれていないため、未検証のまま残るチェックを明示してください。
可能な限りシンプルに。ただし、必要なシンプルさを損なわないようにします。 どのモードでも削減します。Design では表面を、Deepen では概念を、Harden では二重の経路と休眠中の設定を削減します。ただし、最低限必要なものは削りません。信頼境界での検証、データ損失を防ぐエラー処理、セキュリティ、アクセシビリティ、デプロイされたものの可観測性、そして明示的に依頼された内容です。これらのいずれかを損なう単純化はバグです。意図的に手を抜く場合は、次に読む人が完成済みかどうかを推測せずに済むよう、上限とアップグレード手順を明記してください。
進捗を追跡するために以下をコピーし、実行しないモードの行は削除してください。
Codebase architecture progress:
- [ ] Modes chosen and stated (Design / Deepen / Harden)
- [ ] Design: assumptions stated, repo shape, every contract names its check, brief written
- [ ] Deepen: git hot spots, glossary, ranked opportunities with paths, one slice migrated
- [ ] Harden: existing checks surveyed, checks picked by failure, each landed green and proven to bite
- [ ] Validation loop run for the modes used; evidence recorded, N/A items named
参考資料
条件に該当する場合のみ読み込みます。
| 参考資料 | モード | 読み込むタイミング |
|---|---|---|
| references/vocabulary.md | すべて | 出力内でモジュール、インターフェース、シーム、アダプターの名前を付ける前。削除テストについて定義しています |
| references/stack-defaults.md | 設計 | ライブラリ、ツール、デプロイ先を選ぶとき |
| references/api-design.md | 設計、深化 | エンドポイント、モジュールインターフェース、リクエストコンテキスト、エラー形式、転送される認証情報を設計するとき |
| references/distributed-correctness.md | 設計、深化 | 作業が外部システム、Webhook、リトライ、監査証跡、または金銭に確実に関わるとき。深化では grep で検索できます。設計では要件に関する質問なので、製品のドメインから推測せず、読み込む前に確認してください |
| references/brief-conventions.md | 設計 | brief の規約、テスト、品質基準、ロールアウト、ロールバックのセクションを書くとき |
| references/deepening-existing.md | 深化 | 深化を実施するとき:機会のパターン、2 通りの設計、ランキング、エージェント向け変更の測定、出力テンプレート |
| references/domain-language.md | 深化 | 用語集の作成または修正、命名の相違の解決、決定事項の記録を行うとき |
| references/enforcement-ladder.md | 強化 | すでに違反があるリポジトリにチェックを追加するとき |
| references/guardrail-tooling.md | 強化 | 実際のチェックを選択して組み込むとき:デッドコード、重複、循環、モジュールとパッケージの境界、ファイルサイズ、鮮度ゲート |
| references/wayfinding.md | 強化 | エージェントが情報を見つけられない、または同じ手順を何度も導き出しているとき |
| references/contagion-markers.md | 強化 | リポジトリにレガシーコード、生成コード、二重経路、または意図的に簡略化されたコードがあるとき |
| references/verification-tiers.md | 強化 | エージェントが実行すべきコマンドとそのタイミングを定義するとき |
| references/agent-runtime.md | 強化 | 編集後フック、権限の許可リスト、またはエージェントが修正案の作成やアラートのトリアージを無人で行うジョブを設定するとき |
設計モード(新規コードベース)
まず、各サーフェスが本当に必要かどうかを確認します。すでにリリース済みのものの中にフォルダーとして収まるモジュール、サービス、アプリ、エントリーポイントを新設しないことは、最もコストの低いアーキテクチャ上の判断であり、コストの低さを保てる唯一の判断でもあります。導入するサーフェスはどれも、サーフェス領域の予算(brief-conventions.md)における関係維持のコストを伴います。ブリーフに記載する前に、担当者、テスト、可観測性、削除方法を明確にしてください。
- まず制約を確認します。製品の範囲、チームの規模、コンプライアンスとセキュリティ、想定規模、デプロイ先、必要な連携、品質基準です。1 行の依頼にはこれらの情報がないため、一般的なケースを想定し、すべての前提をブリーフの最初のセクションに明記して、修正を促してください。誤った推測によってブリーフの構成自体が変わる場合に限り、率直に質問します。実際には、マルチテナント対応の有無と API が公開されるかどうかです。
- リポジトリの構成を選びます。
apps/にはデプロイ可能なサーフェス(api、web、admin)を配置します。packages/には共有ライブラリ(shared、ui、icons、auth、proto)を配置します。
- バックエンドのモジュールインターフェースを定義し、それぞれに適用する強制方法(インポート境界の lint または型チェック)を明記します。
handler:トランスポートのみを扱います。service:ビジネスオーケストレーションを担います。dao:データベースアクセスのみを扱います。db パッケージをインポートできるのは DAO のみとし、各テーブルには所有するモジュールを 1 つだけ設け、そのサービスのみが書き込みます。クエリのルールは references/api-design.md の「Data Access」を参照してください。mapper:DB/proto/ドメイン間の変換を担います。constantsとtypes:モジュール内の契約を定義します。
- リクエストコンテキストとミドルウェアを定義します。
- AsyncLocalStorage を使った
RequestContextにtenantId、userId、traceIdを保持し、すべてのエントリーポイント(RPC、HTTP、ジョブ、CLI)で初期化して、getContext()経由で読み取ります。ctxパラメーターをすべての呼び出しに渡すと、あらゆるシグネチャが肥大化し、後からフィールドを 1 つ追加するだけでも、すべての呼び出し元に手を入れることになります。実装については references/api-design.md を参照してください。 - 登録時に、各 RPC メソッドの認証ポリシーを明示するよう求めます。ポリシーのないメソッドは、公開をデフォルトにするのではなく、登録に失敗させます。
- 認証、ログ記録、エラー、コンテキストは共有ミドルウェアにまとめ、各ハンドラーのコードには含めません。
- AsyncLocalStorage を使った
- フロントエンドの境界を定義します(デフォルトは Next.js App Router)。
app/にはルーティングファイル(page、layout、loading、error、route)のみを置きます。ドメインコードはsrc/modules/<name>/に置き、そのルートファイル経由で利用します。1 つのルート専用の UI は、そのページの隣にある_components/フォルダーに置きます。ページのロジックが増えたら、app/内の隣接ファイルではなく、モジュールに移します。- デフォルトでは Server Component を使い、インタラクティブな末端に
"use client"を指定します。クライアントラッパーでサーバーレンダリングされたコンテンツが必要な場合は、childrenとして渡します。 - サーバー状態には TanStack または Connect Query、クライアント状態にはコンポーネントの状態を使います。どちらにも当てはまらない横断的なクライアント状態に限り、MobX を使います。データごとに所有者は 1 つだけです。サーバーデータを
useStateに複製したり、2 つのストアをuseEffectで同期したりしているなら、所有者が不明確な兆候です。 proxy.ts(Next 16 でのmiddleware.tsの名称)は、リダイレクト、リライト、ヘッダーを処理します。認可は各ルートハンドラーと Server Function 内で判断します。matcher から除外されたパスは proxy を通らず、Server Function はそのページのルートに POST するためです。
- テストとリリース:
- 単体テストでは DB を使いません。統合テスト/E2E テストは、動的に生成した ID を使って並列実行し、テスト実行同士でフィクスチャが衝突しないようにします。
- 変更ごとにロールバック計画を用意し、小さく、完結した、元に戻せる垂直スライスとしてリリースします。
- 信頼性、エラーパス、可観測性、ユーザー向けの状態まで網羅して初めて、スライスは完了です。これらを仕上げの段階まで先送りすると、結局リリースされないままになります。
- ブリーフに記載するすべての契約には、違反を検出する lint ルール、型チェック、またはテストを明記してから、Harden モードに進み、それらを組み込みます。
Deepen モード(既存のコードベース)
目標:書き換えではなく、ドメインに基づいて深めます。分析手法、機会のパターン、出力テンプレートについては、references/deepening-existing.md を読み込んでください。
- ドメインの用語と判断を把握します。
CONTEXT.md、docs/adr/、または存在する場合はそのローカル相当のものを読み、チームが使っている名称で、エンティティ、アクション、コンテキストをコードから確認します。相違点(1つの概念に3つの名前がある、または1つの名前に3つの概念がある)を記録します。フォーマットとADRのルールは references/domain-language.md を参照してください。 - 変更が入る場所に合わせて調査範囲を絞ります。 変更が繰り返されるコードを深めると効果があるため、まず十分な期間の
git log --onelineを確認し、繰り返し登場するファイルを重視します。範囲を定めずに調査すると、推測に基づく整理に流れてしまいます。 - 深める機会を見つけます。 貧血な概念、浅いモジュール、境界の漏出、命名の相違、概念の重複、プリミティブ型への執着、ロジックの配置ミス、公開インターフェースを越えざるを得ないテストを探します。曖昧な兆候ではなく、各項目にファイルパスを記録します。候補ごとに、まず削除を検討します。実際に呼び出されない概念、分岐が実行されないフラグ、実装が1つしかないレイヤーが該当します。削除こそが深めることであり、コードベースを読みにくくすることのない唯一の手段です。
- 効果の大きさで順位を付けます。 削除テストに合格する、名前の付いた将来の変更を局所化する、変更頻度が低い、現在の要件を満たす、実行可能なテスト境界がある機会を優先します。対象インターフェースを設計する前に候補を順位付けし、推測に基づく整理は除外します。最有力候補については、どちらかを選ぶ前にインターフェースを2通り設計します。
- まず垂直スライスを1つ移行します。 一般化する前に、効果が最も大きい変更を1つのスライスでエンドツーエンドに実証します。
- 新しい境界を lint、型、またはテストによるチェックで強制し、劣化しないようにしてから、モジュールごとに展開します。強制の段階と check-bites テストに進むには、Harden モードを続けてください。
強化モード(定着させる)
二つの柱があります。ガードレールは誤ったものが取り込まれるのを防ぎ、道しるべは正しいものを簡単に見つけられるようにします。エージェントはドキュメントを読むのではなく grep で情報にたどり着くため、どちらも欠かせません。つまり、警告はエージェントがたどり着いた場所に置き、ルールは誰かが覚えているかもしれない文章ではなく、終了コードで示す必要があります。
まず最も強力な仕組みを使います。構造、次に lint と CI、その次に文章、最後に人によるレビューです。レビューコメント、インシデント、繰り返されるミスは、いずれもチェックが欠けていることを示します(references/enforcement-ladder.md)。
手順 1〜3 は必ず実施します。手順 4〜6 は条件に当てはまる場合にのみ実施し、チェックを 1 つ追加する依頼なら手順 3 で止めます。すべての依頼で 6 つの手順すべてを実施すると、バンドルの大半を読み込むことになり、このモードで最も起こりやすい失敗につながります。
- 既存のものを調査します。 パッケージスクリプト、CI の手順、フック設定、lint 設定、指示ファイル、ドキュメントの索引を確認します。次の 3 つを見つけます。ローカルでは実行されるもののマージをブロックしないチェック、CI では実行されるものの失敗にできないチェック(
verification-tiers.mdの「Commands that lie」)、誰も実行していない休眠状態の設定です。最初のチェックは組み込み、2 つ目は修正し、3 つ目は削除します(references/contagion-markers.md)。 - ツールの人気ではなく、防止する失敗に基づいてチェックを選びます。 カテゴリーとツールについては references/guardrail-tooling.md を参照してください。このリポジトリで実際に起きている失敗を 2〜3 個選びます。最初から一式すべてを導入すると、すべてのチェックに対して最も弱い強制レベルを選ばざるを得なくなります。
- 各チェックを導入します。 すでに存在する違反に合わせて強制レベルを選び(references/enforcement-ladder.md)、チェックを通過する状態で導入してから、実際に機能することを確認します(実行し、意図的に失敗させ、修正方法を示すメッセージとともに失敗することを確認し、元に戻します)。プリコミットフックと CI の両方に組み込みます。
- references/wayfinding.md に従って道しるべを整備します。命名と局所性、新しい X を追加する手順ファイル、信頼度ラベル付きのドキュメント索引、唯一の正規の指示ファイルを用意します。
- references/contagion-markers.md に従って感染拡大防止マーカーを設置します。エージェントにコピーさせてはならないもの、または編集させてはならないものには、代わりに使うものを明示した grep 可能なマーカーをコード上の該当箇所に配置します。
- 実行時の使いやすさ: references/verification-tiers.md の検証レベル、references/agent-runtime.md のセッションフック、権限許可リスト、無人修正ジョブ、アラートのトリアージを整備し、強制順序のレベル 4 でレビューを必須にします。
検証ループ
実行したモードに該当する項目を実行し、結果を出力に記録します。各項目には根拠が必要です。「一貫しているように見える」だけでは合格になりません。何もインストールされていない、またはリポジトリに書き込みできないために実行できない項目は、その理由を添えて N/A と記録します。黙って合格扱いにすると、適用されていない契約が検証済みに見える状態でリリースされます。
- 一貫性(Design、Deepen):命名、モジュールのインターフェース、ミドルウェアのルールが、すべてのサービスで一貫していること。根拠:矛盾のスキャンで指摘事項がゼロであること。
- 強制可能性(すべて):すべての契約に、対応する lint ルール、型チェック、またはテストが明記されていること。根拠:契約ごとの強制方法の注記、および実際にインストールされているチェックについて、合格、意図的な違反による失敗、元に戻した後の再合格を示すこと。
- 運用可能性(Design):デプロイ可能な各面について、ヘルスチェック、ロールバック手段、遅延や停止を把握できる可観測性(ルートごとの p95/p99 レイテンシ、ジョブ種別ごとのキュー深度と最古のジョブの経過時間)があること。時間がかかる処理、再試行可能な処理、サードパーティの処理は、アプリの既存データベース内の行を状態として使う永続ジョブとして実行し、新たなキューやストアは追加しません。モジュールは直接呼び出し、呼び出し元がコンシューマーを待つ必要も知る必要もない場合に限ってイベントを使います(references/distributed-correctness.md)。自動化されたすべてのジョブに、デプロイ不要のキルスイッチを設けます。すべての機能について、依存先が停止したときにフェイルオープンとフェイルクローズのどちらになるかを明記します。根拠:ロールアウトのセクションでそれぞれを明示し、モジュール間にイベントやキューを設ける場合は、直接呼び出しでは不十分な理由を明記すること。
- 品質ゲート(コードを変更した場合):リポジトリの lint、型チェック、対象を絞ったテスト(
pnpm lint、pnpm check-types、pnpm --filter <pkg> test、または同等のもの)。根拠:引用した合格出力。 - CI とローカルの一致(Harden):CI のステップが、開発者が実行するものと同じ一括コマンドを呼び出すこと。異なる場合は、意図的な違いであることを明記します。
- 未解決の参照がなく、手順が白紙の状態から機能すること(Harden):ドキュメントのインデックスと指示ファイルで名前が挙がっているすべてのパスが存在することを grep で示し、初期コンテキストのエージェントが「新しい X の追加」レシピを、追加のガイダンスなしで最初から最後まで実行できること。
- 全体としての簡潔さ(すべて):結果として、読者が把握すべきことが増えるのではなく減ること。ファイル、面、エクスポート名の増減を示し、増加したものはすべて、その分どこで何を取り除いたかを明記すること。さらに、導入した各レイヤー、ポート、間接化について、それを実際に必要とした2つ目の呼び出し元または実装を示します。ほかのすべての項目に合格していても、追加するだけのアーキテクチャレビューはこのチェックに不合格です。
不合格の場合:ブリーフ、規約、または接続処理を修正し、ループを再実行します。
出力テンプレート
Design モードではこのブリーフを作成します。Deepen モードの優先順位付き機会テンプレートは references/deepening-existing.md にあります。Harden モードでは、配線そのものとループの根拠が出力となり、ドキュメントは作成しません。
# Architecture brief
## Context and constraints
## Repo shape
## Backend module interfaces
## Request context and middleware policy
## Frontend boundaries
## Testing strategy
## Quality bar and surface-area budget
## Rollout and rollback plan
## Open risks and follow-ups
ブリーフの規模はテンプレートではなく、決定事項に合わせてください。 プロジェクトに当てはまらない見出しは、無理に埋めず削除します。たとえば、フロントエンドのない単一テナントの内部サービスに、Frontend boundaries セクションを設ける必要はありません。各セクションでは、決定事項と、その決定を必要とした制約を記載します。参照先の規約を言い換えるだけではいけません。2つの議論が必要な決定にレビューの注意を向けるべきところ、9つのセクションに水増ししたブリーフでは、その注意を浪費してしまいます。
注意点
Harden モードの注意点は、各ステップで読み込まれるリファレンス(guardrail-tooling.md、enforcement-ladder.md、contagion-markers.md、verification-tiers.md、wayfinding.md)に記載されています。
- チームが 5 人未満の場合、マイクロサービスを採用すると、デプロイパイプライン、コントラクトのバージョン管理、サービスごとのオンコール体制が必要になります。まずはモジュラーモノレポから始め、チームの拡大や規模の拡大によって境界の必要性が実証されてから分割します。
- モノレポのルート
package.jsonにアプリレベルの依存関係を記述すると、暗黙に hoist されるため、ローカルではアプリをビルドできても、単独でデプロイすると失敗します。依存関係は各アプリが個別に管理します。 - インポート境界のルールがない
handler/service/daoのコントラクトは、最初の締め切りを迎えた時点で形骸化します。コントラクトを作成する日に、ルール(daoはhandlerをインポートできない)も追加します。 - ページまたはレイアウトのレベルで
"use client"を指定すると、サブツリー全体がクライアントレンダリングになり、ストリーミングとサーバーからの直接データアクセスができなくなります。末端のコンポーネントに限定します。 - コードを必要とするアプリが 3 つ以上になる前に
packages/へ切り出すと、何のメリットもなくリリースサイクルが結合されます。例外は、すでに 2 つのサーフェスが共有しているコントラクト(生成された型、RPC スキーマ、ブランド付き ID)です。これは両者のインターフェースなので、アプリが 2 つの段階でパッケージに含めます。 - アウトボックス(または CDC)なしでデータベースとキューや Webhook に二重書き込みを行うと、一方のコミット後に他方が失敗したとき、通知が失われたり捏造されたりします。
references/distributed-correctness.mdを参照してください。 - 外部から強制可能な不変条件を、構築時に強制する(符号なし型、厳格な CHECK)と、外部からその状態を強制されたときにクラッシュするか、値が制限されます。その状態を表現できるようにし、事後に検出して、明示的に復旧します。
proxy.tsだけを認可レイヤーとして頼ると、matcher の対象外のパスはこれを回避します。また、Server Functions はページのルートに POST するため、matcher の変更でカバレッジが気づかれないまま失われます。ハンドラーまたは Server Function 自体で認可を確認します。git logでホットスポットを絞り込まずにコードベース全体を対象に深掘りスキャンを行うと、誰も触らないモジュールでリストが埋まり、そこにある項目はすべて定義上、推測にすぎません。
関連スキル
agents-md:AGENTS.md/CLAUDE.md ファイル自体を扱います。このスキルは、そのファイルが参照するチェックとドキュメントツリーを管理します。リンターで強制できるルールは、文章として記述するのではなく、終了コードを返すチェックとしてここに置きます。tidy:レビューと差分の範囲に絞ったクリーンアップを行います。Harden のガードレールによって、その範囲は小さく保たれます。planning:1 つの機能に関する計画を作成します。Design モードのアーキテクチャ概要をここに取り込みます。scaffold-nextjs、scaffold-cli:このスキルで構造化するリポジトリを作成します。multi-tenant-architecture:テナントの識別、分離、ルーティングを扱います。このスキルは、その基盤となるモジュールレイアウトを提供します。dx-audit:パッケージが外部に提供する開発者向けの機能を扱います。ここにあるapi-design.mdでは、コントラクトの形状のみを扱います。app-verification:リポジトリが自ら使用する verify CLI、doctor コマンド、機能マップを構築・保守します。このスキルの Harden モードでは、そのハーネスのスクリプトとフィクスチャが通過すべき CI チェックを組み込みます。名前を指定して呼び出してください。
保守専用:evals/evals.json と evals/evaluation-scenarios.md には、このスキルへの変更に対するリグレッションシナリオが含まれています。どちらもユーザータスク中には読み込まれません。