ヘッドレスサイトのデプロイ前パイプラインをClaudeサブエージェントで再構築した

クライアント向けのヘッドレスサイトを配信する際、Core Web Vitals、スキーママークアップ、アクセシビリティスコア、オーガニックトラフィックの増減など、あらゆることを測定するクライアントと付き合っている。1回の悪いデプロイで、数ヶ月かけて構築したランキングが台無しになる可能性がある。そのため、AnthropicがClaudeコードにサブエージェント、フック、スキルを導入したとき、デプロイ前パイプライン全体をこれらを中心に再構築した。

このポストでは、正確なセットアップを歩み、.claude/ディレクトリ構造、各サブエージェントの定義、フック設定、すべてを結びつけるスキルファイルを紹介する。システムが検出した4つの実際のインシデント、現在の規模でのROI計算、およびこのアプローチにはどのようなギャップがあるかについても共有する。

CLS スパイク 40% が本番環境にまで到達してしまった

3週間前のことだ。クライアントのブログ再設計。開発環境ではすべてが問題ないように見えた。マージした。

2日後、クライアントのCTOがSearch Consoleのスクリーンショットを送ってきた。CLSがモバイルで0.08から0.14に跳ね上がった。「enterprise billing software」で3位にランクしていたページが8位まで落ちた。収益への影響?月間$40,000と見積もられた。

問題は何か?非同期で読み込まれるが、サイズ属性がないヒーロー画像。よくあることだ。実際のプレビュービルドでレイアウトシフトをチェックしていなかったため、CIは何も検出しなかった。

それがサブエージェントを検討し始めるきっかけになった。

サブエージェントはスコープを限定したClaudeコードインスタンスで、親セッション内で独自のシステムプロンプト、ツールアクセス、タスク境界を持って実行される。フックはコマンド実行前、ファイル変更後、コミット時など、特定のポイントでサブエージェントをトリガーする。スキルは再利用可能な命令ファイル(マークダウン)で、Claudeに特定のタスクを実行する方法を教える。

Anthropicは2025年4月14日にルーチンをこれらのプリミティブと共に導入した。当社のユースケースでは、生のサブエージェントとフックにより、各チェックがいつ実行され、どのようなコンテキストを受け取るかをより細かく制御できた。

従来のCIチェックとの主な違い:サブエージェントは結果について推論でき、複数のチェック間で失敗を相関させ、人間が読める要約を書くことができる。CIジョブは終了コード0または1を返す。サブエージェントは「/blog/[slug]上の構造化データが、以前のビルドに存在していたdateModifiedフィールドを欠いています。これはGoogle Search Console内で3~5日以内にリッチスニペットの回帰を引き起こす可能性があります」と返す。

それが全てだ。

3か月後、GitHubActionsセットアップがついに破綻した

これまでのパイプラインはGitHub ActionsがLighthouse CI、pa11y、linkinator、カスタムNode スクリプトを呼び出すごちゃごちゃなものだった。うまく機能していた。

ほぼ。

しかし3つの問題があった。

チェック間の推論がない。 Lighthouseが CLS 問題にフラグを立て、アクセシビリティスキャンが同じ画像の欠落した alt タグにフラグを立てた場合、接続のない2つの別個のアラートが得られた。エンジニアは手動でCIログをgrep、タイムスタンプを相関させ、同じコンポーネントであることを理解する必要があった。

時間の無駄だ。

設定が脆い。 各ツールに独自の設定ファイル、閾値形式、出力スキーマがあった。閾値を更新するには4~6ファイルに触れる必要があった。ここではYAML。そこではJSON。別の場所では環境変数。1つのタイプミスでパイプライン全体が失敗すべきときに0で終了する。

文脈的な説明がない。 エンジニアは合格/不合格を受け取った。ジュニア開発者はなぜ何かが失敗し、何をすべきかを理解するのに20~40分かかった。「アクセシビリティスコア:87」では、どのARIA属性が欠落しているか、またはスクリーンリーダーにとってそれが重要な理由を示さない。

Slack でひとつの失敗を説明するのに週3時間費やすことになった。

最後の一撃は2025年8月。金曜日の午後4時にNorthwind Traders再設計をプッシュした(分かる)。Lighthouseに合格。アクセシビリティに合格。リンクに合格。デプロイした。

