Claude Code Skillsの使い方:RustでAIペアプロするときのトークン消費量を減らす

先日Claude Opus4.5の発表資料を見ていたら、AIコーディングとRustはかなり相性がいいらしくて、SWE-benchの成績でRustがJavaに次ぐパス率でした。しかし体感的には、Typescriptでバイブコーディングしてる時の3倍速くらいで5時間リミットに到達しちゃいます。得意なはずなのになぜ……?

今回はClaude CodeのSkills機能をフル活用して、RustでOpusが無双できる環境づくりを紹介したいと思います。

Rustの何が問題なのか

Rustのいいところって「エラーメッセージがわかりやすい」ところなんですけど、AIにとってはcargo buildcargo testの出力が逆にトークンコスト的なネックになったりします。警告1個だけでも5~10行くらい出力されます。

ある程度実装が進んだプロジェクトで、オプション無しでcargo buildするとこんな感じの出力になりますね。

warning: unused import: `Arc`
 --> src/processor.rs:3:5
  |
3 | use std::sync::Arc;
  |     ^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: unused variable: `config`
 --> src/main.rs:42:9
  |
42|     let config = Config::new();
  |         ^^^^^^ help: if this is intentional, prefix it with an underscore: `_config`

...(クソ長デバッグメッセージ)

warning: `my-project` (lib) generated 16 warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.08s

Rustではデフォルトで、あとで使う予定で定義しておいた変数とかも警告になっちゃいます(cfgフラグでスキップもできますけど、いちいちつけたり消したりがめんどくさい)。警告1個で100トークンくらい消費すると仮定すると15個だと1,500トークン。もちろんビルドエラーがあればその分大量にスタックトレースを出してくれます。10~30行程度、300トークンくらいが追加で消費されます。そう、ビルドのたびにです。

テストだともっと量が多くて、400個のユニットテストを実行すると全パスでも12,000トークンくらい消費されます。そう、テストのたびにです。

一般的な開発フローである

  • コード修正
  • ビルドエラー解析
  • コード修正
  • テスト実行
  • テストメッセージ解析
  • テスト修正
  • テスト実行

この1サイクルで2万トークンくらい減ります。当然1サイクルで済むはずもなくて、単純な機能を追加するだけでもcompactが走るレベル=10万トークンを消費することも。

Max5プランで使わせてもらってますが、リファクタリングとかさせると1時間で5時間リミット消化とか稀によくあります。ていうか毎日でした。

AIにとって必要な情報は「ビルド成功したよ」「警告16個あったよ」「このテストが失敗してたよ」「0.08秒かかったよ」くらいなんですよね。そうすると100トークンくらいで済みます。詳細なスタックトレースとかヘルプメッセージは、エラーが出た時だけ改めてそのファイルだけ再実行するのが効率的です。

Skillsでcargo出力をフィルタリングする

Claude CodeにはSkillsという機能があります。前の記事でもGuardrail Skillsの説明はしてたと思いますが、ざっくり言うと「特定のタスクを実行するときに、こういう手順でやってね」というルールセットを定義できる仕組みです。前回のはプロンプトのみでしたが、今回は「このスクリプトを使え」というのを含めてみます。

今回作るものは以下の3つです。

  1. cargo-filter.mjs – Node.jsで動作するパーサ。cargo出力を解析して要点だけ抽出する
  2. SKILL.md – Skillsの定義ファイル
  3. CLAUDE.mdへの追記 – プロジェクトで自動的にSkillを使うようにする

フォルダ構成としてはこんな感じになります。

~/.claude/skills/cargo-runner/
                    ├── SKILL.md
                    └── scripts/
                        └── cargo-filter.mjs

私は全プロジェクトで使いたいのでユーザディレクトリに置いてますけど、プロジェクトの.claude以下に置いてもOKです。

以下、コードも貼っておきますが、ClaudeCodeにこのページのURLを渡して「これ作って」でいけると思います(怠惰)。

1. パーサを作る

まずはcargo出力をパースするNode.jsスクリプトを作ります。Nodeなのは特に深い意味はないですが、ClaudeCodeが動く環境なら間違いなく動くから、くらいの動機です。

#!/usr/bin/env node
/**
 * cargo-filter.mjs - Cargo output filter for Claude Code token optimization
 *
 * Usage:
 *   cargo build 2>&1 | node cargo-filter.mjs --mode build
 *   cargo test 2>&1 | node cargo-filter.mjs --mode test
 *   cargo clippy 2>&1 | node cargo-filter.mjs --mode clippy
 */

