Claude Code の Team プラン(プレミアムシート)を使っている。トークンは毎週金曜にリセット。
今週、水曜で切れた。 初めて。金曜まであと2日。開発は止められない。
渋々 Cursor を開いた。
やったこと:.cursorrules に150行書いた
Claude Code なら空気読んでくれる。Cursor は初めてだから不安。全部言語化した。
ALWAYS use TypeScript. NEVER use JavaScript.
ALWAYS write tests for every function.
NEVER use any type.
ALWAYS use named exports. NEVER use default exports.
ALWAYS add error handling. NEVER ignore errors.
ALWAYS use early return. NEVER nest more than 3 levels.
ALWAYS use Tailwind CSS. NEVER use inline styles.
...(全部で150行。全行 ALWAYS か NEVER)
起きたこと:無視された
- TypeScript って書いたのに
.jsファイルを生成する -
NEVER nestと書いたのにif-elseの4段ネスト - 会話の後半でルールごと忘れる
書けば書くほど、言うことを聞かなくなった。
調べたこと:公式を2つ読んだ
困った時の Anthropic 頼み。Claude Code ユーザーだから Anthropic の公式リポジトリは庭みたいなもの。
読んだらこう書いてあった。
ALWAYS や NEVER を大文字で書いている自分に気づいたら、それはイエローフラグだ
自分の .cursorrules、全行イエローフラグだった。
Cursor の公式ドキュメントにも同じことが書いてある。Claude を作った会社と、Claude を動かしてる IDE が同じことを言っている。
じゃあ ALWAYS / NEVER をやめて「理由」を書けば解決するのか?
気になったから検証した。
検証:ALWAYS / NEVER vs 理由ベース、本当に差が出るのか
実験の設計
わざとルールと矛盾するコードを用意した。
既存コード(意図的にルール違反):
// Button.tsx — default export、inline style、any 型
export default function Button({ onClick, label, style }: any) {
return (
<button
onClick={onClick}
style={{ backgroundColor: 'blue', color: 'white', padding: '8px 16px' }}
>
{label}
</button>
);
}
Card.tsx、api.ts も同じパターン。全ファイル default export + any 型 + inline style。
ルールは2パターン用意:
| ルール A | ルール B | |
|---|---|---|
| 形式 | ALWAYS / NEVER |
理由ベース |
| 例 | ALWAYS use named exports. NEVER use default exports. |
named export を使う。auto-import の精度が上がりリファクタリング時に参照を追跡しやすいため。 |
タスクは同じものを2回:
- 「
UserProfile.tsxを新規作成せよ」 - 「
Button.tsxを規約に沿ってリファクタせよ」
結果
テスト1:新規ファイル作成
| チェック項目 | ALWAYS/NEVER | 理由ベース |
|---|---|---|
| named export を使ったか | ✅ | ✅ |
| Props を interface で定義したか | ✅ | ✅ |
| any を使わなかったか | ✅ | ✅ |
| Tailwind を使ったか | ✅ | ✅ |
| try-catch でエラー処理したか | ✅ | ✅ |
| 関数を20行以内に分割したか | ✅ | ✅ |
結果:完全に同じコードが出力された。 差分ゼロ。
テスト2:既存ファイルのリファクタ
| チェック項目 | ALWAYS/NEVER | 理由ベース |
|---|---|---|
| default → named export に変更 | ✅ | ✅ |
| any → interface に変更 | ✅ | ✅ |
| inline style → Tailwind に変更 | ✅ | ✅ |
こっちもほぼ同じコードが出力された。
これが意味すること
「ALWAYS/NEVER が悪い」は半分嘘だった。
明確なルールなら、どっちの書き方でも AI は従う。ALWAYS use TypeScript も TypeScript を使う。型でバグを早期発見するため。 も、AI にとっては同じ意味。
じゃあなぜ自分の150行ルールは無視されたのか?
本当の原因は3つだった
原因1:既存コードとルールが矛盾していた
ルール:ALWAYS use named exports.
既存コード(80%):export default function ...
AI は ルールより既存コードのパターンを優先する。自分のプロジェクトが default export だらけなのに ALWAYS named export と書いても、AI は既存パターンに引っ張られる。
検証ではわざと「リファクタしろ」と明示したから従ったが、普段の開発では「新しいコンポーネント書いて」としか言わない。そうすると AI は既存コードに合わせる。
ルールを書く前に、既存コードを直す方が先。
原因2:曖昧なルールが大量にあった
ALWAYS follow best practices for error handling.
ALWAYS write clean and maintainable code.
これ、人間に言われても困る。「ベストプラクティスに従え」は AI にとって「好きにしろ」と同じ。
検証で効いたのは try-catch で囲む。エラーを握りつぶさない みたいな具体的な指示。ALWAYS/NEVER 自体が悪いんじゃなくて、中身が曖昧なのが悪い。
原因3:150行がコンテキストを圧迫していた
Cursor のコンテキストは有限(約120k〜200kトークン)。150行のルールが常に数千トークン消費。会話が長くなると、本当に必要なコード情報がルールに押し出される。
後半でルールを忘れるのは AI の記憶力じゃなく物理的な容量制限。
直したこと:150行 → 3ファイル・80行
Before
# .cursorrules(150行、全部 ALWAYS/NEVER)
ALWAYS use TypeScript strict mode.
NEVER use any type.
ALWAYS use named exports.
NEVER use default exports.
ALWAYS use Tailwind CSS.
NEVER use inline styles.
...
After
.cursor/rules/workspace.mdc(プロジェクト情報)
---
description: "プロジェクト全体の規約"
alwaysApply: true
---
## 技術スタック
Next.js 15 / TypeScript 5 / Tailwind v4 / pnpm / Vitest
## コマンド
- 型チェック: pnpm tsc --noEmit
- リント: pnpm lint
- テスト: pnpm test
## フォルダ構成
- コンポーネント → src/components/
- API → src/app/api/
- ユーティリティ → src/lib/
.cursor/rules/typescript.mdc(言語ルール)
---
description: "TypeScript規約"
alwaysApply: true
---
## 型
strict モード。any は避ける、やむを得なければ unknown。
## エクスポート
named export。既存ファイルが default export なら合わせる。
## エラー処理
API呼び出しは try-catch。エラーを握りつぶさない。
## 関数
20行以内。引数3個以内。早期 return。
.cursor/rules/react.mdc(React 固有、.tsx だけ適用)
---
description: "React規約"
globs: "**/*.tsx"
alwaysApply: false
---
## コンポーネント
関数コンポーネント。Props は interface で定義。
## スタイル
Tailwind CSS。inline style は動的な計算値だけ。
何が変わったか
| Before | After | |
|---|---|---|
| ファイル数 | 1 | 3 |
| 行数 | 150 | 80 |
| 適用範囲 | 全ルール常時適用 | ファイル種別で分割 |
| 既存コードとの矛盾 | 考慮なし | 「既存に合わせる」と明記 |
| 曖昧なルール | 多数 | 排除 |
まとめ
検証でわかったこと:
- ALWAYS/NEVER 自体は悪くない。 明確な内容なら理由ベースと同じ結果が出る
- 本当の敵は「曖昧さ」と「既存コードとの矛盾」。 書き方の形式じゃない
- 150行が問題なのは形式ではなく、曖昧なルールがコンテキストを圧迫すること
Anthropic 公式が「ALWAYS/NEVER はイエローフラグ」と言っているのは、ALWAYS/NEVER を使うと曖昧なルールを量産しがちだから。形式そのものが悪いんじゃなくて、思考停止で ALWAYS best practices と書いてしまう人間の癖が悪い。
つまり:
❌ 形式の問題:ALWAYS/NEVER で書くと AI が従わない
✅ 本当の問題:ルールが曖昧 + 既存コードと矛盾 + コンテキスト圧迫
おわりに
水曜にトークンが切れて Cursor を開いた。150行の .cursorrules を書いて無視された。公式ドキュメントを読んで自分が間違っていたと知った。検証して「ALWAYS/NEVER が悪い」も半分嘘だと知った。
80行に書き直したら、前より効くようになった。
金曜にトークンが復活して Claude Code に戻った。でもこの2日間で学んだことは CLAUDE.md にそのまま使えている。
次トークンが切れたら、またCursorに来ます。