月曜日の朝、マーケティング副社長からメールが届いた。「なぜ製品ページがGoogleから消えているのか?」/products/配下のすべてのページでrobotsメタを誤ってnoindexに設定していたことが判明した。CIは robots タグをチェックしなかった。再インデックスに6日かかった。推定収益損失は$12,000。

別のCIツールは不要だった。すでに信頼している既存ツールの出力を推論できるオーケストレーション層が必要だった。よく書かれたスキルファイルは、アクセシビリティルールをハルシネートするサブエージェントと正しいフラグでpa11yを実行し、JSON出力を解釈するサブエージェントの違いだ。

.claude/ ディレクトリ構造

実際のツリーはこうだ:

.claude/
├── settings.json
├── agents/
│   ├── seo-regression.md
│   ├── cwv-smoke.md
│   ├── accessibility.md
│   ├── broken-links.md
│   ├── schema-validation.md
│   └── deploy-gate.md
├── skills/
│   ├── run-lighthouse.md
│   ├── run-pa11y.md
│   ├── run-linkinator.md
│   ├── parse-schema-org.md
│   ├── compare-seo-snapshot.md
│   └── format-deploy-report.md
└── snapshots/
    └── seo-baseline.json

snapshots/ディレクトリには比較チェック用のベースラインデータが保持される。シンプルだ。Git でバージョン管理するので、クライアントが「先週火曜日になぜランキングが下がったのか?」と聞くときに何が変わったかを見ることができる。

派手なことは何もない。マークダウンファイルとJSON だけだ。

あるクライアントが夜11時に電話してきた、Googleがすべてのリッチスニペットを削除してしまったと

2025年9月。中堅小売業者向けのeコマースサイトを構築していた(Acme Home Goodsと呼ぼう)。6か月かけてリッチスニペット――製品の星、価格設定、在庫――が検索結果に表示されるようにしていた。

Shopifyテーマアップデートをプッシュ。問題ないように見える。金曜夜にデプロイされた。

土曜日午後11時14分にテキストが入った。「製品ページがGoogleで壊れているように見える。星がない。価格がない。どうなった?」

Search Consoleを開く。すべての製品ページが構造化データエラーをスローしている。offersフィールドにpriceCurrencyがない。これがないと、Googleはリッチスニペットを表示しない。ランキングは落ちなかったが、クリック率は夜間に4.2%から1.8%に低下した。

コスト?修正してGoogleが再クロールするまで、週あたり約$8,000のトラフィック損失。

スキーマはそこにあった。Shopify APIがそのキーを使用しているため、プロパティ名をpriceCurrencyからcurrencyに変更しただけだ。深く考えなかった。バリデーションがそれをキャッチしなかった。

そこでスキーマバリデーションサブエージェントを構築した。

.claude/agents/内にマークダウンファイルを作成し、システムプロンプト、許可されたツールのリスト、タスク命令を記述する。親セッション(またはフック)はdispatch_agent()経由か、settings.json内のフック設定経由でそれをスポーンする。

最小限の構造:

# Agent: [Name]

## Role
[1行の説明]

## Allowed Tools
- Bash(特定のコマンドに制限)
- ファイルを読む
- ファイルを書く

## Instructions
[段階的なタスク説明、スキルファイルを参照]

## Output Format
[親が期待する正確な形式]

出力形式について非常に具体的である。デプロイゲートオーケストレーターがpassedブール値とsummary文字列を持つJSONを期待する場合、それを明記しろ。自由形式のテキストを返すサブエージェントはオーケストレーションを破壊する。マークダウンテーブルを返すサブエージェントがあったときにこれを学んだ。親はそれを解析できず、デプロイブロックをトリガーしなかった。エラーなし。黙ってただ失敗した。朝2時にデバッグするのに2時間かかった。

私の失敗を繰り返すな。形式をロックダウンしろ。

サブエージェント1:SEOリグレッション チェック

これは現在のビルドのSEO重要要素をベースラインスナップショットと比較する。

# Agent: SEO Regression Check

## Role
現在のビルドと保存されたベースラインの間でSEOリグレッションを検出します。

## Allowed Tools
- Bash(nodeスクリプトのみ)
- ファイルを読む