import * as readline from 'readline';

// Parse arguments
const args = process.argv.slice(2);
const modeIndex = args.indexOf('--mode');
const mode = modeIndex !== -1 ? args[modeIndex + 1] : 'build';

// State
const state = {
  warnings: new Map(),      // category -> count
  errors: [],               // error messages (max 10)
  testsPassed: 0,
  testsFailed: 0,
  failedTests: [],          // failed test details (max 10)
  duration: null,
  success: true,
  clippyWarnings: new Map() // clippy lint category -> count
};

// Regex patterns
const patterns = {
  warning: /^warning: (.+?)(?:\s*-->|$)/,
  warningSummary: /warning: .+ generated (\d+) warnings?/,
  error: /^error(\[E\d+\])?: (.+)/,
  testOk: /^test (.+) \.\.\. ok/,
  testFailed: /^test (.+) \.\.\. FAILED/,
  testResult: /^test result: (ok|FAILED)\. (\d+) passed; (\d+) failed;/,
  finished: /Finished .+ in ([\d.]+s)/,
  assertion: /assertion .+failed|panicked at/i,
  clippyLint: /^warning: (.+?)\s*$/,
  clippyHelp: /= help: for further information visit .+#(\w+)/
};

// Warning categories
function categorizeWarning(msg) {
  if (msg.includes('unused import')) return 'unused';
  if (msg.includes('never used') || msg.includes('never read')) return 'dead';
  if (msg.includes('field') && msg.includes('never')) return 'field';
  if (msg.includes('unnecessary')) return 'unnecessary';
  if (msg.includes('cast')) return 'cast';
  if (msg.includes('clone')) return 'clone';
  if (msg.includes('format')) return 'format';
  return 'other';
}

// Process a single line
function processLine(line) {
  const errorMatch = line.match(patterns.error);
  if (errorMatch && state.errors.length < 10) {
    state.success = false;
    state.errors.push(errorMatch[2].substring(0, 100));
    return;
  }

  const warnMatch = line.match(patterns.warning);
  if (warnMatch) {
    const cat = categorizeWarning(warnMatch[1]);
    state.warnings.set(cat, (state.warnings.get(cat) || 0) + 1);
    return;
  }

  const clippyMatch = line.match(patterns.clippyHelp);
  if (clippyMatch) {
    const cat = clippyMatch[1];
    state.clippyWarnings.set(cat, (state.clippyWarnings.get(cat) || 0) + 1);
    return;
  }

  if (mode === 'test') {
    if (patterns.testOk.test(line)) {
      state.testsPassed++;
      return;
    }
    const failMatch = line.match(patterns.testFailed);
    if (failMatch) {
      state.testsFailed++;
      state.success = false;
      if (state.failedTests.length < 10) {
        state.failedTests.push(failMatch[1]);
      }
      return;
    }
    const resultMatch = line.match(patterns.testResult);
    if (resultMatch) {
      state.success = resultMatch[1] === 'ok';
      state.testsPassed = parseInt(resultMatch[2]);
      state.testsFailed = parseInt(resultMatch[3]);
      return;
    }
  }

  const finishedMatch = line.match(patterns.finished);
  if (finishedMatch) {
    state.duration = finishedMatch[1];
  }

  if (mode === 'test' && patterns.assertion.test(line) && state.failedTests.length > 0) {
    const lastFailed = state.failedTests[state.failedTests.length - 1];
    if (typeof lastFailed === 'string') {
      state.failedTests[state.failedTests.length - 1] = {
        name: lastFailed,
        reason: line.substring(0, 80)
      };
    }
  }
}

