こんにちは。ファインディのPlatform開発チーム(以降、SREチーム)でSREを担当している原(こうじゅん)です。
SREチームでは、AWSのユーザーとGitHubのアカウントの管理をTerraformで運用しています。Slackから申請が来たらTerraformのコードを書き換えてPRを出す、という作業を以前はDevinで自動化していました。
しかしDevinのアカウント利用形態が変わったことをきっかけに、この自動化基盤をClaude Code Actionsへ移行しました。同じようにAIツールでインフラ運用を自動化している方や、Claude Code Actionsの実践的な使い方を探している方に向けて、移行に至った判断理由と、移行後のアーキテクチャについて紹介します。
背景:Devinでアカウント管理を自動化していた
ファインディでは、GitHub Teamへのメンバー追加やチームの作成・廃止といったアカウント管理を、SREチームがTerraformで運用しています。
エンジニア・ビジネスサイド問わず、メンバーがSlackから申請を出すと、SREがTerraformのコードを手動で書き換えてPRを出し、レビュー・マージ後にapplyされる、という流れでした。毎回決まったパターンのYAML編集とPR作成を手作業でやるのは、典型的なトイルです。
このトイルを減らすために、Devinを使って自動化していました。Slackの申請内容をDevinに渡すと、Terraformリポジトリのコードを編集してPRを作ってくれる仕組みです。この取り組みの詳細は次の記事で紹介しています。
移行を決めた理由
きっかけは、2026年4月1日のDevinのアップデートです。このアップデートでDevinアカウントを持たないユーザーはSlackのDevinスレッドに参加できなくなりました。
アカウントを持たない申請者が@Devinに返信してもDevinが反応せず、「動かない」というSREへの問い合わせが増えました。コンプライアンス上、全メンバーへのアカウント一律払い出しも現実的ではありません。そのため、Devinからの移行に踏み切りました。
移行先の選定にあたっては、次の3つを重視しました。
- 全メンバーが個人アカウントなしで使えること — Anthropic公式の@Claude(Claude in Slack)も検討しましたが、各ユーザーにClaude Codeのアカウントが必要で同じ問題を抱えて断念しました
- 申請者の体験を変えないこと — Slack Workflowのフォームはそのまま、バックエンドだけを差し替えます
- チームのツール統一 — 開発チーム全体がすでにClaude中心の開発体制になっており、自動化基盤もそれに合わせました
この選定理由より、今回のアーキテクチャとなりました。
移行後のアーキテクチャ
移行後の全体構成は次のとおりです。
flowchart TD
subgraph Slack["Slack (申請者の体験)"]
F1["メンバー申請"]
F2["チーム申請"]
Thread[("申請者スレッド")]
end
subgraph GHA["GitHub Actions"]
Triage["triage\n(Claude Code Action)\n整合性チェック・名前解決"]
RoutinePR["routine-pr\n(Claude Code Action)\nファイル編集・PR作成"]
Escalate["escalate\n自動処理不可を通知"]
end
SRE["SRE承認・マージ"]
Apply["terraform apply"]
F1 -->|workflow_dispatch| Triage
F2 -->|workflow_dispatch| Triage
Triage -->|routine| RoutinePR
Triage -->|escalate| Escalate
RoutinePR -->|PR作成| SRE
RoutinePR -->|受付通知| Thread
Escalate -->|エスカレ通知| Thread
SRE -->|マージ| Apply
Apply -->|完了通知| Thread
classDef unchanged fill:#e6f4ea,stroke:#34a853,stroke-width:2px,color:#1b5e20;
class F1,F2,Thread unchanged
style Slack fill:#f1f8f4,stroke:#34a853,stroke-width:2px;
Slack Workflowからの申請がGitHub Actionsのworkflow_dispatchをトリガーし、正常系ではtriageジョブとroutine-prジョブの2つのClaude Code Actionが順に処理する構成です。
ただし、Slack Workflow Builderから直接workflow_dispatchは呼べません。間にSlack Custom Function(Deno Slack SDK)を挟み、GitHub APIへの認証付き呼び出しを行っています。
sequenceDiagram
participant WF as Slack Workflow Builder
participant CF as Custom Function<br/>(Deno Slack SDK)
participant GH as GitHub API
WF->>CF: フォーム入力値を渡す
CF->>CF: GitHub App秘密鍵でJWT署名
CF->>GH: JWT → Installation Access Token取得
GH-->>CF: Token返却
CF->>GH: workflow_dispatch(Token認証)
GH-->>CF: 202 Accepted
申請者から見ればSlackのフォームに入力するという体験は変わっていませんが、裏側ではCustom FunctionがGitHub Appの認証(JWT署名 → Installation Access Token取得)を行い、workflow_dispatchを呼び出しています。
triageジョブ:申請の振り分け
最初のClaude Code Actionは、申請内容の整合性チェックと振り分けを担当します。
チーム名の名前解決(申請者が入力した表記ブレを、リポジトリ上の実際のディレクトリ名に解決する)、申請内容のバリデーション、そしてroutine(自動処理可能)かescalate(自動処理不可)かの判定を行います。
triageとPR作成を1つのジョブにまとめることもできますが、責務と権限を分離するためにあえて分けました。triageジョブは--max-turns 5と少ないターン数に制限し、使えるツールもReadとBash(ls:*)だけに絞っています。判定がおかしければPR作成に進まない安全弁にもなります。
判定結果はJSON Schemaで構造化出力させるので、後続のジョブが確実にパースできます。
claude_args: | --max-turns 5 --allowedTools Read,Bash(ls:*) --json-schema '{"type":"object","properties":{"verdict":{"type":"string","enum":["routine","escalate"]},...}}'
routine-prジョブ:ファイル編集とPR作成
triageでroutineと判定された申請は、2つ目のClaude Code Actionが処理します。TerraformリポジトリのYAMLファイルを編集し、ブランチを切ってPRを作成するジョブです。
--max-turns 20とターン数を多めに確保し、ファイル編集やgit操作、PR作成に必要なツールを許可しています。
claude_args: | --max-turns 20 --allowedTools 'Read,Edit,Write,Bash(git checkout:*),Bash(git add:*),...,Bash(gh pr create:*)'
PR作成後はSlackの申請スレッドに受付通知を送り、SREがレビュー・マージすればterraform applyが走って完了通知が届きます。
escalateジョブ:自動処理できない申請の通知
triageが自動処理できないと判断した申請は、Slackの申請スレッドにその旨が通知されます。Claude Code Actionは使わず、シェルスクリプトで通知を送るだけのシンプルなジョブです。
まとめ
Devinのアカウント利用形態変更をきっかけに、アカウント管理の自動化基盤をClaude Code Actionsへ移行しました。Claude Code Actionをtriage(振り分け)とroutine-pr(PR作成)の2段階に分け、それぞれの責務と権限を絞った設計にしています。
現在、GitHubアカウント管理の移行は完了し、運用を開始しています。今後はAWSのユーザー管理なども移行を進めていきます。
ファインディでは一緒に会社を盛り上げてくれるメンバーを募集中です。興味を持っていただいた方はこちらのページからご応募お願いします。