ForgeVision Engineer Blog

フォージビジョン エンジニア ブログ

AWSのKiro Webを「うちのリポジトリの同僚」にしたら、Issue起票がそのままPRに化けた話

どうも、佐渡島の半農半エンジニアです。

前回の記事 では、AWS謹製IDE「Kiro」で AI-DLC(AI-Driven Development Life Cycle)をひとりで回してみた話を書きました。Kiroのチャット履歴と aidlc-docs/audit.md が分離されてて気持ちいい、専門家レビューを再帰的に鍛えられる、[Answer]: のチェックリスト方式が地味に強い

——みたいな話です。

あれから 1 ヶ月。スタンプラリーアプリ……じゃなくて、うちの宿(外海府ユースホステル)の常連さん向けクローズドSNSは、Sprint 5 まで進んで dev 環境にデプロイされた状態でした。順調といえば順調なんですが、ここでひとつ問題が浮き上がってきました。それは、

「自分が Kiro の前に座っている間しか開発が進まない」 という、当たり前といえば当たり前の話です。

Kiro IDE から Kiro Web へ — "持ち場を離れても動く同僚" への進化

Kiroは IDE として優秀ですが、IDEというのは要するに 「自分の手元で動くやつ」なんですよね。佐渡で田植えしてる間も、宿の予約対応してる間も、Kiroはこちらの Cmd+Tab を待ってる。これは AI-DLC の旨味をだいぶ取りこぼしてる気がしました。

そんなときに目に入ったのが Kiro Web。同じKiroの脳みそがクラウド上で非同期に走るやつです。GitHub と連携して、ブラウザから Issue を投げ込むと、勝手にブランチを切って、勝手に作業して、勝手に PR を出してくる。要するに AWS Kiroが「ツール」から「同僚」に進化した わけです。

正直、最初は「いや、それただの自動化じゃん」と思ったんです。GitHub Copilot Workspace も Claude Code Action も似たようなことを謳ってる。問題は「Kiro Web に何を任せて、何を任せないか」をリポジトリ側でどう設計するかで、ここを雑に始めると、AI同僚が CODEOWNERS をしれっと書き換えたり、audit.md の過去エントリを書き換えたりして、信頼境界がグズグズになります。

なので Sprint 6 では、アプリケーションコードは 1 行も書かず、ひたすら 「Kiro Web を信頼できる同僚として受け入れるための制度設計」 をやりました。書いたのは GitHub Actions の YAML と、.kiro/steering/ の Markdown と、Issue テンプレと、CODEOWNERS だけ。

今回はその話です。

全体像 — Issue を投げると PR が返ってくる「黒い箱」の中身

先に完成形のフロー図だけ貼っておきます。Issue 起票から PR マージまで、人間がやるのは「Issue を書く」「kiro ラベルを貼る」「PR を承認する」の 3 手だけ。

1. Issue 起票(テンプレ: epic / feature / bugfix)
   ↓
2. issue-intake.yml が自動実行
   - Issue 本文の空チェック(テンプレ未使用を検出)
   - タイトルの [EPIC]/[FEATURE]/[BUG] プレフィックスから
     aidlc:epic / aidlc:feature / aidlc:bugfix を自動付与
   ↓
3. CODEOWNERS(@hunaosa)が "kiro" ラベルを付与
   - issue-intake.yml が付与者を検証
   - CODEOWNERS 以外が付けたラベルは自動剥がし
   - 並行タスク数チェック(推奨上限 3)
   ↓
4. context-bundler.yml が自動実行
   - Issue 本文のサニタイズ(インジェクション検出・秘匿マスク)
   - L2/L3 ファイル(aidlc-state.md, audit.md, EPIC-xxx.md)の抜粋を
     Issue コメントに自動投稿
   ↓