// Generate output
function generateOutput() {
  const parts = [];

  switch (mode) {
    case 'build': {
      parts.push(state.success ? 'BUILD: OK' : 'BUILD: FAIL');
      if (state.duration) parts[0] += ` ${state.duration}`;

      const totalWarnings = Array.from(state.warnings.values()).reduce((a, b) => a + b, 0);
      if (totalWarnings > 0) {
        const cats = Array.from(state.warnings.entries())
          .filter(([_, v]) => v > 0)
          .map(([k, v]) => `${k}:${v}`)
          .join(' ');
        parts.push(`W:${totalWarnings} (${cats})`);
      }

      if (state.errors.length > 0) {
        parts.push(`E:${state.errors.length}`);
        state.errors.forEach(e => parts.push(`  ${e}`));
      }
      break;
    }

    case 'test': {
      const total = state.testsPassed + state.testsFailed;
      if (state.success) {
        parts.push(`TEST: ${total}/${total} PASS`);
      } else {
        parts.push(`TEST: ${state.testsPassed}/${total} PASS`);
      }
      if (state.duration) parts[0] += ` ${state.duration}`;

      if (state.testsFailed > 0) {
        parts.push(`FAIL:${state.testsFailed}`);
        state.failedTests.forEach(t => {
          if (typeof t === 'object') {
            parts.push(`  ${t.name}`);
            parts.push(`    ${t.reason}`);
          } else {
            parts.push(`  ${t}`);
          }
        });
      }
      break;
    }

    case 'clippy': {
      parts.push(state.success ? 'CLIPPY: OK' : 'CLIPPY: FAIL');
      if (state.duration) parts[0] += ` ${state.duration}`;

      const allWarnings = new Map(state.warnings);
      state.clippyWarnings.forEach((v, k) => {
        allWarnings.set(k, (allWarnings.get(k) || 0) + v);
      });

      const totalWarnings = Array.from(allWarnings.values()).reduce((a, b) => a + b, 0);
      if (totalWarnings > 0) {
        const cats = Array.from(allWarnings.entries())
          .filter(([_, v]) => v > 0)
          .sort((a, b) => b[1] - a[1])
          .slice(0, 5)
          .map(([k, v]) => `${k}:${v}`)
          .join(' ');
        parts.push(`W:${totalWarnings} (${cats})`);
      }

      if (state.errors.length > 0) {
        parts.push(`E:${state.errors.length}`);
        state.errors.forEach(e => parts.push(`  ${e}`));
      }
      break;
    }
  }

  return parts.join(' | ').replace(/ \| (\s{2})/g, '\n$1');
}

// Main
const rl = readline.createInterface({
  input: process.stdin,
  terminal: false
});

rl.on('line', processLine);
rl.on('close', () => {
  console.log(generateOutput());
});

やってることはシンプルで、標準入力から1行ずつ読み込んで正規表現でパースし、最後に要約を出力するだけのスクリプトです。

2. SKILLファイルを作成する

次に、Skillsの定義ファイルを作ります。下のコードコピペでもいいですし、Claudeに作らせてもいいでしょう。Windowsの方はNode.jsの実行にフルパスが必要ですので、ユーザフォルダのパスだけ修正して使ってください。

---
name: cargo-runner
description: Rust cargo出力フィルタ(トークン99%削減)
tools:
  - Read
  - Bash
---

# cargo-runner Skill

Rustプロジェクトでcargo build/test/clippyを実行する際、出力をフィルタしてトークン消費を99%削減する。

## 適用条件

- プロジェクトに `Cargo.toml` が存在する
- `cargo build`, `cargo test`, `cargo clippy` を実行する場面

## スクリプト

このスキルに同梱: `scripts/cargo-filter.mjs`

## 使用方法

### Build

```bash
cargo build 2>&1 | node ~/.claude/skills/cargo-runner/scripts/cargo-filter.mjs --mode build
```

### Test

```bash
cargo test 2>&1 | node ~/.claude/skills/cargo-runner/scripts/cargo-filter.mjs --mode test
```

### Clippy

```bash
cargo clippy 2>&1 | node ~/.claude/skills/cargo-runner/scripts/cargo-filter.mjs --mode clippy
```

**Windowsの場合**:
```bash
cargo build 2>&1 | node "C:\Users\{ユーザー名}\.claude\skills\cargo-runner\scripts\cargo-filter.mjs" --mode build
```

## 出力フォーマット

### Build 成功時
```
BUILD: OK 0.08s | W:16 (unused:7 dead:5 field:4)
```

### Build 失敗時
```
BUILD: FAIL | E:2
  cannot find type `Foo` in this scope
  unresolved import `bar`
```

### Test 成功時
```
TEST: 463/463 PASS 13.2s
```

### Test 失敗時
```
TEST: 462/463 PASS 13.2s | FAIL:1
  music_quality::test_xxx
    assertion `left == right` failed
```

### Clippy
```
CLIPPY: OK 1.5s | W:26 (unnecessary_cast:4 clone_on_copy:2 unused:7)
```

このスクリプトのトークン削減効果(Warningのみのケース)

コマンドフィルタなしフィルタあり削減率
build~1,650 tok~15 tok99%
test~12,450 tok~50 tok99.6%
clippy~3,350 tok~80 tok98%

