この記事では、Claude CodeのSkill(Agent Skill)やCIを活用して、コードベースから外部連携の仕様書を自動生成・更新する仕組みを構築した取り組みを紹介します。
はじめに
こんにちは!ヘンリーで電子カルテ開発チームでエンジニアをしているわくわく(@wakwak3125 / @wakwakjp) です。
最近社内でのAI活用が進んでいており、 https://dev.henry.jp/entry/claude-code-orchestrator のような便利なSkillのおかげで開発自体の速度がぐんぐん上がっています。
一方で、まだまだ人の手で行われている部分が多いのも事実です。今回はその人力で行われていて、抜け漏れのチェックが非常にめんどくさい「仕様書」と呼ばれるもののメンテナンスを Claude Code, Skill, GitHub Actions を使い半自動化する仕組みをご紹介します。
Henryという電子カルテにおける仕様書とは
ここで言う「仕様書」はHenryの内部の仕様を解説したものではありません。ではなにかというと、外部のシステムとの連携に関する仕様書です。
電子カルテという製品は様々な周辺のソフトウェアと接続・連携して病院業務の中核を担います。一例としては、臨床検査システムや調剤システム、予約・問診システム、自動精算機などがあります。
連携がどのように実施されてるかに興味がある人は次の記事を読むと楽しめると思います。
https://dev.henry.jp/entry/2024/12/14/163949
https://note.com/henry_app/n/n29691b917b41
仕様書か管理の難しさ・煩雑さ
外部連携のインターフェイス仕様や連携を必要とされるお客様環境への導入プロセスにおける設定に必要なデータなどはHenryの機能追加などで変わっていきます。冒頭でも書きましたが開発プロセスへのAI活用のおかげでこれまででは考えられないような速度感の開発になりつつある中で
- 仕様書と実装に齟齬は無いか
- 仕様書に更新が必要な実装なのか
- 仕様書に変更がある場合の記載作業と記載内容のレビュー
- 仕様書の公開作業
といった作業に加えて、連携種類が増えた際の仕様書の追加がされた際のフォーマット・テイストの統一など品質面の調整の工数もかかります。
そこで、変更検知、仕様書作成・レビュー・公開の自動化フローを組みました。
全体像
このシステムは2つのスキルで構成されています。
| スキル名 | 役割 | 実行タイミング |
|---|---|---|
generate-integration-spec |
コードベースを探索し、仕様書を生成・更新する | 開発者がローカルで手動実行 |
spec-change-check |
PRの変更が外部連携仕様に影響するかを検知する | PR作成・更新時にCIで自動実行 |
この2つのスキルが連携することで、「仕様に影響する変更の検知 → 仕様書の更新」という一連のフローを実現しています。
flowchart TD
A[開発者がPRを作成] --> B[CI: spec-change-check が自動実行]
B --> C{外部連携仕様に影響あり?}
C -->|無関係| D[CIパス]
C -->|影響なし・更新不要| E[PRにコメント + CIパス]
C -->|影響あり・更新必要| F[PRにコメント + CI失敗]
F --> G[開発者が /generate-integration-spec を実行]
G --> H[仕様書が自動生成・更新される]
H --> I[更新された仕様書をコミット]
I --> D
F --> J[手動で仕様書更新 or SpecChangeApproved ラベル付与]
J --> D
spec-change-check: PRの仕様影響検知スキル
まず、CIで自動実行される検知側のスキルから説明します。
何をするスキルか
PRの差分(diff)を取得し、各連携の設定ファイル(spec-config.md)に定義された検知キーワードと照合することで、その変更が外部連携の仕様に影響するかを判断します。
動作フロー
sequenceDiagram
participant CI as GitHub Actions
participant Skill as spec-change-check
participant GH as GitHub API
CI->>Skill: PR番号を渡して起動
Skill->>Skill: spec-config.md をすべて読み取り
Skill->>GH: gh pr diff でPRの差分を取得
Skill->>Skill: 検知キーワードと差分を照合
Skill->>Skill: 変更判断基準に基づき更新要否を判定
alt 無関係
Skill->>CI: RESULT:NO_IMPACT
else 影響なし・更新不要
Skill->>GH: PRにコメント投稿
Skill->>CI: RESULT:NO_UPDATE_NEEDED
else 影響あり・更新必要
Skill->>GH: PRにコメント投稿(対応方法を案内)
Skill->>CI: RESULT:UPDATE_REQUIRED(CI失敗)
end
判定の仕組み
判定は次の3分類に分かれます。
- 無関係: NO_IMPACT
- 検知キーワード(クラス名やパッケージ名など)がPRの差分に含まれない
- 影響なし: NO_UPDATE_NEEDED
- 検知キーワード(クラス名やパッケージ名など)がPRの差分に含まれるが、仕様書への反映の必要が無い
- 影響あり: UPDATE_REQUIRED (CI失敗)
- 検知キーワード(クラス名やパッケージ名など)がPRの差分に含まれるが、仕様書への反映が必要
例えば、以下のような変更は仕様書更新不要と判定されます。
- リファクタリングのみ(外部仕様に影響しない内部構造の変更)
- テストの追加・修正のみ
- バグ修正(仕様通りに動くようにする修正)
一方、以下は更新必要と判定されます。
- データ構造・フォーマット・通信仕様の追加・変更
- 新しい連携先の追加
- エンティティの構造変更
設定の共有
重要なポイントとして、spec-config.md が**両スキル共通の設定ファイルとして機能しています。検知キーワードや変更判断基準をここに集約することで、検知と生成の整合性が保たれます。
generate-integration-spec: 仕様書生成スキル
こちらが本記事の主役です。コードベースを探索し、その事実に基づいて仕様書を生成・更新します。
使い方
/generate-integration-spec specimen-inspection all
- 第1引数: 連携種別(例:
specimen-inspection) - 第2引数: 対象の仕様書名(省略時は
all) -force: 変更検知をスキップして強制生成
オーケストレーション全体像
このスキルの内部では、オーケストレーター(メインのスキル本体)が3つの専門エージェントを順番に起動するマルチエージェント構成を採用しています。
flowchart TB
subgraph Orchestrator["オーケストレーター (SKILL.md)"]
S1["Step 1: 設定読み込み spec-config.md / spec-template.md"]
S2["Step 2: 変更検知 git diff + .generation-state.json"]
S3["Step 3: コードベース探索"]
S4["Step 4: 仕様書生成"]
S5["Step 5: レビュー"]
S6["Step 6: 生成状態記録"]
S7["Step 7: ユーザーへ報告"]
end
subgraph Agents["専門エージェント"]
EA["探索エージェント (explore.md)"]
GA["生成エージェント (generate.md)"]
RA["レビューエージェント (review.md)"]
end
S1 --> S2 --> S3
S3 -.->|"Task(Explore)"| EA
EA -.->|構造化された事実一覧| S3
S3 --> S4
S4 -.->|"Task(general-purpose)"| GA
GA -.->|生成ファイル一覧| S4
S4 --> S5
S5 -.->|"Task(general-purpose)"| RA
RA -.->|"APPROVED / NEEDS_REVISION"| S5
S5 -->|APPROVED| S6
S5 -->|"NEEDS_REVISION 最大2回リトライ"| S4
S6 --> S7
以下、各ステップを詳しく見ていきます。
Step 1: 設定読み込み
2つの設定ファイルを読み取ります。
spec-config.md: 連携の概要、検知キーワード、バージョン定義、仕様書構成spec-template.md: 各仕様書のテンプレート(セクション構成や表のフォーマット)
これらのファイルは docs/external-integration/{連携種別}/config/ 配下に配置されており、連携ごとに独立しています。新しい連携種別を追加する場合は、このディレクトリに設定ファイルを追加するだけでスキル本体の変更は不要です。
Step 2: 変更検知
前回の生成時のコミットハッシュを .generation-state.json に記録しており、そこからの差分を git diff で取得します。差分がなければ生成をスキップし、不要な再生成を防ぎます。
{ "commitHash": "abc1234...", "generatedAt": "2026-02-15T10:30:00Z", "specs": { "v2/overview.md": { "commitHash": "abc1234...", "generatedAt": "2026-02-15T10:30:00Z" } } }
仕様書単位でコミットハッシュを記録しているため、特定の仕様書だけをターゲットにした差分検知も可能です。
Step 3: 探索エージェント
ここからが本スキルの核心部分です。探索エージェントは、コードベースから連携に関する事実を徹底的に収集する専門エージェントです。
flowchart LR
subgraph Input
KW[検知キーワード]
VER[バージョン定義]
end
subgraph ExploreAgent["探索エージェント"]
direction TB
GrepGlob["Grep / Glob で<br/>キーワード検索"]
Collect["情報収集"]
Classify["バージョン分類"]
end
subgraph Output["構造化された事実一覧"]
E1[エンティティ・値オブジェクト]
E2[リポジトリ]
E3[サービス・UseCase]
E4[Enum クラス(全値)]
E5[GraphQL スキーマ]
E6[テーブル定義]
E7[フォーマット実装]
end
KW --> GrepGlob
VER --> Classify
GrepGlob --> Collect --> Classify --> Output
収集する情報
| カテゴリ | 収集内容 |
|---|---|
| エンティティ | クラス名、パッケージ、主要プロパティ |
| リポジトリ | インターフェースと実装、メソッドシグネチャ |
| サービス/UseCase | クラス名、メソッド、依存関係 |
| Enum | 全値を省略せず列挙(値のプロパティ含む) |
| GraphQL | Query/Mutation/Type/Input 定義 |
| テーブル定義 | カラム定義、インデックス |
| ファイルフォーマット | 連携ファイルのビルダーやパーサーの実装、フィールド定義 |
探索エージェントの出力は特別な解釈はせずに、ありのままを出力します。ファイルパスと行番号が必ず含まれ、後続のエージェントがコードを参照できるようになっています。
Step 4: 生成エージェント
生成エージェントは、探索エージェントの出力とテンプレートを組み合わせて仕様書を生成します。
更新の原則
自動生成による更新の問題点として毎回作られる仕様書に小さな表現の差が生まれるというのがあります。これは一定仕方ない部分なので次の仕組みをプロンプトに組み込むことで大幅なテイスト変更などが発生しづらい仕組みにしています。
- 既存ファイルがある場合は差分更新(変更箇所のみ Edit)
- 新規ファイルはこの制限を受けない
- コードから読み取った事実のみを記載
- 推測が含まれる場合は
[要確認]マーカーを付与- これを見て人間がレビューをする
生成される成果物(検査システムの例)
docs/external-integration/{連携種別}/
├── config/
│ └── spec-config.md # 設定(入力)
├── template/
│ └── spec-template.md # テンプレート(入力)
├── v2/ # バージョン別ディレクトリ
│ ├── overview.md # 概要
│ ├── master-data.md # マスターデータ仕様
│ ├── request-formats.md # リクエストフォーマット
│ ├── report-formats.md # 結果報告フォーマット
│ ├── data-flow.md # データフロー
│ ├── external-spec.md # 外部公開用仕様書
│ ├── laboratories/ # 連携先別仕様
│ │ ├── lab-a.md
│ │ └── lab-b.md
│ └── sample/ # CSVサンプル等
└── .generation-state.json # 生成状態
外部公開用仕様書(external-spec.md)の特別な扱い
external-spec.md は連携先企業や医療機関との打ち合わせで使用する外部向け仕様書です。以下のルールが適用されます。
- 内部システム名(
general-api等)を含めない - 特定の連携先の会社名・システム名を含めない
- フォーマット名に特定企業名を使わず、技術的特徴で命名する
- 非技術者にもわかる具体例を併記する
- 更新履歴テーブルを自動で管理する(版数のインクリメント含む)
Step 5: レビューエージェント
生成された仕様書を、再度コードベースと突合してレビューします。人間のレビュアーと同様に、複数の観点から検証を行います。
flowchart TB
subgraph Review["レビュー観点(6つ)"]
R1["正確性<br/>コードとの突合"]
R2["網羅性<br/>漏れの検出"]
R3["一貫性<br/>用語の統一"]
R4["外部公開適切性<br/>内部情報の漏洩チェック"]
R5["テンプレート準拠<br/>構造の正しさ"]
R6["[要確認] 検出<br/>マーカーの適切性"]
end
Review --> Decision{判定}
Decision -->|問題なし| Approved["APPROVED<br/>→ Step 6へ"]
Decision -->|問題あり| NeedsRevision["NEEDS_REVISION<br/>→ 指摘付きで Step 4 へ差し戻し"]
6つのレビュー観点
- 正確性: コードと一致するかを実際のコードを検索して突合する
- 網羅性: 関連するクラス・メソッド・Enum値が仕様書に漏れなく反映されているか
- 一貫性: ドキュメント間で同じ概念に対して異なる用語が使われていないか
- 外部公開適切性: 内部実装の詳細(クラス名、パッケージ名等)が外部向け仕様書に漏れていないか
- テンプレート準拠: テンプレートで定義された構造に従っているか
[要確認]検出: 推測に基づく記述に適切にマーカーが付いているか、逆に確認済みの事実に不要なマーカーがないか
リトライ機構
レビューで NEEDS_REVISION が返された場合、指摘事項を生成エージェントにフィードバックし、修正を依頼します。このリトライは最大2回まで行われ、それでも解決しない指摘はユーザーに報告されます。
Step 6-7: 状態記録と報告
生成完了後、.generation-state.json にコミットハッシュとタイムスタンプを記録し、次回の変更検知に備えます。最後にユーザーに生成結果を報告して完了です。
アーキテクチャの設計思想
マルチエージェント構成を選んだ理由
次の観点で、仕様書生成を1つの巨大なプロンプトで行うのではなく、探索・生成・レビューの3つの専門エージェントに分割しました。
- コンテキストの分離: 各エージェントが専門領域に集中でき、プロンプトの肥大化を防ぐ
- リトライの効率化: レビューで問題が見つかった場合、生成エージェントだけを再実行すれば良い
- 並列実行: 探索エージェント内部では、複数のキーワード検索を並列に実行できる
- 保守性: 各エージェントのプロンプトは独立したMarkdownファイルとして管理され、個別に改善できる
とはいえ、最初からマルチエージェントで組んだわけでは無くシングルエージェント構成で詰めてからより効率化と堅牢な設計のために途中で分割していきました。
(本当は最初からもう少し設計を詰めてからやるべきだったかなとも思っていますが、まだ初心者なので勘所がわかってない。)
設定ファイル駆動
spec-config.md と spec-template.md を外部設定として分離することで、新しい連携種別を追加する際にスキル本体を一切変更する必要がありません。設定ファイルを追加するだけで、同じオーケストレーションフローが適用されます。
まとめ
generate-integration-spec スキルは、以下の流れで仕様書を自動生成します。
- 設定読み込み → 何を探索し、どう仕様書を構成するかを把握
- 変更検知 → 不要な再生成を防止
- 探索エージェント → コードベースから事実を収集
- 生成エージェント → テンプレートに沿って仕様書を生成
- レビューエージェント → コードと突合して品質を検証(最大2回リトライ)
- 状態記録 → 次回の差分検知に備える
そして spec-change-check スキルがCIでゲートキーパーとして機能し、仕様影響のある変更が仕様書更新なしにマージされることを防ぎます。
この2つのスキルによって、「コードと仕様書が常に同期している」という状態を、開発者に大きな負担をかけることなく維持できるようになりました。