0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

社内の勤怠管理システムを、AWSのAgentic IDE Kiro で作っています。

Excelテンプレートへの出力、残業申請の承認フロー、5種類のロール権限、月次締め処理……と要件を詰めていったら、画面設計書だけで6画面分、共通ルールとDBスキーマを含めて数百行の設計書ができあがりました。

それを目の前にして、ふと不安になりました。

これ、一気にKiroに流したら混乱するのでは?

結論から言うと、この直感は正しかったです。そして「じゃあどう分けるのか」を考えた結果、Kiroの Steering という機能の本当の使いどころが見えてきました。

この記事では、以下を実例つきで書きます。

  • 巨大な設計書を Steering と Spec にどう分解したか
  • Steeringに何を書き、何を書かなかったか
  • AIが誤解した箇所をSteeringに「書き戻す」運用サイクル
  • .kiro の場所を勘違いしていた話(やらかし)

対象読者は、KiroやCursor、Claude Codeなどでそこそこの規模のシステムを作ろうとしている人です。ツールは違っても、ルールファイル(.cursorrulesCLAUDE.md など)を持つツールなら考え方はそのまま応用できます。

環境

  • Kiro(2025年7月プレビュー公開 → 2025年11月GA)
  • 2026年7月現在、IDE / CLI / Web / モバイル(iOS) の4インターフェース
  • 本記事はIDE版が前提
  • 対象プロジェクト: Spring Boot 3.x + React(MUI) + PostgreSQL / Docker / VPS

セキュリティ注記: 2026年4月に細工されたプロジェクトファイルによる任意コード実行の脆弱性(CVE-2026-4295)が報告されています。v0.8.0で修正済みなので、古いバージョンを使っている人は先にアップデートしてください。外部から受け取ったプロジェクトを開く運用をしているなら特に。


1. なぜ一気に流してはいけないのか

起きること

6画面分の設計書+共通ルール+スキーマを1つのSpecに突っ込むと、こうなります。

① 序盤の制約を忘れる

タスクが数十個規模に膨らむと、コンテキストの前方にある指示ほど効きが薄れます。「テンプレートは新規生成せず既存ファイルに書き込む」という最重要ルールを冒頭に書いていても、後半のタスクではしれっと無視されます。これはAIの構造的な性質なので、書き方を工夫しても限界があります。

② 依存関係を無視した順序で作り始める

計算ロジックが存在しないのに、それを表示する画面から作り始めたりします。人間なら「まず計算からだろう」と考えますが、設計書に並んでいる順に着手されると、後で全部やり直しになります。

③ 失敗の切り分けができない

巨大な1回の生成が微妙な出来だったとき、どの指示が悪かったのか特定できません。全部投げ直すことになります。

分解の軸は「寿命」

じゃあどう分けるか。ファイル数や画面数で機械的に割るのではなく、その指示の寿命で分けるのが正解でした。

Spec Steering
役割 今回作る機能の指示書 常に守るルール
効く範囲 そのSpecの作業中だけ 全Spec・全チャット・全生成に常時
寿命 実装完了で役目を終える プロジェクトが続く限り有効
「勤怠計算サービスを作れ」 「秘密情報を直書きするな」

Steeringは .kiro/steering/ に置いたMarkdownで、そのプロジェクトの全AI対話に常時注入される永続システムプロンプトとして機能します。

図にするとこうです。

例えるなら、Specが作業員に渡す作業指示書で、Steeringは壁に貼ってある安全規則です。作業指示は現場ごとに変わりますが、安全規則は毎回貼り直しません。


2. 実際の分解

数百行の設計書を、こう振り分けました。

Steering: 4本に分けた

.kiro/steering/
├── template-output.md   … Excelテンプレート出力の鉄則
├── security.md          … 秘密情報の扱い・SSH・配信設定
├── domain-rules.md      … 業務ルール(権限・残業計算・締め処理)
└── ui-standards.md      … UI標準(色・書式・確認ダイアログ)

分け方の基準は「将来これだけ差し替えることがあるか」です。UIフレームワークを変えるなら ui-standards.md だけ書き直す、業務ルールが変わるなら domain-rules.md だけ、という単位にしておくと保守が楽になります。

中身の雰囲気はこんな感じです(domain-rules.md から抜粋)。

## ロールと権限(5ロール固定)
- Role: ADMIN / SOMU / DEPT_MANAGER / LEADER / MEMBER
- 参照系APIは必ず visibleEmployeeIds を経由する
  (画面側の出し分けだけで制御しない)
- スコープ外のID直接指定は404を返す(403ではなく。存在自体を隠す)
- ロールの追加・変更はこのsteeringの更新を伴う(コードだけで増やさない)

最後の行がポイントです。「ルールを変えたければここを直せ」と書いておくと、AIが勝手にロールを増やす方向に流れにくくなります。

Spec: 依存順に6本