激減してて草。

1回のビルドで1,600トークン節約、テストで12,000トークン節約です。1日に何十回もビルド・テストを繰り返すことを考えると、これはかなり大きい。

3. CLAUDE.mdに追記する

最後に、プロジェクトの CLAUDE.md にSkillを使うよう指示を追記します。グローバルの ~/.claude/CLAUDE.md に書いておけば全プロジェクトで適用されますが、Rustの仕様率が低い人はプロジェクトごとに書くほうがいいのかも。

## Rust Cargo Runner Skill (Token Optimization)

**Rustプロジェクトでは `cargo-runner` skill を使用してトークン消費を99%削減する。**

### 適用条件
- プロジェクトに `Cargo.toml` が存在する
- `cargo build`, `cargo test`, `cargo clippy` を実行する場面

### 使用方法

```bash
# macOS / Linux
cargo build 2>&1 | node ~/.claude/skills/cargo-runner/scripts/cargo-filter.mjs --mode build
cargo test 2>&1 | node ~/.claude/skills/cargo-runner/scripts/cargo-filter.mjs --mode test
cargo clippy 2>&1 | node ~/.claude/skills/cargo-runner/scripts/cargo-filter.mjs --mode clippy

# Windows (Git Bash / PowerShell)
cargo build 2>&1 | node "C:\Users\{ユーザー名}\.claude\skills\cargo-runner\scripts\cargo-filter.mjs" --mode build
```

こうしておくと自動的に`cargo test` `cargo run` `cargo build`でこのスキルが読み込まれて、スクリプトへパイプしてサマリだけが呼び出し元のエージェントへ渡されるわけです。実際の戻り値は下記の感じです。実にシンプル。

BUILD: OK 0.08s | W:16 (unused:7 dead:5)<br>TEST: 462/463 PASS 13.2s | FAIL:1<br>music_quality::test_xxx<br>CLIPPY: OK 1.5s | W:26 (cast:4 clone:2)

実はまだ問題が……

実際のAIペアプロ開発では

  • テスト実行 → 失敗があった
  • テストの出力を解析
  • 修正
  • テスト再実行

ここまでAIが自動的にやっちゃうと思います。2番目の「テストの出力を解析」、これが結局文字量が多くてトークンドカ食いしちゃいます。

今のClaudeCodeはデフォルトがOpus4.5(2025/12現在)、正直エラー出力の解析程度の軽作業をさせるのはコスト的にもったいないですね。これをどうにかしましょう。

テスト実行専用のエージェントを作る

Opusが高いならHaikuを使えばいいじゃない!というわけでtest-runnerというカスタムエージェントを作ります。Claude Codeのカスタムエージェントはあらかじめ使用するモデルを指定できます。

このエージェントはRustに限らずほぼ全部の言語で使えるトークン節約エージェントなので、ユーザグローバルに保存してます。

~/.claude/agents/test-runner.md

---
name: test-runner
description: テスト実行と結果報告に特化したサブエージェント。ユニットテストの大量出力処理でOpusのトークンを節約するために使用。テスト実行、結果解析、簡潔な報告を行う。
tools: Bash, AskUserQuestion, Skill, SlashCommand, KillShell, Read, Grep, Glob
model: haiku
color: green
---

# Test Runner Agent 🧪

テスト実行と結果報告に特化した軽量エージェントです。Haikuモデルを使用してトークンコストを最小化しながら、テスト結果を効率的に処理・報告します。

## 主な用途

- ユニットテストの実行
- 統合テストの実行
- テスト結果の解析と要約
- 失敗テストの特定と報告

## 基本コマンド(言語別)

### JavaScript / TypeScript

```bash
# npm/yarn
npm test
yarn test

# Jest
npx jest                              # 全テスト実行
npx jest path/to/test.ts              # 特定ファイル
npx jest --testNamePattern="テスト名"  # 特定テスト
npx jest --watchAll=false             # Watchモードなし
npx jest --coverage                   # カバレッジ付き
npx jest --verbose                    # 詳細出力
npx jest --bail                       # 失敗時に即停止
npx jest --maxWorkers=2               # 並列数制限

# Vitest
npx vitest run                        # 全テスト実行
npx vitest run path/to/test.ts        # 特定ファイル
npx vitest run --reporter=verbose     # 詳細出力

# Mocha
npx mocha                             # 全テスト実行
npx mocha path/to/test.js             # 特定ファイル
npx mocha --grep "テスト名"            # 特定テスト
```