## Instructions
1. .claude/skills/compare-seo-snapshot.mdのスキルファイルを読む
2. 実行: node scripts/extract-seo-meta.js --url=$PREVIEW_URL --output=/tmp/seo-current.json
3. .claude/snapshots/seo-baseline.jsonを読む
4. 2つのスナップショットをフィールドごとに比較:
   - titleタグ(完全一致)
   - metaディスクリプション(類似度> 0.85)
   - canonicalURL(完全一致)
   - h1カウント(ページあたり1つである必要がある)
   - robots meta(noindexに変更されていないこと)
   - OpenGraphタグ(og:title、og:description、og:image が存在)
5. robotsが noindex に変更されたページは CRITICAL としてフラグを立てる。
6. 欠落または重複したタイトルタグは HIGH としてフラグを立てる。
7. メタディスクリプション変更が15%以上異なる場合は MEDIUM としてフラグを立てる。

## Output Format
{"passed": boolean, "critical": [], "high": [], "medium": [], "summary": string}

extract-seo-meta.jsスクリプトは、サイトマップ内のすべてのページにアクセスし、タイトル、メタ、canonicals、h1s、およびOGタグをJSONにダンプする120行のPuppeteerだ。スマートなことは何もない。抽出だけだ。

サブエージェントの値は、抽出ではなく、比較と推論にある。どの変更が重要かを知っている。どれが化粧品的か。どれがクライアント四半期あたり$15,000のオーガニックトラフィックを失わせるか。

例:メタディスクリプションを「Best CRM software for small businesses in 2025」から「Best CRM software for small business」に変更する場合、類似度スコアは0.91だ。大丈夫だ。しかし「CRM software」に変更すると、類似度は0.65に低下する。サブエージェントは MEDIUM としてフラグを立てる。なぜなら、それはキーワード密度を40%削減し、CTRに害を及ぼす可能性があるからだ。

diff ではなく、その diff が意味するものについての推論だ。

これまでのところ、4つの問題をこれで検出した。robots noindex のことだ。誰かがすべてのOG画像を削除したケース(ソーシャル シェアを台無しにしていただろう)。タイトルタグが60文字の代わりに40文字に切り詰められたケース(見た目が悪いだけで、SEOに害はなかったが、クライアントは気づいていただろう)。canonical URL がhttps://からhttp://に変更されたケース(複製コンテンツペナルティを引き起こしていただろう)。

それぞれがクリーンアップに少なくとも数時間とクライアント信頼の費用がかかっていただろう。多分もっと多く。

seo-baseline.jsonをリポジトリに保存し、デプロイ成功フックの一部として更新する。

サブエージェント2:Core Web Vitals スモークテスト

# Agent: CWV Smoke Test

## Role
主要ページでLighthouseを実行し、CWVリグレッションにフラグを立てます。

## Allowed Tools
- Bash

## Instructions
1. .claude/skills/run-lighthouse.mdを読む
2. これらのページに対して$PREVIEW_URLに対してLighthouse CIを実行:
   - /(ホームページ)
   - /blog/(リスティング)
   - /blog/[most-recent-post](詳細)
   - /services/(存在する場合)
3. 閾値(以下の場合は失敗):
   - LCP:2500ms
   - FID/INP:200ms
   - CLS:0.1
   - パフォーマンススコア:85
   - アクセシビリティスコア:90
4. メトリックが前回の実行から10%以上悪化した場合、
   閾値を超えていてもWARNINGとしてフラグを立てる。
5. Lighthouseが報告するLCPまたはCLSを引き起こしている特定の要素を含める。

## Output Format
{"passed": boolean, "pages": [{"url": string, "scores": {}, "flags": []}], "summary": string}

関連するスキルファイル(run-lighthouse.md)には正確なlhciCLIの呼び出しが含まれている:

# Skill: Run Lighthouse

## Command
```bash
npx @lhci/cli@0.14.0 collect \
  --url="$1" \
  --numberOfRuns=3 \
  --settings.preset=desktop \
  --settings.output=json \
  --settings.outputPath=/tmp/lhci-results/

Parsing

/tmp/lhci-results/から中央値の実行を読む。以下を抽出:

  • categories.performance.score * 100
  • audits['largest-contentful-paint'].numericValue
  • audits['cumulative-layout-shift'].numericValue
  • audits['interaction-to-next-paint'].numericValue(存在する場合)

## サブエージェント3:アクセシビリティスキャン

```markdown
# Agent: Accessibility Scan

