前回の計画編では、移行の方針とフェーズ設計を紹介しました。本記事では、計画を実際に自律実行するためのフレームワーク設計を解説します。


全体アーキテクチャ

自律移行の仕組みは、大きく 3 つのレイヤーで構成されています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
┌─────────────────────────────────────────────────────┐
│  オーケストレーション層: run-issue.sh             │
│  - Issue 読み込み → ブランチ作成 → Claude 起動    │
│  - リトライ → Push → PR 作成 → マージ → Issue 閉じ │
└──────────────────┬──────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│  実行層: Claude Code (claude -p)                 │
│  - ソースコード調査 → 設計 → 実装 → テスト        │
│  - コミット(push はしない)                      │
│  - サブエージェント: explorer / architect / reviewer│
└──────────────────┬──────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│  品質保証層: Hooks + CI + verify-phase.sh        │
│  - Pre-commit: ruff format + check              │
│  - PostToolUse: 編集時の即座リント               │
│  - CI: lint → Django check → pytest             │
│  - Phase 検証: ファイル存在 + 機能チェック        │
└─────────────────────────────────────────────────────┘

責務分離の原則

最も重要な設計原則は、ワークフロー制御と実装作業の責務分離です。

責務担当理由
ブランチ作成・切替スクリプト確定的に実行する必要がある
git pushスクリプトタイミングを制御する必要がある
PR 作成・マージスクリプトワークフローの一部
Issue クローズスクリプト完了判定はスクリプトが行う
コード実装Claude Code創造的判断が必要
テスト作成Claude Code実装と一体
コミットClaude Codeこまめにコミットさせる
コードレビューClaude Code(サブエージェント)品質チェック

この分離が不十分だったことが後述の「ブランチ分岐問題」の根本原因でした。


run-issue.sh の設計

約 800 行の Bash スクリプトで、Issue 単位の自律実行を制御します。

実行フロー

1
./scripts/run-issue.sh <issue_number>
1
2
3
4
5
6
7
8
1. GitHub Issue を読み込み(gh issue view)
2. 依存 Issue の完了チェック
3. feature ブランチを作成(main から分岐)
4. Claude Code を起動(claude -p <prompt>)
5. 完了判定(コミット有無 + テスト結果)
6. 失敗時: 最大 3 回リトライ(10 秒クールダウン)
7. 成功時: push → PR 作成 → マージ → Issue 閉じ
8. 実行ログを execution.md に追記

バッチ実行

1
2
./scripts/run-issue.sh all    # 全 Issue を順次実行
./scripts/run-issue.sh resume # 中断した Issue から再開

all モードでは、Issue の依存関係を解決しながら順次実行します。前の Issue が失敗したら停止し、手動介入を待ちます。

リトライ機構

Claude Code のセッションは非決定的です。同じプロンプトでも異なる結果になり得ます。リトライ時には前回の失敗情報をコンテキストとして渡します:

1
2
3
4
# リトライ時のプロンプト(概念)
"前回の実行が失敗しました。
git status, git diff, git log を確認し、
前回の作業状態を把握してから再開してください。"

実際に 15 Issue 中 8 Issue がリトライを経験しましたが、全て 2〜3 回目で成功しています。


Claude Code に渡すプロンプトの設計

run-issue.sh が Claude Code を起動する際のプロンプトは約 360 行で、以下のステップで構成されています。

10 ステップの作業指示

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Step 1: Issue を読む(gh issue view で全文取得)
Step 2: ソースコード調査(feature-dev:code-explorer サブエージェント)
Step 3: 設計(feature-dev:code-architect サブエージェント、複雑な場合)
Step 4: 実装(Django のベストプラクティスに従う)
Step 5: テスト作成(pytest-django)
Step 6: 品質チェック(ruff format + check + Django check)
Step 7: コードレビュー(feature-dev:code-reviewer サブエージェント)
Step 8: 指摘事項の修正
Step 9: verify-phase.sh の実行
Step 10: execution.md への記録

サブエージェントの活用

Claude Code には「サブエージェント」機能があり、メインの Claude とは別のコンテキストで専門的なタスクを実行できます。本プロジェクトでは 3 種類を活用しました:

code-explorer: Laravel のソースコードを深く調査し、移植すべきビジネスロジックを特定

「Laravel の ContractController を調査し、
 全メソッドのビジネスロジックを整理してください」

code-architect: 複雑な機能の設計方針を決定

「28 フィールドの検索フォームを Django で実装する
 最適なアーキテクチャを設計してください」

code-reviewer: 実装済みコードのセキュリティ・品質レビュー

「変更されたファイルをレビューし、
 セキュリティ問題・ロジックエラーを報告してください」

権限管理

Claude Code の権限は .claude/settings.json で制御します。自律実行に必要な操作のみをホワイトリストで許可しました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "permissions": {
    "allow": [
      "Bash(git *)",
      "Bash(docker compose *)",
      "Bash(uv run *)",
      "Bash(gh issue view *)",
      "Read", "Edit", "Write", "Glob", "Grep"
    ]
  }
}