### Python

```bash
# pytest
pytest                                # 全テスト実行
pytest path/to/test_file.py           # 特定ファイル
pytest -k "test_name"                 # 特定テスト
pytest -v                             # 詳細出力
pytest --cov=src                      # カバレッジ付き
pytest -x                             # 失敗時に即停止
pytest -n auto                        # 並列実行 (pytest-xdist)

# unittest
python -m unittest discover           # 全テスト実行
python -m unittest path.to.test_module  # 特定モジュール
python -m unittest -v                 # 詳細出力
```

### Rust

```bash
# cargo test
cargo test                            # 全テスト実行
cargo test test_name                  # 特定テスト
cargo test --package package_name     # 特定パッケージ
cargo test -- --nocapture             # 出力を表示
cargo test -- --test-threads=1        # シングルスレッド
cargo test --release                  # リリースモード
```

### Go

```bash
# go test
go test ./...                         # 全テスト実行
go test ./path/to/package             # 特定パッケージ
go test -run TestName                 # 特定テスト
go test -v ./...                      # 詳細出力
go test -cover ./...                  # カバレッジ付き
go test -race ./...                   # レースコンディション検出
go test -count=1 ./...                # キャッシュ無効化
```

### Java

```bash
# Maven
mvn test                              # 全テスト実行
mvn test -Dtest=TestClassName         # 特定クラス
mvn test -Dtest=TestClassName#methodName  # 特定メソッド
mvn test -DfailIfNoTests=false        # テストなしでも失敗しない

# Gradle
./gradlew test                        # 全テスト実行
./gradlew test --tests "TestClassName"  # 特定クラス
./gradlew test --info                 # 詳細出力
./gradlew test --fail-fast            # 失敗時に即停止
```

### C# / .NET

```bash
# dotnet test
dotnet test                           # 全テスト実行
dotnet test --filter "FullyQualifiedName~TestName"  # 特定テスト
dotnet test --logger "console;verbosity=detailed"   # 詳細出力
dotnet test --collect:"XPlat Code Coverage"         # カバレッジ
```

### Ruby

```bash
# RSpec
bundle exec rspec                     # 全テスト実行
bundle exec rspec path/to/spec.rb     # 特定ファイル
bundle exec rspec -e "test name"      # 特定テスト
bundle exec rspec --format documentation  # 詳細出力

# Minitest
ruby -Itest test/test_file.rb         # 特定ファイル
rake test                             # 全テスト実行
```

### PHP

```bash
# PHPUnit
./vendor/bin/phpunit                  # 全テスト実行
./vendor/bin/phpunit path/to/Test.php # 特定ファイル
./vendor/bin/phpunit --filter testName  # 特定テスト
./vendor/bin/phpunit --testdox        # 詳細出力
./vendor/bin/phpunit --coverage-text  # カバレッジ
```

### 共通オプションパターン

| 目的 | 一般的なフラグ |
|------|---------------|
| 詳細出力 | `-v`, `--verbose`, `--info` |
| 失敗時停止 | `-x`, `--bail`, `--fail-fast` |
| 特定テスト | `-k`, `--filter`, `--grep`, `-t` |
| カバレッジ | `--coverage`, `--cov`, `--collect` |
| 並列実行 | `-n`, `--parallel`, `--maxWorkers` |

## 報告フォーマット

### 成功時の報告

```
✅ テスト結果: 全て成功

実行: XX テスト
成功: XX
失敗: 0
スキップ: 0
実行時間: X.XXs
```

### 失敗時の報告

```
❌ テスト結果: 失敗あり

実行: XX テスト
成功: XX
失敗: X
スキップ: X
実行時間: X.XXs

--- 失敗詳細 ---

1. テストファイル: path/to/test.ts
   テストケース: "テスト名"
   エラー: エラーメッセージの要約
   期待値: expected
   実際値: received

2. ...
```

## 操作プロトコル

### 1. テスト実行前

- テスト対象のスコープを確認
- 必要に応じてテストファイルの存在確認
- 依存関係が最新か確認(必要時)

### 2. テスト実行中

- コマンドを実行し、完了を待機
- 出力をキャプチャ

### 3. テスト実行後

- 結果を解析
- 成功/失敗数を集計
- 失敗がある場合は詳細を抽出
- 簡潔なサマリーを生成

## エラーハンドリング

### コンパイルエラー