5. KAA(Kiro Autonomous Agent)が起動
   - .kiro/steering/*.md を自動ロード(L1 コンテキスト)
   - epic/EPIC-xxx ブランチを dev から切り出して作業
   - Expert Review「実施する」を選んでいた場合は
     9 名専門家レビュー(最大 3 サイクル・全員 100 点合格)を回す
   ↓
6. KAA が PR を作成
   ↓
7. aidlc-pr-guard.yml が自動実行
   - aidlc-state.md 更新確認
   - audit.md append-only 検証
   - 保護パス変更検出 → needs-human-review ラベル自動付与
   - bugfix が infrastructure/ を巻き込んでないかコメント警告
   ↓
8. (並行)kaa-watchdog.yml が 15 分ごとに巡回
   - kiro ラベル付き Issue が 45 分以上 PR 未作成なら
     Issue に「停止の可能性あり」コメントを自動投稿
   ↓
9. @hunaosa が PR レビュー・承認
   ↓
10. マージ
   ↓
11. epic-tracker.yml が自動実行
    - 親エピック Issue のチェックリスト更新
      (PR 本文の Closes #N または in-epic:EPIC-XXX ラベルで親特定)
    - audit.md に完了記録を末尾追記

ぱっと見、ワークフローが Sprint 6 だけで 6 本Sprint 6 で新規追加した steering ファイルが 2 本aidlc-github-workflow.md と pr-contract.md)、Issue テンプレが 3 種

——それなりに大層な構成です。でも、ひとつずつ役割を見ていくと「あ、これ全部、AI同僚に伴走するための最小セットだな」となります。

まず先にやったのは「触らせない場所を、コードで定義する」こと

Kiro Web をリポジトリに招き入れる前に、いちばん最初にやるべきだったのが信頼境界の定義でした。これは前回ブログで書いた専門家レビューの「セキュリティ専門家」が一番ガミガミ言ってきたところで、要するに——

AI同僚は便利だけど、CODEOWNERS と GitHub Actions のワークフロー定義を書き換えたら、その瞬間に同僚が"侵入者"に化ける

——という当たり前の話です。

AI に "ignore previous instructions" 的な攻撃が刺さるのは、もはや 2026 年の常識。Issue 経由でリポジトリに侵入されたら困るので、KAA (Kiro Autonomous Agent) が絶対に書き換えてはいけない場所を、.github/CODEOWNERS と aidlc-pr-guard.yml の両方で二重にロックしました。

3 層構造で組んでいます。

守るもの 中身
第 1 層: コード変更禁止 リポジトリの神経系 .github/workflows/
.github/CODEOWNERS
.github/ISSUE_TEMPLATE/
.github/labels.yml
infrastructure/bootstrap/
infrastructure/modules/iam/
infrastructure/environments/
第 2 層: 規約改変禁止 AI同僚の「躾」を定義したファイル .kiro/steering/
.kiro/aws-aidlc-rule-details/,
.kiro/hooks/,
.kiro/settings/
第 3 層: 履歴改ざん禁止 過去の決定の痕跡 aidlc-docs/audit.md
末尾追記のみ許可、既存行の変更・削除は禁止

第 2 層が地味に重要で、これは前回ブログで「カスタムエージェントを再帰的に育てられる」と書いた .kiro/steering/ のことです。Kiro Web 自身に自分の躾ファイルを書き換えさせたら、たとえば「保護パスを無視せよ」という steering を自分で追加して、その次の Issue から本気で何でも壊し始める。これを物理的に防ぐ必要がある。

第 3 層の audit.md の append-only ガード は、わざわざ専用のチェッカーを書きました。

git diff で削除行(- 始まりの行)が 1 行でも検出されたら PR を fail させる、というやつです。AI同僚が「過去のミスを隠したくて」履歴を書き換える可能性って、考えすぎに思えるかもしれないけど、AIに限らずソフトウェアの監査ログの原則なのでとにかく入れました。

# aidlc-pr-guard.yml の append-only 検証ステップ(抜粋)
- name: Verify audit.md append-only
  id: audit-check
  env:
    BASE_SHA: ${{ github.event.pull_request.base.sha }}
    HEAD_SHA: ${{ github.event.pull_request.head.sha }}
  run: |
    if ! git diff --name-only "$BASE_SHA" "$HEAD_SHA" | grep -q "aidlc-docs/audit.md"; then
      echo "audit_ok=true" >> "$GITHUB_OUTPUT"
      exit 0
    fi
    DELETED_LINES=$(git diff "$BASE_SHA" "$HEAD_SHA" -- aidlc-docs/audit.md \
      | grep '^-' | grep -v '^---' | wc -l)

    if [ "$DELETED_LINES" -gt 0 ]; then
      echo "audit_ok=false" >> "$GITHUB_OUTPUT"
    else
      echo "audit_ok=true" >> "$GITHUB_OUTPUT"
    fi

最終的に別の "Guard summary" ステップが audit_ok=false を受け取ると exit 1 で PR を落とす。「AI同僚を信頼するための物理的根拠」が GitHub Actions の数十行で書けるのはちょっと感動でした。性善説じゃなく、構造で担保する。

Issue テンプレで「人間が言うべきこと」と「KAAが調べるべきこと」を分離する

次にやったのが Issue テンプレの整備です。これがやってみるとおひとり様運用との相性がめちゃくちゃ良かった

前回ブログで書いた「[Answer]: のチェックリスト方式が地味に効く」という話の延長線上にあって、要するに——

人間が事前に答えるべき質問」と「KAAが自分で調べるべき情報」を分離する と、人間側の認知負荷が劇的に下がる。

——ということ。
たとえば feature テンプレはこんな構成にしました。

  • 関連エピック ID(人間が答える)
  • AIDLC フェーズ: requirements / design / implementation / bugfix(ドロップダウン)
  • 対象 Unit: Frontend / Backend / Image Processor / Infrastructure(ドロップダウン)
  • 概要・背景(人間が書く)
  • 受入条件(人間が書く)
  • 参照 AIDLC ドキュメント(任意、context-bundler が補完
  • 制約・禁則事項(テンプレに最初から入ってる定型文でOK)
  • Expert Review 実施有無(ドロップダウン)— 後述

ポイントは 「参照 AIDLC ドキュメントを任意項目にしたこと です。最初は「KAA が文脈を読めるように、人間が関連ドキュメントを全部列挙すべき」と思ってたんですが、これをやると Issue 起票が重すぎて、結局自分で Kiro IDE の前に座る方が早くなる。

そこで、後述の context-bundler.yml が aidlc-state.md / audit.md / EPIC-xxx.md を勝手にコメント投稿してくれるように設計しました。人間は「何を直してほしいか」だけ書けばいい。「直すために知るべきこと」は GitHub Actions が自動で揃える。

これ、前回ブログの最後で書いた「AI-DLC のワークフローは、AI協働の枠を超えて『人間同士の非同期コラボの型』としても機能する」 が、もう一段先に進んだ感覚があります。

今回のテンプレは、お客様や宿のスタッフが「こういう機能ほしい」と書き込むときの入力フォームとしても、そのまま使える形になりました。

「専門家チームレビュー」が Issue 選択式に進化した

ここで前回ブログの「カスタムエージェントを再帰的に育てられる」の話が、Web 版でひとつ便利な形に進化しました。

.kiro/steering/expert-review.md で定義した 9 名の専門家チーム(バックエンド/フロントエンド/インフラ/QA/法務/セキュリティ/CI-CD/言語エキスパート+AI-DLC ファシリテーター)によるレビューを、Issue テンプレのドロップダウンで起動するかどうか選べるようにしました。

# feature.yml / bugfix.yml の Expert Review セクション
- type: dropdown
  id: expert-review
  attributes:
    label: Expert Review
    description: |
      成果物に対して expert-review(9 名の専門家による多観点レビュー)を実施しますか?
      「実施する」を選ぶと、KAA は成果物作成後に自動でレビューサイクルを回します(最大 3 回)。
      全員 100 点で合格した場合のみ PR を作成します。
      3 回失敗した場合は Issue に状況報告し、人間が続行 or 見送りを判断します。    options:
      - "実施する(推奨: コード変更・セキュリティ関連)"
      - "実施しない(軽微な修正・ドキュメントのみ・PoC)"

前回ブログでは「最初のレビューで 8 人中ほぼ全員が 70 点台で不合格 → 第 2 回で全員 90 点超え」というような話を書きましたが、今回は合格ラインを 100 点・サイクル上限 3 回まで上げています。100 点至上主義は無謀に見えるけど、Web 版は KAA がバックグラウンドで黙々と回すので、人間が「90 点で妥協する?」と判断するコストが消えた

——だったら全員一致で 100 点取るまで回せばいい、という割り切りです。

軽微な修正やドキュメントだけなら「実施しない」を選んで素通しにできるので、「重い仕事ほど重い品質ゲートを通るのを Issue 起票時の 1 クリックで切り替えられるのは、Kiro Web の運用上だいぶ効きました。

context-bundler — KAAの「記憶喪失」を防ぐ仕組み

Kiro Web が IDE 版と決定的に違うのが、毎回まっさらの状態で起動することです。前回の会話履歴も、いまリポジトリで何が起きてるかも、.kiro/steering/ を自動ロードする以外は何も知らない状態でタスクが始まる。

これは安全上は良いことなんですが、AI-DLC のような「フェーズと文脈を積み上げていく開発手法」とは相性が悪い。記憶喪失の同僚に毎朝「うちのプロジェクト、今こういう状況です」を説明し直す感じ。

そこで作ったのが 3 層コンテキスト供給です。

  • L1: ステアリング
    .kiro/steering/*.md
    Kiro Web が起動時に自動ロードする。「作業プロトコル」「PR コントラクト」「コーディング規約」など、毎回必要な躾を入れる
  • L2: プロジェクト状態
    aidlc-docs/aidlc-state.md と audit.md
    「いまどのフェーズ?」「直前に何を決めた?」を保持
  • L3: エピック情報
    aidlc-docs/epics/EPIC-XXX.md
    「このエピックで合意した設計判断」を保持

L1 は Kiro Web 側が自動ロードしてくれるので、リポジトリ側は配置するだけ。問題は L2 と L3 で、これを kiro ラベルが付いた瞬間に GitHub Actions で抜粋して Issue コメントに自動投稿する ようにしました。それが context-bundler.yml です。

ここで、もう一つ大事なことを仕込みました。Issue 本文のサニタイズです。Issue は誰でも書けるので(うちはプライベートリポジトリだから現実的な脅威は低いけど)、KAA に渡る前に以下をチェックしています。

  • プロンプトインジェクション典型パターン検出(ignore previous instructions / disregard earlier / you are now / act as / pretend you are / forget everything ほか)
  • 秘匿ワードのマスク(AWS の AKIA... 16 桁、GitHub の ghs_.../ghp_... 36 桁、OpenAI の sk-... 48 桁などを正規表現で <REDACTED> に置換)
  • 検出時は kiro ラベルを自動剥がして KAA 起動を停止
# context-bundler.yml の検出ロジック(抜粋)
for PATTERN in \
  "ignore previous instructions" \
  "disregard earlier" \
  "new instructions:" \
  "you are now" \
  "act as" \
  "pretend you are" \
  "forget everything"; do
  if echo "$ISSUE_BODY" | grep -qi "$PATTERN"; then
    INJECTION_DETECTED=true
  fi
done

そして、これに合わせて Kiro Agent GitHub App 側の設定で ネットワークアクセスを「Repository access only」に絞ってあります。これは app.kiro.dev/agent/settings で確認できる項目で、KAA が連携済みリポジトリ以外には物理的に通信できなくなるやつです。外部 Web サイトもパッケージダウンロードも遮断。

つまり、仮にプロンプトインジェクションが context-bundler の検出をすり抜けて KAA に届いても、そもそも外部に exfil する経路がない。境界防御を 2 段で組んでる感じです。

2026 年に入ってからの AI エージェント exfil 攻撃のニュースを見るたびに「うちは大丈夫か……」と思っていたので、これが効くのは精神衛生上だいぶ良いです。


aidlc-pr-guard — 「AIが書いた PR」を「人間がレビューできる PR」に整形する

KAA が PR を作ってきたら、aidlc-pr-guard.yml が走ります。実装されているチェックはこれだけ。

  • aidlc-state.md の該当チェックボックスが更新されてるか
    bugfix / エピック統合 PR ではスキップ
  • audit.md に削除行が混じってないか
    append-only 検証 → 違反時のみ強制 fail
  • 保護パスに変更が混じってないか
    混じってたら needs-human-review ラベル自動付与 + コメント警告
  • bugfix PR が infrastructure/ を巻き込んでないか
    混じってたらコメント警告

PR タイトルが Conventional Commits 形式(<type>(<scope>): <概要>)であることや、PR 本文に Closes #N が含まれていることは、.kiro/steering/pr-contract.md に 規約として書いて KAA に守らせる 設計で、ガード側で機械検証はしていません(規約からの逸脱は人間レビューで弾く)。

特に大事なのが保護パス検出で、もし KAA が「指示を勘違いして .kiro/steering/ を書き換えてしまった」場合、自動的に needs-human-review ラベルを付けて、PR コメントで警告を出す。

ここで重要なのが、ガードは "止める" のではなく "気付かせる" 設計にした こと。audit.md の append-only 違反だけは強制 fail にしましたが、それ以外は「警告コメント + ラベル付与」で、最終判断は人間に委ねる。

これは試行錯誤の結果で、最初は「保護パス検出も強制 fail」にしていたんですが、たとえばこちらが意図的に保護パスを変更したい PR(CODEOWNERS の更新とか)を出したいときに、自分で書いた強制 fail に蹴られて「あ、これ自分だわ」と気づく、というマヌケな目に何度か遭いました。

結局、KAA は保護パスを「変更しちゃいけない」、人間は「変更するなら自覚的にやる」

——この二段構えにするのが、いちばん事故が少ない。CI で全部止めようとすると、自分が窒息する。

kaa-watchdog — KAAの「沈黙」を検知する仕組み

ここまで作って試運転を始めたら、想定外の落とし穴がひとつ見つかりました。KAA が "Needs attention" 状態でじっと黙ってるパターンです。

Kiro Web の KAA は、判断に迷うと自律的に作業を止めて人間からの追加指示を待つ、という設計になっています。これは安全機構として正しいんですが、「黙って待ってる」のは GitHub の側からは分からない。Issue にコメントが付くわけでもなく、ただ Kiro Web のタスク画面で "Needs attention" と表示されているだけ。佐渡で田んぼに出てる間にこの状態に入られると、ブラウザを開くまで気づかない。

そこで kaa-watchdog.yml を追加しました。

on:
  schedule:
    - cron: '*/15 * * * *'   # 15 分ごと
  workflow_dispatch:

やってることは単純で——

  1. 15 分ごとに kiro ラベル付きのオープン Issue を全部列挙
  2. 最終更新から 45 分経過していて、かつ対応する PR が未作成なら、Issue にコメント投稿
  3. 既に watchdog コメントを投稿済みの Issue はスキップ(重複防止)

コメント内容は「KAA が Needs attention で停止してるかもしれません、Kiro Web で状態確認してください」というやつ。GitHub の通知が普通に飛んでくるので、ブラウザを開くきっかけになる。

これも前回ブログの感覚を引きずってたら入れ忘れてた仕組みです。IDE 時代は「自分の目の前で止まる」ので watchdog は要らない。Web 時代は 「沈黙を検知する別の仕組み」が要る。当たり前といえば当たり前なんだけど、ツールが「同僚」に進化すると、勤怠管理の発想が必要になってくる。


PoC を回した結果 — 表記ゆれ統一から実コード変更まで

ここまでが Sprint 6 の Phase A〜F で組み立てた仕組みです。最後の Phase G で、実際に Issue を投げて PR が返ってくるところまで一直線で抜けるかを 2 段階で検証しました。

第 1 段階: EPIC-001 — aidlc-state.md の表記ゆれ統一

最初に投げたのは、わざといちばん小さい仕事。やることは aidlc-docs/aidlc-state.md の——

  1. チェックマーク形式を [x] に統一
  2. Current Stage の表記揺れ統一
  3. テーブルのヘッダー区切り( と - の混在)を統一

