Andrej Karpathy発の「LLMコーディング失敗パターン」、CLAUDE.mdへ結晶化
2026年4月、GitHubで突然トレンドに躍り出たCLAUDE.mdテンプレートがある。forrestchang/andrej-karpathy-skills——公開3ヶ月弱で 30,044スター を集めた、たった 4原則・2,357バイト の単一CLAUDE.mdだ。
名前が示すとおり、このリポジトリの源流は Andrej Karpathy氏 のXポスト(2026年1月)。元Tesla AIディレクター、OpenAI創設メンバー、スタンフォードCS231n講師を務めた「AI分野でコードを書くのが一番上手い人の一人」として広く知られる彼が、LLMにコードを書かせる際の典型的な失敗パターンを指摘した短い観察録だった。このポストを受けて forrestchang が観察を4原則のCLAUDE.mdに結晶化し、MITライセンスで公開——これが現在30k★超のリポジトリになっている。
本記事では、Karpathyの原ポスト(公式引用)・4原則の中身・具体的な過ちパターン・導入方法までを一気に解説する。Claude Codeを日常的に使うエンジニアなら、読み終わる頃には自分の CLAUDE.md に4原則を追記したくなるはずだ。
(LLM失敗4パターン)"] --> F["forrestchang
(CLAUDE.md化)"] F --> P["4原則CLAUDE.md
(2,357バイト)"] P --> C1["Think Before Coding"] P --> C2["Simplicity First"] P --> C3["Surgical Changes"] P --> C4["Goal-Driven Execution"] C1 & C2 & C3 & C4 --> R["30,044★
事実上のデファクト"] style K fill:#f5a623,stroke:#e67e22,color:#000 style F fill:#f5a623,stroke:#e67e22,color:#000 style P fill:#2980b9,stroke:#1a5276,color:#fff style C1 fill:#27ae60,stroke:#1e8449,color:#fff style C2 fill:#27ae60,stroke:#1e8449,color:#fff style C3 fill:#27ae60,stroke:#1e8449,color:#fff style C4 fill:#27ae60,stroke:#1e8449,color:#fff style R fill:#2980b9,stroke:#1a5276,color:#fff
Andrej Karpathy氏の観察→CLAUDE.mdへ結晶化した2,357バイトのルール集
公開3ヶ月弱で30k★獲得——Claude Codeユーザーの事実上のデファクト
4原則は「無言の仮定・過剰実装・副次的改変・目標の曖昧さ」に対応
Karpathyが指摘した3つの問題|原ポスト引用と日本語訳
リポジトリのREADMEには、Karpathyの原ポストから3つの指摘が引用されている。いずれもLLMにコードを書かせたことがある人なら「あるある」と頷くはずだ。
問題1: 無言の仮定と合流
“The models make wrong assumptions on your behalf and just run along with them without checking. They don’t manage their confusion, don’t seek clarifications, don’t surface inconsistencies, don’t present tradeoffs, don’t push back when they should.”
「モデルはあなたの代わりに誤った仮定を置き、確認もせずに突っ走る。混乱を管理せず、確認を求めず、不整合を表に出さず、トレードオフを提示せず、反論すべき場面でも反論しない」
典型例:export ユーザーデータ と依頼 → LLMは黙って全ユーザーをJSONで1ファイルに吐き出し、ページネーション・プライバシー・量の問題に触れない。
問題2: 過剰実装とコード肥大
“They really like to overcomplicate code and APIs, bloat abstractions, don’t clean up dead code… implement a bloated construction over 1000 lines when 100 would do.”
「モデルはコードやAPIを過剰に複雑化したがる。抽象化を肥大させ、デッドコードを掃除しない。100行で済むのに1000行の膨張した構築物を実装する」
典型例:「割引を計算する関数を作って」→ Strategy Pattern・DataClass・Protocol・ABCを駆使した30行以上のクラス階層(本来は1関数3行で済む)。
問題3: 副次的改変・理解せずに削除
“They still sometimes change/remove comments and code they don’t sufficiently understand as side effects, even if orthogonal to the task.”
「モデルは時に、タスクとは無関係で十分理解していないコメントやコードを副作用として変更・削除してしまう」
典型例:バグ修正を依頼したら、無関係な型ヒント追加・docstring追加・クォート統一・「改善っぽい」リファクタが一斉に紛れ込み、差分レビューが地獄になる。
この3つの問題に対して、4つの原則で網を張る——これがandrej-karpathy-skillsの設計思想だ。
無言の仮定で
突っ走る"] --> R1["原則1
Think Before
Coding"] P2["問題2
過剰実装・
コード肥大"] --> R2["原則2
Simplicity
First"] P3["問題3
副次的改変・
理解せず削除"] --> R3["原則3
Surgical
Changes"] K["Karpathyの洞察
『LLMは目標ループが
異常に得意』"] --> R4["原則4
Goal-Driven
Execution"] style P1 fill:#e74c3c,stroke:#c0392b,color:#fff style P2 fill:#e74c3c,stroke:#c0392b,color:#fff style P3 fill:#e74c3c,stroke:#c0392b,color:#fff style K fill:#f5a623,stroke:#e67e22,color:#000 style R1 fill:#27ae60,stroke:#1e8449,color:#fff style R2 fill:#27ae60,stroke:#1e8449,color:#fff style R3 fill:#27ae60,stroke:#1e8449,color:#fff style R4 fill:#27ae60,stroke:#1e8449,color:#fff
原則1: Think Before Coding|仮定を隠さず、不明を名指す
Don’t assume. Don’t hide confusion. Surface tradeoffs.
実装の前に、以下を徹底する:
- 仮定は明示:不確かなら推測せず尋ねる
- 複数解釈があれば全て提示:黙って1つを選ばない
- 単純な代替案があれば押し戻す:「もっと簡単なやり方があります」と言う
- 不明な点は立ち止まる:何が不明かを名指ししてから質問する
悪い例(黙って仮定を置く)
ユーザー: 「検索を速くして」
# 勝手にキャッシュ + DB索引 + 非同期処理を全盛り
@lru_cache(maxsize=1000)
async def search(query: str) -> List[Result]:
# ... 200行の最適化コード
良い例(仮定を表に出して選ばせる)
「検索を速くする」には3通りの解釈があります:
1. 応答時間を短縮(500ms→100ms)
→ DB索引追加・キャッシュ。見積 2時間
2. 同時リクエスト数を増やす(スループット)
→ async/await・コネクションプール。見積 4時間
3. 体感速度の改善(UX)
→ 部分結果を即表示・段階的ロード。見積 3時間
現状は典型クエリで約500ms。どれを優先しますか?
このパターンはClaude CodeだけでなくClaude Skills徹底解説で扱った「スキルで専門知識を教える」方式との相性が良い。「質問テンプレート」をスキル化してしまう運用も効果的だ。
原則2: Simplicity First|過剰設計の罠を断つ
Minimum code that solves the problem. Nothing speculative.
ルール:
- 頼まれていない機能を足さない
- 単回使用のコードに抽象を持ち込まない
- 頼まれていない「柔軟性」「設定可能性」を入れない
- 起きえないシナリオのエラーハンドリングを書かない
- 200行で書いたものが50行で済むなら、書き直す
テスト:「シニアエンジニアがこれを見て『過剰だ』と言うか?」——Yesなら単純化する。
が混ざっていないか?"} B -->|"混入あり"| R1["削除"] B -->|"なし"| C{"単回使用のコードに
抽象化を入れていないか?"} C -->|"あり"| R2["具象化し直す"] C -->|"なし"| D{"起こらないシナリオへの
エラーハンドリングがないか?"} D -->|"あり"| R3["削除"] D -->|"なし"| E{"200行で書いたが
50行で済むのでは?"} E -->|"Yes"| R4["書き直す"] E -->|"No"| F{"シニアが『過剰』
と言うか?"} F -->|"Yes"| R5["単純化"] F -->|"No"| OK["✅ 完了"] R1 --> A R2 --> A R3 --> A R4 --> A R5 --> A style R1 fill:#e74c3c,stroke:#c0392b,color:#fff style R2 fill:#e74c3c,stroke:#c0392b,color:#fff style R3 fill:#e74c3c,stroke:#c0392b,color:#fff style R4 fill:#e74c3c,stroke:#c0392b,color:#fff style R5 fill:#e74c3c,stroke:#c0392b,color:#fff style OK fill:#27ae60,stroke:#1e8449,color:#fff
悪い例(割引計算の過剰抽象化)
from abc import ABC, abstractmethod
class DiscountStrategy(ABC):
@abstractmethod
def calculate(self, amount: float) -> float: ...
class PercentageDiscount(DiscountStrategy):
def __init__(self, percentage: float):
self.percentage = percentage
def calculate(self, amount: float) -> float:
return amount * (self.percentage / 100)
# ... FixedDiscount, DiscountConfig, DiscountCalculatorと続く30+行
良い例(必要十分)
def calculate_discount(amount: float, percent: float) -> float:
"""Calculate discount amount. percent should be 0-100."""
return amount * (percent / 100)
discount = calculate_discount(100.0, 10.0) # $10 off
複雑さは「必要になった時に追加する」——先回りの抽象化はほぼ全て害になる。Strategy Patternが本当に要るのは「割引の種類が3つ以上存在し、新規追加の頻度も高い」状況のみ。その時にリファクタすればいい。
原則3: Surgical Changes|触ってはいけない境界
Touch only what you must. Clean up only your own mess.
既存コード編集時のルール:
- 隣接コード・コメント・フォーマットを「改善」しない
- 壊れていないものをリファクタしない
- 既存スタイルに合わせる(自分流儀を押し付けない)
- 関係ないデッドコードに気づいたら 伝えるだけ——消さない
自分の変更が孤児を作った時:
- 自分の変更で不要になったimport/変数/関数のみ削除
- 以前から存在するデッドコードは頼まれない限り触らない
テスト:変更された全行が、ユーザーのリクエストに直接トレースできるか?
ユーザーの依頼に
直接紐づく?"} B -->|"Yes"| OK["✅ 維持"] B -->|"No"| C{"自分の変更で
不要になった
import/変数?"} C -->|"Yes"| D["✅ 削除OK"] C -->|"No"| E{"隣接する
既存コードの
『改善』では?"} E -->|"Yes"| R1["❌ 戻す"] E -->|"No"| F{"既存スタイル
からの逸脱?"} F -->|"Yes"| R2["❌ 戻す"] F -->|"No"| G{"壊れていないものの
リファクタ?"} G -->|"Yes"| R3["❌ 戻す"] G -->|"No"| OK style OK fill:#27ae60,stroke:#1e8449,color:#fff style D fill:#27ae60,stroke:#1e8449,color:#fff style R1 fill:#e74c3c,stroke:#c0392b,color:#fff style R2 fill:#e74c3c,stroke:#c0392b,color:#fff style R3 fill:#e74c3c,stroke:#c0392b,color:#fff
悪い例(バグ修正ついでに改良してしまう)
リクエスト:「空メールでvalidatorが落ちるバグを直して」
def validate_user(user_data):
- # Check email format
- if not user_data.get('email'):
+ """Validate user data."""
+ email = user_data.get('email', '').strip()
+ if not email:
raise ValueError("Email required")
- if '@' not in user_data['email']:
+ if '@' not in email or '.' not in email.split('@')[1]:
raise ValueError("Invalid email")
+ # 勝手にユーザー名検証も追加
+ username = user_data.get('username', '').strip()
+ if len(username) < 3:
+ raise ValueError("Username too short")
+ if not username.isalnum():
+ raise ValueError("Username must be alphanumeric")
return True
良い例(依頼された1点のみ)
def validate_user(user_data):
# Check email format
- if not user_data.get('email'):
+ email = user_data.get('email', '')
+ if not email or not email.strip():
raise ValueError("Email required")
if '@' not in email:
raise ValueError("Invalid email")
if not user_data.get('username'):
raise ValueError("Username required")
return True
変更したのは「空メールの扱い」だけ。クォート・型ヒント・docstring・ユーザー名検証には一切手を触れない。diffがクリーンならレビューコストが劇的に下がる。
原則4: Goal-Driven Execution|命令から目標へ書き換える
Define success criteria. Loop until verified.
タスクを 検証可能な目標 に変換する:
| 命令 | 目標形式 |
|---|---|
| “Add validation” | “無効入力に対するテストを書き、それを通す” |
| “Fix the bug” | “バグを再現するテストを書き、それを通す” |
| “Refactor X” | “変更前後でテストが通ることを保証する” |
複数ステップのタスクには簡潔な計画を:
1. [ステップ] → verify: [チェック]
2. [ステップ] → verify: [チェック]
3. [ステップ] → verify: [チェック]
Karpathyはこの原則の背景を次のように語っている:
“LLMs are exceptionally good at looping until they meet specific goals… Don’t tell it what to do, give it success criteria and watch it go.”
「LLMは特定の目標を満たすまでループするのが異常なほど得意だ。何をすべきかを命令するのではなく、成功基準を与えて見ていろ」
この洞察は本リポジトリの最も重要なアイデアかもしれない。「make it work」のような曖昧な命令は常に確認のやり取りを要求するが、「このテストが通ることを目指せ」のような検証可能な基準があればLLMは独立してループし続ける。
Claude Codeベストプラクティス完全ガイド2026でもTDD(テストファースト開発)の重要性を扱ったが、Karpathy流は単なるTDDではなく「成功基準を外に出す → エージェントが自律ループ」というパラダイムシフトを伴っている。
導入方法と効果測定|Plugin vs CLAUDE.md直接貼付
方法A: Claude Code Plugin(推奨)
Claude Code内から以下を実行。マーケットプレイス追加後にプラグインをインストールする。
/plugin marketplace add forrestchang/andrej-karpathy-skills
/plugin install andrej-karpathy-skills@karpathy-skills
プラグイン導入のメリットは 全プロジェクトで横断的に適用 される点。個別に CLAUDE.md をコピーする手間が不要。
方法B: CLAUDE.md 直接貼付(プロジェクト単位)
新規プロジェクト:
curl -o CLAUDE.md https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/CLAUDE.md
既存のCLAUDE.mdに追記:
echo "" >> CLAUDE.md
curl https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/CLAUDE.md >> CLAUDE.md
既存のプロジェクト固有ルールと4原則は併存可能。たとえば:
## Project-Specific Guidelines
- Use TypeScript strict mode
- All API endpoints must have tests
- Follow the existing error handling patterns in `src/utils/errors.ts`
[Karpathy 4原則をここに追記]
適用?"} B -->|"全プロジェクト
横断"| P["Plugin方式
(推奨)"] B -->|"特定プロジェクト
のみ"| M{"既存CLAUDE.md
がある?"} M -->|"Yes"| A1["curl で追記
(既存ルール+4原則)"] M -->|"No"| A2["curl で新規作成"] P --> P1["/plugin marketplace add
forrestchang/andrej-karpathy-skills"] P1 --> P2["/plugin install
andrej-karpathy-skills@karpathy-skills"] P2 --> OK["✅ 全プロジェクトで有効"] A1 --> OK2["✅ このプロジェクトで有効"] A2 --> OK2 style P fill:#2980b9,stroke:#1a5276,color:#fff style P1 fill:#f5a623,stroke:#e67e22,color:#000 style P2 fill:#f5a623,stroke:#e67e22,color:#000 style A1 fill:#f5a623,stroke:#e67e22,color:#000 style A2 fill:#f5a623,stroke:#e67e22,color:#000 style OK fill:#27ae60,stroke:#1e8449,color:#fff style OK2 fill:#27ae60,stroke:#1e8449,color:#fff
効果測定の4指標
公式READMEは「効いている」を判定する4つの観察可能な指標を提示している:
| 指標 | 観察方法 |
|---|---|
| 不要な差分が減る | git diff を見て、リクエスト外の変更が入っていないか |
| 過剰実装による書き直しが減る | PRを何度も大きく書き直す頻度 |
| 確認質問が実装前に来る | 実装後に「こう解釈したけど良かった?」が減る |
| PRが最小限・クリーン | 無関係な「drive-by改善」が混ざらない |
逆にこれらが見られなければ、マージした4原則が読まれていない可能性がある。Claude Code再起動や明示的な /summarize CLAUDE.md 相当の確認で復習させると効果が戻る。
トレードオフ|すべての作業に適用すべきではない
リポジトリ作者は「caution over speed(速度より慎重さ)に偏る」という明確なトレードオフを明記している。
| 適用すべき | 適用すべきでない |
|---|---|
| 非自明な機能追加 | タイポ修正 |
| 大規模リファクタリング | 明らかな一行変更 |
| 設計判断を伴うコーディング | 定型的なボイラープレート生成 |
| 本番コードの修正 | ローカル実験・プロトタイピング |
「ちょっとしたスクリプトで1行のロガー追加」のような明白な作業に毎回「仮定を明示してください」と立ち止まると、開発速度が落ちるだけだ。4原則は「コストの高いミスが発生し得る非自明な作業」で真価を発揮する。
まとめ|Karpathy観察は「LLM時代のコードレビューの心得」
このOSSの優れた点は、単なるTips集ではなく 「LLMの典型的失敗パターン → それを封じ込める原則」 というペアリング構造にある。1.5年分のLLMコーディング経験の蓄積が、2,357バイトの CLAUDE.md に凝縮されている。
Karpathyの原ポストは「LLM批判」ではなく「LLMの癖を理解して使いこなす」ためのノートだ。4原則を自分の CLAUDE.md に追記してみて、日常的にClaude Codeを使うならClaude Skills徹底解説と組み合わせて「質問テンプレート」「計画テンプレート」をスキル化するのも効果的。Agentic AI Engineer Roadmap 2026でも触れたとおり、これからのエンジニアに必須の「AIエージェントと協働するスキル」の核心がここにある。
参照ソース
- forrestchang/andrej-karpathy-skills (GitHub) — 本記事の対象OSSリポジトリ
- Andrej Karpathy X post (元ポスト) — 4原則の源流
- CLAUDE.md (本体) — 2,357バイトの本体ファイル
- EXAMPLES.md — 4原則の具体的な悪い例/良い例
- Andrej Karpathy GitHub — Karpathy氏本人のアカウント
- Anthropic Claude Code 公式ドキュメント — CLAUDE.mdの仕様一次ソース