```
🔴 コンパイルエラー

ファイル: path/to/file.ts
行: XX
エラー: エラーメッセージ
```

### タイムアウト

```
⚠️ テストタイムアウト

テスト: "テスト名"
タイムアウト時間: XXms
推奨: --testTimeout オプションの調整を検討
```

### 環境エラー

```
🔴 環境エラー

問題: エラーの説明
推奨対処: 具体的なアクション
```

## トークン効率のためのガイドライン

1. **出力の要約**: 大量のテスト出力は要約して報告
2. **必要な情報のみ**: 失敗時のスタックトレースは関連部分のみ抽出
3. **構造化レポート**: 読みやすい構造化フォーマットで報告
4. **不要な詳細の省略**: 成功したテストの詳細は省略

## 呼び出し元への報告

親エージェント(Opus)への報告時は以下を含める:

1. **結果サマリー**: 成功/失敗/スキップ数
2. **失敗詳細**(ある場合): ファイル、テスト名、エラー概要
3. **推奨アクション**(必要時): 修正が必要な箇所の提案

## 制限事項

このエージェントは以下を行いません:

- ❌ コードの修正
- ❌ 新規テストの作成
- ❌ アーキテクチャの提案
- ❌ 複雑な分析

これらが必要な場合は、親エージェントに報告して対応を委譲してください。

CLAUDE.mdに、このサブエージェントを使うように指示追加して終わり。

## Sub-agent Strategy

**Use Haiku model sub-agents for simple tasks to minimize token consumption:**

- **test-runner**: Run tests and report results
- **Explore**: Quick file/code searches
- **documentor**: Create/update documentation

When launching Task tool, specify `"model": "haiku"` for:
- Test execution
- Simple searches (grep, glob patterns)
- Documentation lookups
- Repetitive/mechanical tasks

Reserve Opus/Sonnet for:
- Complex multi-step implementations
- Architectural decisions
- Code review requiring deep analysis

こうしておくと、Claudeは「テスト実行するか」ってなったときに自動的に軽量なtest-runnerエージェントを立ち上げてくれます。

  • テスト実行(Haiku) → 失敗
  • 失敗したファイルを抽出(Haiku)
  • 本体で該当ファイルを調査・修正(Opus)

というワークフローが出来上がります。これでOpus氏にはコーディングに専念してもらう事ができます。

おまけ:AI用の時間見積もりガイドライン

必須じゃないけどCLAUDE.mdに書いておくと便利なやつを共有しておきます。AIに「この計画の作業見積もりをお願いします」と聞いたときに、AI基準の時間で答えてくれるようになります。(AI時間はモデルが更新されたら変えていったほうがいいでしょう。下記の例はOpus4.5での時間)

## AI Time & Token Estimation Guidelines

### AI vs Human Time Conversion

- **Human 1 hour** ≈ **AI 3-5 minutes** (straightforward implementation)
- **Human 2-3 hours** ≈ **AI 8-15 minutes** (complex features with tests)
- **Human debugging** ≈ **AI 1-2 minutes** (immediate compilation checks)

### Token Usage Estimates

- Reading code: 50-300 tokens/file
- Writing code: 300-2000 tokens/implementation
- Tests: 150-400 tokens/suite
- Error fixes: 200-500 tokens/iteration

### Task Token Budgets

- Small feature (<200 lines): 2k-5k tokens
- Medium feature (200-500 lines): 5k-10k tokens
- Large feature (500-1000 lines): 10k-20k tokens

プランニングの段階で「このタスクは推定16kトークンです」みたいに消費トークンも提示してくれます。「今日のトークンリミットで完了できそうなところまでのプランに変更」という指示もできるようになりますので、作業途中でトークンオーバーでCI/CD通らなくて帰れないみたいな事故は減ります。

まとめ

  1. cargo出力をフィルタするNode.jsスクリプトを作成 – 成功/失敗と要約だけを出力
  2. Skills定義ファイルを作成 – Claude Codeに使い方を教える
  3. CLAUDE.mdに追記 – 自動的にSkillを使うよう指示
  4. Haikuサブエージェントを活用 – テスト実行などの単純作業は軽量モデルに任せる

これで、Rustプロジェクトでのトークン消費を劇的に削減できます。特にテストが多いプロジェクトだと効果テキメンです。

バイブコーディングは気持ちいいですが、お財布には優しくありたいですよね。Skillsをうまく活用して、効率的にコーディングしていきましょう。

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です