ただし、CLAUDE.md の禁止事項で git push / git branch / gh pr create を禁止しているため、実質的には「読み取り + 実装 + コミット」に限定されます。


品質保証の実装

Pre-commit Hook

1
2
3
4
5
6
7
8
#!/bin/bash
# .githooks/pre-commit
STAGED_PY=$(git diff --cached --name-only --diff-filter=d -- '*.py')
[ -z "$STAGED_PY" ] && exit 0

uv run ruff format $STAGED_PY
uv run ruff check --fix $STAGED_PY
git add $STAGED_PY

Claude Code がコミットするたびに自動フォーマット + lint 修正が走ります。

PostToolUse Hook

Claude Code 固有の機能で、Edit や Write ツールが実行されるたびにフック関数が呼ばれます。

1
2
3
4
#!/bin/bash
# .claude/hooks/post-edit-lint.sh
# Claude が Python ファイルを編集するたびに ruff check を実行
uv run ruff check "$FILE_PATH"

これにより、コミット前の段階でスタイル違反を検出・フィードバックできます。

verify-phase.sh

各フェーズ完了後の検証チェックリスト:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/bash
# scripts/verify-phase.sh <issue_number>

echo "=== Phase 検証開始 ==="

# 共通チェック
check "git 状態がクリーン" git diff --quiet HEAD
check "ruff format" uv run ruff format --check .
check "ruff check" uv run ruff check .
check "Django check" uv run python manage.py check
check "マイグレーション整合性" uv run python manage.py makemigrations --check --dry-run

# Phase 固有チェック(ファイル存在確認など)
case $ISSUE in
  2) check "masters/models.py が存在" test -f masters/models.py ;;
  5) check "accounts/middleware.py が存在" test -f accounts/middleware.py ;;
  # ...
esac

# テスト実行
check "pytest 全パス" uv run pytest

GitHub Actions CI

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# .github/workflows/ci.yml
jobs:
  lint:
    steps:
      - run: uv run ruff format --check .
      - run: uv run ruff check .

  django-check:
    needs: lint
    services:
      mysql: { image: mysql:8.0 }
    steps:
      - run: uv run python manage.py check
      - run: uv run python manage.py makemigrations --check --dry-run

  test:
    needs: django-check
    steps:
      - run: uv run pytest

Docker 環境

開発環境は Docker Compose で完結させ、Claude Code が Docker 内で動作確認できるようにしました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# docker-compose.yml
services:
  db:
    image: mysql:8.0
    volumes:
      - ./docker/mysql/init/001-dump.sql:/docker-entrypoint-initdb.d/001-dump.sql
    # ↑ 既存 DB ダンプを初回起動時に自動リストア

  app:
    build: .
    depends_on:
      db: { condition: service_healthy }
    volumes:
      - .:/app  # ライブリロード用

  nginx:
    image: nginx:alpine
    ports: ["8080:80"]

41MB の本番 DB ダンプを docker/mysql/init/ に配置し、docker-compose up だけで既存データ入りの環境が立ち上がります。Claude Code は docker compose exec app pytest でテスト実行、docker compose exec app python manage.py check で Django チェックを行えます。


実行ログの自動記録

execution.md にタイムスタンプ付きの実行ログを自動記録します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
### Issue #2: マスタ系モデル定義
- 開始: 2026-03-26 12:18:50
- リトライ 2: 2026-03-26 12:31:22
- 完了: 2026-03-26 12:33:21
- 所要時間: 14分32秒
- 試行回数: 2
- 結果: 成功

#### 作業内容
- inspectdb で全テーブルのモデル雛形を自動生成
- マスタ系 10 モデルを分類・整理
- ForeignKey リレーション設定
- Django Admin に登録
...

「作業内容」と「成果物」のセクションは Claude Code 自身が記述します。スクリプトはタイムスタンプと結果のみを書き込みます。


設計で重視したこと

1. 冪等性

リトライ時に副作用が蓄積しないよう設計。ブランチが既に存在すれば再利用、コミットが既にあれば追加のみ。

2. 障害の局所化

1 つの Issue が失敗しても他に影響しない。各 Issue は独立したブランチで作業し、main にマージされるまで他の Issue に影響しません。

3. 可観測性

実行ログ・git log・GitHub Issue/PR のコメントで、何が起きたかを事後に追跡可能。

4. 中断耐性

「こまめなコミット」を指示することで、Claude Code のセッションが中断しても未コミットの変更を最小化。実際に中断からの復旧に成功したケースがありました。


次回予告

自動化基盤編では「どう動かすか」の設計を解説しました。

次の実行結果・教訓編では、実際に 15 Issue を自律実行した結果 — 成功パターン、発生した問題(ブランチ分岐問題)、そして次回のプロジェクトに活かすべき教訓を紹介します。