## Role
プレビューURLに対してpa11yを実行し、WCAG 2.1 AA違反を報告します。

## Allowed Tools
- Bash

## Instructions
1. .claude/skills/run-pa11y.mdを読む
2. CWVエージェントと同じページセットに対してpa11yを実行。
3. 結果を重大度別に分類:error、warning、notice。
4. 各エラーについて、以下を含める:
   - 違反されたWCAG基準(例:1.1.1非テストコンテンツ)
   - HTML要素(セレクタ)
   - 1文の修正提案
5. エラーが存在する場合は失敗。警告> 10の場合は警告。

## Output Format
{"passed": boolean, "error_count": number, "warning_count": number, "errors": [{"criterion": string, "selector": string, "fix": string}], "summary": string}

--runner=axeフラグでpa11y@8.0.0を使用する。デフォルトのhtmlcsランナーはaxeがキャッチするいくつかの色コントラスト問題を見落とす。

サブエージェント4:壊れたリンク スキャン

# Agent: Broken Link Scan

## Role
プレビューサイトをクロールし、壊れた内部および外部リンクを報告します。

## Allowed Tools
- Bash

## Instructions
1. .claude/skills/run-linkinator.mdを読む
2. 実行: npx linkinator@6.1.2 $PREVIEW_URL --recurse --timeout 15000 --format json > /tmp/link-results.json
3. 結果をステータス>= 400またはステータス=== 0(タイムアウト)にフィルタリング。
4. 内部(同じドメイン)と外部の壊れたリンクを分離。
5. 内部の壊れたリンクはCRITICAL。外部の壊れたリンクはWARNING。
6. 既知の不安定な外部ドメインを除外:twitter.com、linkedin.com(クローラーをブロック)。

## Output Format
{"passed": boolean, "internal_broken": [{"source": string, "target": string, "status": number}], "external_broken": [...], "summary": string}

サブエージェント5:スキーマ バリデーション

# Agent: Schema Validation

## Role
すべてのページでJSON-LD構造化データを検証します。

## Allowed Tools
- Bash
- ファイルを読む

## Instructions
1. .claude/skills/parse-schema-org.mdを読む
2. サイトマップ内の各ページについて:
   a. すべての<script type="application/ld+json">ブロックを抽出
   b. JSONとして解析(形式が正しくない場合は失敗)
   c. @typeごとの必須フィールドを検証:
      - Article:headline、datePublished、dateModified、author、image
      - LocalBusiness:name、address、telephone
      - WebPage:name、description
      - BreadcrumbList:position、name、itemを持つitemListElement
   d. すべての@idリファレンスがページのグラフ内で解決されることを確認
   e. スキーマ内のURLが相対的ではなく絶対的であることを検証
3. 欠落している必須フィールドはHIGHとしてフラグ。
4. 形式が正しくないJSONはCRITICALとしてフラグ。

## Output Format
{"passed": boolean, "pages": [{"url": string, "schemas": [{"type": string, "valid": boolean, "issues": []}]}], "summary": string}

サブエージェント6:デプロイゲート オーケストレーター

この親エージェントは他の5つをスポーンし、go/no-go 判定を下す。

# Agent: Deploy Gate

## Role
すべてのデプロイ前チェックをオーケストレーションし、最終的なデプロイ判定を実施します。

## Allowed Tools
- Bash
- ファイルを読む
- ファイルを書く
- dispatch_agent

## Instructions
1. これらのエージェントを並列でスポーン:
   - .claude/agents/seo-regression.md
   - .claude/agents/cwv-smoke.md
   - .claude/agents/accessibility.md
   - .claude/agents/broken-links.md
   - .claude/agents/schema-validation.md
2. すべての出力を収集。
3. .claude/skills/format-deploy-report.mdを読む
4. 判定ロジック:
   - いかなるエージェントもCRITICALフラグを持つ場合:デプロイをBLOCK。
   - 2個以上のエージェントがHIGHフラグを持つ場合:デプロイをBLOCK。
   - 1個のエージェントがHIGHフラグを持つ場合:WARN、手動オーバーライドが必要。
   - それ以外:APPROVE。
5. 完全なレポートを/tmp/deploy-report.mdに書き込む。
6. 判定を出力。