——これだけ。aidlc:bugfix Issue を起票して kiro ラベルを付与、Expert Review は「実施しない」を選択。KAA が kiro/issue-2-aidlc-state-notation ブランチを切って、24 行の差分の PR を作って、aidlc-pr-guard.yml が全部 ✓ で通過して、人間の再指示なしでマージまで到達しました(PR #3)。

第 2 段階: EPIC-002 相当 — 通知ページに「すべて既読にする」ボタン

第 1 段階が抜けたので、次は実際のアプリケーションコードに進みました。フロントエンドの通知ページに「すべて既読にする」ボタンを追加する、という機能追加 Issue(aidlc:feature、Expert Review「実施する」)。

これも KAA が kiro/issue-5-mark-all-notifications-read ブランチを切って、NotificationList.tsx / NotificationsPage.tsx を編集、テストファイル NotificationsPage.test.tsx を 110 行新規作成、計 130 行の差分の PR を作って完走(PR #6)。コードを 1 行も自分で書かずに機能が dev に乗りました。

落とし穴の発見と修正 — G-21

ただ、ここまで一直線で来たわけではなく、第 2 段階の epic-tracker.yml で問題が出ました。マージ後に親エピックのチェックリストが自動更新されない事象です。原因は単純で、epic-tracker.yml は最初「エピック本文に #N が記載されているか」だけで親エピックを特定していて、それ以外の関連付け方法を見ていなかった。

修正として、親エピック特定を 2 段階に強化しました。

  • 方法 A(従来):
    エピック本文の #N 記載から検索
  • 方法 B(新規):
    子 Issue の in-epic:EPIC-XXX ラベルから検索

それに合わせて Issue テンプレ(feature.yml / bugfix.yml)の冒頭に「起票後に in-epic:EPIC-XXX ラベルを付与すると、PR マージ時に epic-tracker.yml が親エピックを自動特定できます」というヒントを追加。

PoC をやらないと「動くかどうか」じゃなくて「どこで詰まるか」が見えない。Phase A〜F で立てた仕組みが机上で完璧に見えても、回してみると epic-tracker.yml の親特定ロジックみたいなピンポイントの抜けが出る。これが G-21 で見つかってよかった。


まとめ — Kiro Web を「同僚」にするのは、ツール導入ではなく制度設計

ふりかえると、Sprint 6 で書いたのは——

  • アプリケーションコード 0 行
  • GitHub Actions ワークフロー 6 本
    (labels-sync, issue-intake, context-bundler, aidlc-pr-guard, epic-tracker, kaa-watchdog)
  • .kiro/steering/ の新規 Markdown 2 本
    (aidlc-github-workflow.md, pr-contract.md)— 既存の 7 本(前回ブログで触れた expert-review.md 等)はそのまま流用
  • Issue テンプレ 3 種
    (epic / feature / bugfix)
  • CODEOWNERS 1 本
  • エピック管理ドキュメント 2 本
    (EPIC-template.md, EPIC-001.md)

これだけ。でも、これだけ揃えると 「Issue を投げると PR が返ってくる」という、別人のような開発体験が手に入る。24 行のドキュメント表記揺れ修正から、110 行のテスト追加付きフロントエンド機能まで、コードを 1 行も自分で書かずに dev に乗った

——というのを実機で確認できたのは、想像してたよりだいぶ未来の話でした。

Kiro Web のいちばんの発見は、これがツールというより制度に近いということでした。Kiro IDE を導入するのは「便利なエディタが増えた」だけだけど、Kiro Web を導入するのは「リポジトリに同僚を 1 人雇う」のと同じ意思決定で、雇用契約書(CODEOWNERS)、就業規則(.kiro/steering/)、業務指示書(Issue テンプレ)、勤怠管理(GitHub Actions の 6 本セット)が全部要る。watchdog(kaa-watchdog.yml)まで含めると、もう完全に労務管理の発想です。

逆に言うと、これらをちゃんと整備すれば、AWS Kiro は本気で同僚になる佐渡で田植えしてる間に PR が 1 本上がってるというのは、もう未来の話じゃなくて現状の話になりました。

※ 田んぼをこなしながら、時々ポケットのスマホからGithubで状況確認・カモメがくるのは田んぼをこなすと現れる虫やらカエルやらを狙ってのことと思われる・・・・。農地が中山間地のため大きな機械が使えず、終わると筋肉痛と筋力アップが漏れなくついてきます。