① ドメイン基盤    … スキーマ + 計算ロジック(画面なし・テストまで)
② 勤務表入力画面   … ①に依存
③ 残業申請+承認   … ①②に依存
④ 外部連携アダプタ … ③に依存
⑤ 締め+帳票出力   … ①〜③に依存
⑥ 一覧・管理画面   … 全部に依存

①を最初に完成させるのが肝でした。計算ロジックは全画面が依存する心臓部なので、ここだけは画面なしで単体テストまで固めてから次に進みます。逆にここが曖昧なまま画面を作らせると、Kiroが画面ごとに微妙に違う計算を勝手に実装するという最悪のパターンに入ります。

二重に書かない

分解で一番気をつけたのは同じルールを両方に書かないことです。

Specには「詳細ルールはsteeringを参照」とだけ書きます。両方に書くと、片方だけ直したときに食い違って、AIがどちらに従うか揺れます。真実の源はひとつ、が鉄則です。


3. 流し方:tasks.mdで一度止める

Kiroの仕様駆動開発は requirements.mddesign.mdtasks.md → 実装 と進みます。ここでtasks.mdの生成後に必ず人間が確認するのを挟みます。

最初のプロンプトはこれだけです。

.kiro/specs/domain-foundation/ の実装を開始してください。
既存の実装は参照せず、steeringとこのspecのみに従ってください。
まずtasks.mdを生成して見せてください。

チェックするのは3点。

  1. スコープ外(このSpecでは画面)を作ろうとしていないか
  2. 依存順(スキーマ → 計算 → テスト)になっているか
  3. 要件に書いた具体的なテストケースがタスクに入っているか

3番目について補足すると、requirements.mdに期待値つきの実例を1つ書いておくと精度が跳ね上がります。

テストには以下の実例ケースを必ず含める SHALL:
- 中抜けケース: 9:00出勤・21:30退勤・休憩12:00-13:00・中抜け17:30-19:30、
  所定17:30退勤(所定実働7.5h)
  → 実働9.5h / 申請残業2.0h / 換算退勤19:30 / 給与残業1.5h

計算ロジックをAIに書かせるとき、正解の数値が1組あるだけで結果が安定します。


4. 本題:AIが誤解した箇所こそSteeringに書く

ここからが実際にやってみて一番の学びでした。

事例1:名前が仕様を誤解させる

Specに「月40h相当超過(シフト勤務)」という項目を書いていました。すると実装中にKiroから質問が来ます。

「月の実働合計が月40h相当を超えた分」として設計しました。実務上の意図は「所定実働合計 + 40h」でしょうか?

どちらも違います。正解はこうでした。

月法定基準超過 = max( 月実働合計 − 月の日次残業合計 − 所定労働日数 × 8h, 0 )

式に 40という数字は出てきません。「40h相当」は「週40h ≒ 1日8h×5日」という換算の名残で、月版では「所定労働日数×8h」がその基準になります。名前だけが独り歩きしていたわけです。

さらにKiroの解釈には日次残業の控除が抜けていました。これを省くと、すでに日次残業としてカウント済みの時間を二重計上します。

ここで大事なのは、Specだけ直して終わりにしないことです。名前が誤解を生んだのだから、名前と式の両方をSteeringに書き戻します。

- 週40h超過(通常) / 月法定基準超過(シフト)は別枠として集計し、合算しない
  - 週40h超過 = Σ各週 max(週実働合計 − 週の日次残業合計 − 40h, 0)
  - 月法定基準超過 = max(月実働合計 − 月の日次残業合計 − 所定労働日数 × 8h, 0)
  - いずれも法定8h基準で計算する(所定実働7.5hではない)
  - 日次残業の控除は必須(二重計上防止)

名前だけ変えても意味がないのがポイントです。式が書かれていなければ、次に読んだAIがまた推測します。

事例2:粒度の勘違い

もうひとつ。締め処理の編集可否判定で、Kiroからこんな確認が来ました。

手動締めは日時で設定されるので、時刻粒度の締め切りを持つ形であってますか?

これも違いました。手動締めは「その時刻までは編集可」という締め切り時刻ではなく、「締めた」という状態の記録です。総務が締めボタンを押した瞬間から編集不可でなければ困ります。

public boolean isEditable(LocalDate targetDate) {
    var closing = repo.find(YearMonth.from(targetDate));
    // 手動締め済み → 存在するだけで編集不可(時刻比較しない)
    if (closing != null && closing.manuallyClosedAt() != null) return false;
    // 未締め → 自動締め日(翌月第2営業日)の終端まで編集可
    return !LocalDate.now().isAfter(resolveAutoClosingDate(...));
}

これもSteeringに書き戻しました。

- 手動締め(manually_closed_at)は「締め切り時刻」ではなく「締められた記録」。
  値が存在する時点で時刻比較せず編集不可とする
  (resolveClosingDate の戻り値との日付比較だけで判定しない)

運用サイクルとして

この2件から見えたのは、こういうサイクルです。