## Output Format
{"decision": "APPROVE" | "WARN" | "BLOCK", "reports": {agent_name: agent_output}, "summary": string}

フック設定:settings.json

これが実際のsettings.jsonだ(クライアント固有のURLは編集済み):

{
  "hooks": {
    "pre-commit": [
      {
        "agent": ".claude/agents/schema-validation.md",
        "condition": "files_changed_match('**/*.json', '**/structured-data/**')",
        "env": {
          "PREVIEW_URL": "http://localhost:3000"
        }
      }
    ],
    "pre-push": [
      {
        "agent": ".claude/agents/deploy-gate.md",
        "env": {
          "PREVIEW_URL": "$VERCEL_PREVIEW_URL"
        },
        "timeout": 300,
        "on_failure": "block"
      }
    ],
    "post-deploy-success": [
      {
        "command": "node scripts/extract-seo-meta.js --url=$PRODUCTION_URL --output=.claude/snapshots/seo-baseline.json",
        "description": "デプロイ成功後にSEOベースラインを更新"
      }
    ]
  },
  "agent_defaults": {
    "model": "claude-sonnet-4-20250514",
    "max_tokens": 8192,
    "timeout": 120
  },
  "skills_directory": ".claude/skills/"
}

この設定に関する注記:

  • サブエージェントにはOpusではなくclaude-sonnet-4-20250514を使用する。ここでの推論タスクはコスト差を正当化しない。Sonnetは「2つのJSONオブジェクトを比較し、差分にフラグを立てる」をうまく処理できる。
  • デプロイゲート上のtimeout: 300はすべての5つのサブエージェントの実行時間を与える。個別のエージェントは120秒のデフォルトを持つ。オーケストレーターはすべてが終了するのを待つため5分を得る。
  • pre-commit フック上のconditionはスキーマ関連ファイルに触れたときだけスキーマバリデーションを実行することを意味する。CSS変更では実行する意味がない。
  • post-deploy-successはベースラインを更新する。これがないと、SEOリグレッションチェックは古いデータと比較する。

スキルファイル定義はそれらを結びつける

最も多くの作業を行うスキルファイルはcompare-seo-snapshot.mdだ:

# Skill: Compare SEO Snapshots

## Purpose
2つのSEOメタデータスナップショットを比較し、リグレッションを特定します。

## Input
- 現在のスナップショット:/tmp/seo-current.json
- ベースラインスナップショット:.claude/snapshots/seo-baseline.json

## Comparison Rules

### Title Tags
- タイトルが変更され、ページのオーガニックトラフィック(ベースラインメタデータから)> 1000セッション/月の場合、HIGHとしてフラグ。
- タイトルが現在は空であるか、別のページのタイトルと一致する場合、CRITICALとしてフラグ。
- タイトルが低トラフィックページで変更された場合、MEDIUMとしてフラグ。

### Canonical URLs
- 正規URL への変更は HIGH。
- 別のドメインを指す正規参照は CRITICAL。
- 欠落している正規(存在していたが、現在はない)は HIGH。

### Robots Meta
- 「noindex」を得たページは CRITICAL。
- 内部リンク上で「nofollow」を得たページは HIGH。

### 新しいページ
- 現在にはあるが、ベースラインにはないページは INFO(新しいコンテンツでは予想)。
- ただし、タイトル、メタディスクリプション、canonical、少なくとも1つのh1を持つことを確認。

### 削除されたページ
- ベースラインにはあるが、現在にはないページは HIGH。
- これらは意図しないルート削除を示す可能性がある。

このスキルファイルは、数か月のSEOインシデント対応を、Claudeが確実に従うことができる形式にエンコード化する。これがなければ、サブエージェントはリグレッションが何を構成するかについて合理的だが一貫性のない判断を下すだろう。

システムが検出した4つのインシデント

インシデント1:47ブログ投稿への偶発的なnoindex

クライアント: B2B SaaS企業、200ページ、月6万オーガニックセッション。

開発者は新しいメタタグを追加するためにブログテンプレートの<Head>コンポーネントを更新した。ステージング設定からコピーペーストしたが、<meta name="robots" content="noindex, nofollow">がハードコードされていた。レビュアーが新しいタグに焦点を当てたため、既存のタグに気づかずコード審査に合格した。

