はじめに
個人・学習用のアプリ開発を題材に、AIエージェント(Claude Code)に仕様駆動開発(SDD)を守らせ続けるための監督の仕組み=「ハーネス」 を作った記録のシリーズです。
第1回(総論)では、次を扱います。
- なぜAIは「お願い(指示書)」を守ってくれないのか
- それを解く「ハーネス」という発想
- ハーネスを構成する 4つの層 の全体像
📦 ソースコード:https://github.com/NeoSolleil/aim-trainer/tree/harness-only
(harness-onlyブランチ。mainは今後の機能開発で変わるため、記事と一致する状態を固定したブランチです)
↓mainブランチはこちらです
この記事について
対象読者・前提知識
- AIコーディング(Claude Code / Copilot 等)を少し触ったことがある人
- Web開発(フロント+API+DB)の経験がある人
- Clean Architecture / BDD / TDD は「言葉は聞いたことがある」程度でOK(出てくる用語はその都度かみ砕きます)
逆に、特定のフレームワークの使い方の記事ではありません。テーマは「AIに決めたとおり作らせ続けるには、何をどう仕込めばいいか」です。
シリーズ構成(予定)
- 総論:なぜAIに“ハーネス”が要るか(この記事)
- 指示と文脈の層:
CLAUDE.mdと.claude/rules/(AIに“何を・いつ”知らせるか) - 機械強制の層:import-linter・pre-commit・Claude のフック・CI
- 仕様駆動のパイプライン:発見 → 仕様 → 設計 → 分解 → 実装
- スキルとサブエージェント:役割分担で品質を上げる
動機:AIは「お願い」を守ってくれない
AIにコードを書かせると、最初はうまくいきます。問題は作り続けるうちです。
例えば「ドメイン層(業務ルールの中核)には、Webフレームワークやデータベースの道具を持ち込まない」という設計判断があったとします。これは Clean Architecture の基本で、後で技術を入れ替えやすくするための約束です。
この約束を、AIへの指示書(Claude Code なら CLAUDE.md)に日本語で書いておく——のですが、文章はあくまで「お願い」です。会話が長くなり、文脈が薄れ、急いでいると、AIは平気で import sqlalchemy(DBの道具)をドメイン層に書きます。そして何も止めてくれません。
学習目的で「一度ガチガチの正式版を通してみたい」と思ったとき、この“なし崩し”が一番の敵でした。
発想:禁止は「文章」ではなく「仕組み」に置く
そこで方針を一つに絞りました。
「絶対に起きてはならないこと」は、文章では強制できない。実際に逸脱を止める力は“仕組み”(フック・lint・CI)に宿る——それがこのシリーズで言う「ハーネス」だ。
指示書は事実の共有と助言に徹し、逸脱を実際に止めるのは決定論的な仕組みに任せる。この「監督の仕組み」一式を、本シリーズでは ハーネス(harness) と呼びます。レースカーの運転手を固定して安全に走らせる、あのハーネスのイメージです。
ポイントは、「助言」と「機械強制」を意図的に書き分けること。「これは助言(守ってくれたら嬉しい)」「これは機械強制(破れない)」を曖昧にしないことが、信頼できるハーネスの条件です。
ハーネスの全体像:4つの層
作ったハーネスは4層構成です。外側ほど“やわらかい助言”、内側ほど“硬い強制”になっています。
| 層 | 置き場所 | 役割 | 強制力 |
|---|---|---|---|
| ① 事実の共有 | CLAUDE.md |
構成・規約の索引(プロジェクト憲法) | 助言 |
| ② パス別のルール | .claude/rules/ |
特定のフォルダを触る時だけ読まれる規約 | 助言+一部は機械強制へ昇格 |
| ③ 決定論的な強制 | pre-commit / Claudeのフック / CI | 逸脱をブロックする | 機械強制 |
| ④ 仕様駆動の進行+検証 |
.claude/skills/ / .claude/agents/
|
開発の各段階を進める手順役・役割別の作業役/レビュー役 | プロセス |
図にすると、外側ほど“やわらかい助言”、内側ほど“硬い強制”です。
プロジェクト全体のファイル配置はこんな形です。
aim-trainer/
├── CLAUDE.md # ① 事実の索引(憲法)
├── .pre-commit-config.yaml # ③ コミット前チェック
├── .github/workflows/ci.yml # ③ CI(push / PR)
├── .claude/
│ ├── rules/ # ② パス別ルール(5本)
│ ├── settings.json # ③ フック登録
│ ├── hooks/ # ③ フック本体
│ ├── skills/ # ④ SDDの段階+知識(11本)
│ └── agents/ # ④ 役割別サブエージェント(9体)
├── backend/ # FastAPI(Clean Architecture)
├── frontend/ # Vite + React + Canvas
└── specs/ # SDD成果物(機能ごと)
ざっくり言うと:
- ①② は「AIに知っておいてほしいこと」を、必要な時に必要な分だけ渡す層。
- ③ は「やったら止める」層。ここがハーネスの中核です。例えば後述しますが、AIがルール違反のコードを書こうとした瞬間に、その編集自体を拒否できます。
- ④ は「どう進めるか(仕様駆動)」と「誰がやるか(役割別のAIエージェント)」を整える層。
各層の中身は第2回以降でコードとともに掘り下げます。
題材と、いまの正直な現在地
題材はFPSのエイム練習アプリ(画面の的をクリックして反応速度と命中率を測るもの)。技術は Vite + React(フロント)/ FastAPI + SQLAlchemy + SQLite(バック)です。
ただし強調したいのは、この記事時点ではアプリの機能は1行も実装していないということです。やったのは「作る前に、作り方を守らせる枠組みを固める」こと。順序がふつうと逆に見えますが、学習目的では「枠を先に固めてから、その中で実装する」方が、SDD(仕様駆動開発)の効きを体感しやすいと考えました。
- ✅ ハーネス4層は完成
- ⬜ 最初の機能の仕様・実装はこれから(次は「発見(discover)」段階から)
次回予告
第2回は、AIに“何を・いつ”知らせるか——指示と文脈の層(① CLAUDE.md と ② .claude/rules/)を扱います。
- プロジェクト憲法
CLAUDE.mdを「事実の索引」に徹させる理由(禁止を散文で書かない) -
.claude/rules/のパス別ルール——特定フォルダを触る時だけ読み込ませる仕組み - 助言にすぎないルールを、次回(第3回)の機械強制へ“格上げ”する橋渡し
その後の第3回で、いよいよ「AIの編集をその場で拒否する」決定論的な強制に踏み込みます。