steering_writeback_cycle.png

★の一手間が効きます。 Specだけ直すと、次に別のSpecを作るときに古い理解から誤りが再生産されます。Steeringは全Specに効くので、ここに書けば一度で終わります。

余談ですが、この2件の質問はどちらもKiroが自発的に確認してきたものです。Steeringを読んで整合性をチェックできている証拠でもあるので、ルールファイルが機能しているサインとして受け取っています。


5. やらかし:.kiro の場所を勘違いしていた

正直に書きます。

私はしばらく、.kiro の下にプロジェクトを置くものだと思っていました。

~/Documents/Kiro/          ← ここがKiroのホームだと思っていた
├── .kiro/
├── 勤怠システムのソース
├── counter-app/           ← 別の練習用アプリまで同居
└── ...

正しくは逆で、各プロジェクトが .kiro を1つずつ持ちます.git.vscode と同じです。プロジェクトフォルダをKiroで開くと、その配下に .kiro/ が自動生成されます。

my-project/
├── .kiro/
│   ├── steering/   ← プロジェクトルール
│   ├── specs/      ← 仕様書
│   ├── hooks/      ← 自動化トリガー
│   └── skills/     ← カスタムコマンド
├── src/
└── README.md

なぜ勘違いしたか(半分は正しかった)

言い訳させてください。~/.aws~/.ssh のように、ドット始まりのフォルダはホーム直下の共通設定という先入観がありました。

そして調べたら、実際にグローバルな ~/.kiro/ は存在します

~/.kiro/skills/     ← どのプロジェクトでも使えるカスタムコマンド

Skillsにはグローバル領域があるんです。だから「.kiro はホームにあるもの」という感覚自体は半分正しくて、Steeringとspecsはプロジェクト単位というのが正解でした。

この勘違いの実害

放置していたらどうなったか。

複数のシステムが1つのリポジトリに同居すると、Steeringが混ざります。勤怠システムの「テンプレートは不変のシェルとして扱う」「残業は二基準で管理」みたいな固有ルールが、まったく関係ない別アプリの開発に注入されます。無関係なコードがコンテキストに入るほど、精度も落ちます。

正しくはこうです。

~/Documents/projects/
├── attendance-system/    ← .kiro/steering は勤怠のルール
│   └── .kiro/
└── backend-lecture/      ← 完全に独立
    └── .kiro/

ただしSecurityだけは使い回す

とはいえ、4本すべてがプロジェクト固有かというとそうでもありません。

  • 持ち出せない: template-output.md(あのExcel専用)、domain-rules.md(勤怠の業務ルール)
  • 持ち出せる: security.md の大部分

秘密情報を直書きしない、環境変数から読む、.env はgit管理外、AIのセルフチェックは一次フィルタで最終ゲートは人間——これらは次に何を作るときも同じです。

なので security.md個人の汎用テンプレートとして手元に保管しておき、新しいプロジェクトを始めるたびにコピーして置く運用にしました。毎回考え直さなくて済みます。


6. 開発が終わってからが本番

最後にひとつ。「開発が完了したらSteeringは消すべきか」を考えたのですが、答えは残すでした。

Specは今回の実装限りなので、完了したらアーカイブでいいです。でもSteeringの本当の出番は完了後に来ます。

半年後にバグ修正でAIを使うとき、来年機能を追加するとき、モバイル版を作るとき——そのときSteeringがなければ、AIは何の制約も知らないままコードを書きます。テンプレートを作り直す実装に逆戻りしたり、権限フィルタを通さないAPIを足したりする危険が復活します。

ただし完了時に整理はします。

  • 残す: 恒久的なルール(大部分)
  • 削る: 移行期限定の記述。古いルールが残っている方が有害で、AIが不要なコードを書く原因になる
  • 足す: 開発中にAIが誤解した箇所(前述のサイクル)

Steeringは書いたら終わりの設定ファイルではなく、プロジェクトと一緒に育てる資産です。.kiro/ は当然gitにコミットします。


まとめ

  • 巨大な設計書を一気に流すと、序盤の制約を忘れ、依存順が崩れ、失敗を切り分けられなくなる
  • 分解の軸は寿命。常に守るルール=Steering、今回作る機能=Spec
  • Steeringは一括配置(順番なし)、Specは1本ずつ完了確認しながら
  • 同じルールを両方に書かない(真実の源はひとつ)
  • AIが誤解した箇所こそSteeringに書き戻す。Specだけ直すと誤りが再生産される
  • 名前だけでなく式や定義まで書く。名前は独り歩きする
  • .kiro はプロジェクトごと。ただしSkillsにはグローバル領域がある
  • Steeringは開発完了後も残す。運用フェーズこそ本番

Kiroに限らず、ルールファイルを持つAIコーディングツールなら同じ考え方が使えるはずです。「AIが間違えたらルールに昇格させる」——このサイクルを回し始めてから、同じ指摘を二度しなくて済むようになりました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?