SEO リグレッションサブエージェントは47ページを CRITICAL とフラグ――robots meta が noindex に変更された。デプロイはブロックされた。

検出までの時間: プッシュ後2分14秒。システムなしでは、Search Consoleが3~7日後にカバレッジ低下を示すときにキャッチされていただろう。

回避された推定影響: これら47投稿は大体月$14,000のパイプラインを生成した。1週間のdeindexイベントでさえ$3,500+の費用がかかった可能性があった。

インシデント2:新しいヒーロー画像からのCLSリグレッション

クライアント: eコマースブランド、Shopify Hydrogen上のNext.js 14ストアフロント。

デザインチームはホームページヒーロー を新しい画像にスワップしたが、アスペクト比が異なり、<Image>コンポーネント上のwidth/height属性を更新しなかった。画像はうまく読み込まれたがCLS 0.34を引き起こした――0.1の閾値をはるかに超える。

CWVスモークテストサブエージェントはホームページ上のCLSリグレッションを報告した。要約は特に次のように呼び出した:「CLS は要素img.hero-bannerシフト0.34で引き起こされた。画像の寸法(1920x800)がコンテナアスペクト比(16:9 = 1920x1080)と一致しません。明示的にwidth={1920} height={800}を追加するか、コンテナを更新してください。」

検出までの時間: 1分47秒。

インシデント3:URL再構成後の壊れた内部リンク

クライアント: プロフェッショナルサービス企業、80ページ。

サービスページを/services/[name]から/[category]/[name]に再構成した。リダイレクトは導入されていたが、3ブログ投稿は古いURLへのハードコードリンクを持ち、CMS駆動ナビゲーションは削除されたページをポイントするキャッシュされたエントリを持っていた。

壊れたリンク スキャンは4つの内部404を見つけた。サブエージェントの要約は、4つの3つがブログ投稿本文コンテンツ(ナビゲーションではない)に含まれていることに注目した。つまり、リダイレクト監査で見落とされていた。

検出までの時間: 3分8秒。linkinator クロールは最も遅い部分だ。

インシデント4:Article スキーマの欠落した dateModified

クライアント: メディア企業、2,000記事。

WordPressからSanityへのCMS移行により、dateModifiedフィールドマッピングが失われた。スキーマ生成コードはdateModifiednullにフォールバックし、無効なJSON-LDを生成した。

スキーマバリデーションサブエージェントはすべての記事ページを HIGH としてフラグ――欠落している必須dateModifiedフィールド。要約は説明した:「Google は Article 構造化データについて dateModified が必要です。Top Stories とリッチリザルトの対象となる。すべての2,147記事ページが影響を受けます。」

検出までの時間: 4分22秒(大規模サイトマップ)。

ROI:配信あたりの分数節約と月あたりのドル

ここが計算だ:

メトリック 前(CI + 手動) 後(サブエージェント) デルタ
デプロイあたりのチェック 4ツール、手動レビュー 5エージェント、自動化 +1チェック、-100%手動レビュー
すべてのチェック実行時間 8~12分(シーケンシャルCI) 3~5分(並列サブエージェント) -60%
失敗を理解するまでの時間 失敗あたり20~40分 1~2分(文脈的な要約) -90%
デプロイ/週(すべてクライアント) 18 18 同じ
誤検知率 ~15%(ノイズの多いLighthouse) ~4%(推論がノイズをフィルタリング) -73%

配信あたりの分数節約: チェックが失敗するときの平均25分(デプロイの30%)。これは25分 × 5.4失敗デプロイ/週 = 135分/週 = 月9時間

システムのコスト:

  • サブエージェント用のClaudeAPI コスト:完全なデプロイゲート実行あたり~$0.12(5エージェント、Sonnet、エージェント平均6,000トークン)
  • 週18デプロイ × 4.3週 × $0.12 = 月$9.29 API コスト
  • Puppeteer/Lighthouse インフラストラクチャ:既存のVercel ビルドインスタンスで実行、追加費用なし
  • メンテナンス時間:スキルファイルと閾値を更新するのに月~2時間

エンジニア時間節約のドル価値: 月9時間 × $85/時間(チーム混合率) = 月$765節約

回避されたインシデントのドル価値: 上記4つのインシデントに基づいて、noindex インシデント単独が$3,500を費用がかかった可能性がある。四半期ごとに1つのそのようなインシデント を防ぐことができれば、それは月$1,166の回避されたクライアント影響だ。

