1. はじめに:何を作ったか
自分のプロジェクトで、JiraのチケットからPRまでを自動で消化していく仕組みを作りました。
Readyになっているチケットを定期実行のルーチンが自分で拾い、実装し、「実際に動いた」証跡を貼ったPRを出して、チケットをIn Reviewまで進めます。
人間に残るのはレビューだけ、という状態を目指しています。
きっかけは、実装そのものよりも、その周辺の定型作業で消耗していたことでした。
次に着手するチケットを選び、ブランチを切り、決まった形でコミットとPRを作る。
一つひとつは小さくても、毎日何度も繰り返される判断なので、積み重なると集中の妨げになります。
それなら、Readyのチケットを上から順に消化していく流れごと自動化してしまえばいい、と考えました。
この記事では、その仕組みを「どう作ったか」に絞って書きます。
消化の手順を1つのスキルに切り出し、それをローカルのルーチンで定期実行する、という構成を順に説明していきます。
なお「そもそもどんなチケットならClaudeに任せられるのか」という問いは、それだけで一本になるので別記事に回します。
ここでは“回す仕組み”のほうに集中します。
2. 全体像:スキルとローカルのルーチンの2層
全体は2つの層でできています。
ひとつは、1枚のチケットを消化する手順そのものを書いたスキル(jira2pr)です。
チケットを取ってきて、実装して、証跡を取って、PRにする。
この一連の手続きを、プロンプトに直書きせず、スキルとして切り出しています。
これが「手法本体」にあたります。
もうひとつは、そのスキルを定期的に叩くローカルのルーチンです。
いつ起動し、どのチケットを対象にし、各実行をどう隔離するか。
こうした“回す側”の責務をここが持ちます。
チケットはこの仕組みの中で、Ready → In Progress → In Review とステータスが進んでいきます。
そして重要な約束ごととして、1回の実行で扱うチケットは1枚だけにしています。
複数を一度に処理させると失敗の切り分けが難しくなりますし、あとで出てくるロックの設計も単純にできるからです。
3. 消化モデル:ステータスをロックとして使う
この仕組みは、3つの役割で捉えると分かりやすくなります。
Jiraが「キュー」、チケットのステータスが「ロック」、ローカルのルーチンが「ワーカー」です。
ワーカーが定期的に起きて、キューから1枚取り出し、ロックを掛けてから処理する、という見立てです。
キューはJQLで定義する
何を消化対象にするかは、JQLで決めます。
私の運用では、Readyかつ label = claude が付いたチケットを対象にしています。
status = "Ready" AND labels = claude ORDER BY priority DESC, created ASC
このクエリの結果が、そのまま「消化キュー」になります。
ルーチンは毎回、この先頭の1枚だけを取り出します。
該当が0件なら、何もせずにその回は終了します。
In Progressへの遷移がロックになる
ここがこの設計の肝です。
取り出したチケットは、実装に入る前に、まずステータスをIn Progressへ遷移させます。
次の実行のJQLは status = Ready で引くので、In Progressに移った時点で、そのチケットは次回以降のキューから外れます。
つまり、ステータスを進めること自体が、二重消化を防ぐロックとして働きます。
ローカル実行でも、スケジュールを短くしたり手動実行を重ねたりすれば、実行が並行する場面は出てきます。
そこで、In Progressへ遷移させる直前に、そのチケットがまだReadyかどうかをもう一度確認します。
すでに別の実行が掴んでIn Progressになっていたら、そのまま何もせず終了します。
この「直前の再確認」を入れておくと、実行が重なってもチケットを二重に消化せずに済みます。
(いわゆる楽観ロックの考え方です。)
worktreeで実行を物理的に隔離する
ステータスのロックは、チケット単位の排他です。
これに加えて、コードを触る側も実行ごとに隔離します。
各実行は claude/{チケットキー} という名前のブランチを、独立したgit worktreeの中で扱います。
worktreeで切り分けることで、スケジュール実行が手元の作業ディレクトリを汚すことも、複数の実行が互いのファイルを踏むこともなくなります。
ブランチ名をチケットキーに固定しているのには、もうひとつ理由があります。
同じチケットキーのブランチや、未マージのPRがすでにあれば、新規に作り直さず、そこから再開できるからです。
何度実行しても、同じチケットは同じブランチに収束します。
4. 手法をスキルにする:なぜプロンプト直書きにしないか
消化の手順は、ルーチンのプロンプトに直接書き込むこともできます。
ですが私は、手順を1つのスキル(jira2pr)として切り出し、ルーチンからはそれを呼ぶだけにしました。
自律実行と相性のよい形にしたかったからです。
プロンプトに直書きすると、手順がルーチンの設定の中に埋もれてしまいます。
中身が長くなるほど差分が追えなくなり、レビューもしづらくなります。
スキルとして切り出せば、手順はリポジトリ内のファイルになります。
バージョン管理でき、変更の差分をレビューでき、手元の対話セッションからも同じ手順を呼べます。
特に効くのが、本番投入の前に対話モードで動作確認できる点です。
ルーチンは承認なしで自律的に走るので、いきなり自動実行に任せるのは不安があります。
先に手元でスキルを叩いて挙動を確かめておけば、その不安をかなり減らせます。
結果として、ルーチン側のプロンプトは「次の1件を jira2pr で消化して」程度に薄く保てます。
スキルの構造(進行的開示)
スキルは、本体のSKILL.mdと、参照ファイルに分けています。
本体には全体の流れだけを書き、証跡の取り方のような種別ごとの詳細は参照ファイルに逃がしています。
本体を読んだうえで、フロントなら references/frontend.md、バックなら references/backend.md を読ませる、という形です。
こうしておくと本体を短く保てますし、毎回必要なところだけを読み込ませられます。
実際の本体は、次のような骨格になっています。
---
name: jira2pr
description: Readyかつlabel=claudeのJiraチケットを1件取り出し、In Progressに移して実装し、動作確認の証跡を付けたPRを作成してIn Reviewに遷移させる。…
---
## 全体フロー
1. キューから1件取る(JQLで選択)
2. ロックを取る(即In Progressへ遷移)+ worktreeを切る
3. 種別を判定し、対応する参照ファイルを読む
4. 実装する
5. 証跡を取る(=検証する)
6. PRを作る(証跡を貼る・チケットに紐付ける・In Reviewへ遷移)
7. 詰まったら退避する(誤解を招くPRは作らない)
5. 証跡をPRに残す
ここがこの仕組みの中心です。
ルーチンは承認なしで自律的に走るので、実装の途中に人は入りません。
そして、実行が最後まで流れたからといって、タスクが成功したとは限りません。
エラーなく終了したことと、要求どおりに動いたことは別物です。
だとすると、出てきたPRをレビュアーはどう信用すればいいのか、という問題が残ります。
私の答えは、コードを信用してもらうのではなく、「動いた事実」を見せる、というものです。
実際に動かした結果を、PR本文に貼り付けます。
レビュアーはコードを追わなくても、まず証跡を見て判断できます。
フロントエンド:スクリーンショット
フロントの実装では、画面が実際にどう表示されるかを見せます。
まずモックサーバを立てて、依存するAPIの応答を固定します。
そのうえでアプリを実際に起動し、受け入れ基準に対応する画面の状態をPlaywrightでスクリーンショットに撮ります。
入力前と入力後、エラー表示、空状態のように、確認すべき状態が複数あるなら、それぞれ撮ります。
撮った画像をPR本文に貼れば、レビュアーは見た目でそのまま確認できます。
バックエンド:curlの結果
バックの実装では、実際にエンドポイントを叩いた結果を見せます。
ローカルでエンドポイントを起動し、curlでリクエストします。
正常系だけでなく、バリデーションエラーや認証エラーのように、基準で要求される異常系も叩きます。
そして、リクエストとレスポンスの両方をPR本文に貼ります。
ステータスコードとレスポンスボディが基準どおりかを、レビュアーがそのまま突き合わせられる状態にします。
画像をPRに貼るのが地味に難しい(gh-attach)
ここで一番つまずいたのが、スクリーンショットをPRに載せる部分でした。
GitHubには、画像をPRに添付する公式のAPIがありません。
WebのUIで画像を貼ると user-attachments のURLに変換されますが、このアップロードはトークンでは通らず、ログイン済みブラウザのセッションを必要とします。
そのため、CLIやAPIから素直に画像を載せることができません。
私はここを gh-attach で解決しました。
ブラウザのセッション経由で画像をアップロードし、返ってきたURLをPR本文に埋め込めるようにするツールです。
そして、このツールがローカルのブラウザセッションを前提にしていることが、そのままローカル実行を選んだ理由のひとつになっています。
(クラウドで動かす構成だと、このログイン済みブラウザが手元になく、ここでつまずきます。)
6. ローカルのルーチンで回す
スキルができたら、あとはそれを定期的に呼ぶだけです。
私はこれを、ローカルのルーチンで回しています。
ルーチンの作り方
ローカルのルーチンは、デスクトップアプリの「Routines」から「New routine」を選び、「Local」を選んで作ります。
対象のリポジトリと、起動スケジュール(毎時、5分おきなど)を指定します。
プロンプトは薄くて構いません。
やることはスキル側に書いてあるので、ここでは「Readyかつ label = claude の次の1件を jira2pr スキルで消化して」と指示する程度です。
各実行はworktreeで隔離します。
これは3節で触れたとおりで、スケジュール実行が手元の作業を踏まないようにするためです。
自律的に動かす
ローカルのルーチンは、初期の設定では都度許可を確認され、自律的に動いてくれません。
自動モードや許可をバイパスすることで、完全自律で動作するようになります。
注意しておきたい事として、最初にこの設定を行った後、人が止める機会はありません。
だからこそ、4節・5節で書いたように、スキル側の手順と証跡が品質の歯止めになります。
正直なトレードオフ
ローカルで動かす以上、実行されるのはPCが起きていて、アプリが開いている間だけです。
ノートを閉じたりスリープしたりしている間は動きません。
スリープでスケジュールを逃した場合も、復帰時に拾い直すのは直近の1回だけです。
つまり「PCをつけっぱなしにする」ことが前提になります。
なお、PCを閉じても動かしたいなら、クラウド側のルーチン(リモート)という選択肢もあります。
ただしクラウドだと、手元のローカルファイルにも、ログイン済みのブラウザセッションにも触れません。
今回の構成は証跡まわりでローカルのツールに強く依存しているので、私はローカルを選びました。
7. スキルの作り方:skill-creator / superpowers
このスキルは、自分でゼロから書くより、スキル作成用のツールに任せたほうが早く、品質も安定します。
選択肢は主に2つです。
ひとつは、Anthropic純正の skill-creator です。
スキル作成そのものに集中していて、素直に使えます。
ドラフトを書き、テスト用のプロンプトで実際に動かし、結果を見て直す、という反復で仕上げていきます。
もうひとつは superpowers です。
こちらはスキル作成だけでなく、TDDや「完了前に検証する」といった開発の進め方ごと持ち込むツール群です。
「動いた証跡が取れて初めて完了」という今回の考え方と、思想がそのまま噛み合います。
ただし一式のワークフローが乗ってくるので、目的を絞ったスキルを1つ作るだけなら、やや重く感じるかもしれません。
使い分けの目安としては、検証を完了条件に組み込む発想ごと借りたいなら superpowers、軽く作りたいなら skill-creator、という整理になります。
どちらにしても、一度書いて終わりにせず、対話モードで何度か叩いて直す前提で進めるのがよいです。
自律実行に任せる前に手元で挙動を固めておけることが、スキルにしておく一番のメリットだからです。
8. まとめ
最後に、全体を3つに整理します。
- スキルが手法です。1チケットをどう消化するかの手順を、リポジトリ内のSKILL.mdに切り出しました。
- ローカルのルーチンがランナーです。スケジュールでスキルを呼び、worktreeで実行を隔離します。
- 証跡が信頼です。動いた事実をPRに残すことで、自律実行でもレビュアーが判断できる状態を作りました。
そして、ステータスをロックとして使うことで、キューの消化を排他的に回しています。
この仕組みがうまく回るかどうかは、最終的には「どんなチケットを流すか」に大きく左右されます。
Claudeに任せられるチケットとは何か、という話は、それ自体で一本になるので、別の記事で掘り下げます。