純ROI:API コスト月$9.29 で月$1,920 の価値。 これは206倍のリターンだ。API コストを大規模チーム向けに10倍にしたとしても、まだ有利だ。

ギャップと変更したい内容

このシステムは完璧ではない。ここが引き続き荒い点だ:

ビジュアルリグレッション テスト がない。 サブエージェントはLighthouseとpa11yを実行できるが、スクリーンショットを見て「ヒーロー セクションが壊れている」と言うことはできない。Claudeのビジョン機能をウォッチ中だ。

ベースライン ドリフト。 SEO ベースラインはデプロイ成功時に更新されるが、システムが検出しないリグレッションを配信する場合、それが新しいベースラインになる。月1回手動でベースラインをレビューする。

外部リンク の不安定性。 Twitter/X、LinkedIn、一部の政府サイトはクローラーをブロックするか積極的にレート制限する。除外リストを維持するが、手動更新が必要だ。

コールドスタート時間。 リポジトリをクローン後の初回実行はnpxがパッケージをフェッチする必要があるため長くかかる。Docker レイヤーでCLIツールを事前インストールすることを検討中だ。

Anthropic レート制限。 ピークアワー中に同時に5つのサブエージェントをスポーンすることは、Claude API上のレート制限にときどき当たる可能性がある。スポーン間に2秒のずれを追加したが、不格好だが機能する。

スキーマバリデーション(400単語)のような長いエージェント定義は、より短いものよりもときどき構造化された出力が少ない。エージェントをスキーマバリデーションをタイプ別のサブサブエージェントに分割することを検討中だ。

FAQ

Claudeコード サブエージェントは任意のLLMで機能しますか、それともClaudeのみですか?

サブエージェントはClaudeコード機能で、Anthropic APIに結びついている。Claude API キーがClaudeコードへのアクセスに必要だ。エージェント定義形式はClaudeコードの.claude/ディレクトリ慣例に固有で、一般標準ではない。

デプロイあたり5つのサブエージェントを実行するのはAPI費用でいくらかかりますか?

現在の規模では、Claude Sonnet を使用した完全なデプロイゲート実行あたり大体$0.12。月18デプロイ週で月$9~10。Opusはおよそ5倍多く費用がかかるが、これらのタスクには必要であることが判明していない。

サブエージェントはGitHub ActionsのようなCI/CDパイプラインで実行できますか?

はい。CI環境で Claude コードをヘッドレスで呼び出すことができる。Vercel プレビューデプロイ完了時にウェブフック経由でトリガーしてプレビューURLを環境変数として.claude/agents/deploy-gate.mdの実行を呼び出す。

Claude コード スキルとサブエージェントの違いは何ですか?

スキルはClaudeに何かを行う方法を教えるマークダウン命令ファイル(レシピのような)だ。サブエージェントは独自のコンテキストとツールと共にスポーン可能な隔離されたClaudeインスタンスだ。サブエージェントスキルを使う。スキルはドキュメント、エージェントは労働者と思考する。

Anthropic のRoutines機能が必要ですか、それとも生のサブエージェントで十分ですか?

デプロイゲートワークフロー用に、settings.json内の生のサブエージェント + フックで十分だ。ルーチンは、より複雑なマルチステップワークフロー向けの高レベルオーケストレーション層を追加する。デプロイチェックがエージェント6を超えて増加する場合、ルーチンを採用するかもしれない。

サブエージェント障害またはタイムアウトをどのように処理しますか?

各サブエージェントは120秒タイムアウトを持つ。サブエージェントが失敗またはタイムアウトする場合、デプロイゲートオーケストレーターはそれをBLOCKではなくWARNとして扱う。Lighthouseが引っ掛かるため、デプロイをブロックするより船で不完全なチェックを使う方が良い。要約は完了しなかったチェックを記述する。

このアプローチはLighthouse CIやpa11yなどの専用ツールを置き換えることができますか?

いいえ――それらをラップする。サブエージェントはこれらのツールを bash 経由で呼び出し、出力について推論する。基盤となるツールがインストールされている必要があり。値は、スキャナー自体を置き換えるではなく、オーケストレーション、相関、自然言語報告層にある。