| name | law-search |
| description | This skill should be used when the user asks to "search a law", "法令検索", "条文を見せて", "法律を調べて", "○○法 第○条", "条文参照", "法令を確認", "何条に書いてある", or wants to look up Japanese law articles from the e-Gov API. |
| version | 1.2.0 |
法令検索(law-search)
e-Gov 法令 API を使用して、日本の法令条文を検索・取得・表示する。
データの取扱い
law-search の XML キャッシュはユーザー固有ディレクトリ ~/.claude-bengo/cache/law-search/ に 24 時間保存される。POSIX 上では所有者専用(0o700)で作成するため、共有 /tmp を経由した他ユーザーからの書込攻撃は防げる。暗号化ボリュームや事務所ポリシーで配置先を変更する場合は環境変数 CLAUDE_BENGO_CACHE_PATH で上書きできる。
整合性チェック(破損検出): 各キャッシュエントリ(例: law_{id}.xml, article_{id}_{article}.xml)には SHA-256 のサイドカー(<filename>.sha256)を併置する。書込は tmp + rename で原子的に行い、読取時には必ずサイドカーと本体のハッシュ一致を検証する。不一致・サイドカー欠落・TTL 超過のいずれかに該当すれば両ファイルを破棄して再取得扱いとする。
整合性チェックの限界(同一ユーザー権限の攻撃者には無力): サイドカーは自己チェックサムであり、HMAC や署名を含まない。従ってキャッシュディレクトリへ書込権限を持つ攻撃者(同一 OS ユーザーとして動作するマルウェア等)は、.xml と .sha256 の両方を一貫して書き換えることで改ざんを成立させ得る。この仕組みは破損検出(corruption detection)であり、敵対的改ざん検出(adversary detection)ではない。高信頼要求がある場合は以下を検討する:
手動で削除したい場合は次を実行する(サイドカーもまとめて削除される):
Bash: python3 skills/law-search/search.py clear-cache
特定の法令のみ削除する場合は --law-id 129AC0000000089 を付ける。オフラインの自己診断は python3 skills/law-search/search.py self-test で実行する。
キャッシュは ~/.claude-bengo/cache/law-search/ 配下に配置する。共有 tmp 上のキャッシュは信頼しない。
重要: トークン制限への対応
法令全文は絶対に Claude のコンテキストに載せない。 民法は 1000 条以上、会社法は 979 条あり、全文 XML は数 MB に達する。
必ず条文単位の API(/articles エンドポイント)経由で取得する。 トピック検索の場合のみ、全文 XML をローカルのキャッシュに保存してキーワード検索し、ヒットした条文だけを条文単位で取得する(search.py がこの流れを内部で実装している)。
ワークフロー
Step 1: ユーザーの意図を解析
入力パターンに応じて処理を分岐する:
| 入力パターン | 例 | 処理 |
|---|
| 法令名 + 条番号 | "民法709条" | → Step 2 → Step 3a(条文取得) |
| 法令名 + 条範囲 | "民法709条から711条" | → Step 2 → Step 3a(複数条文を個別取得) |
| 法令名のみ | "会社法" | → Step 2 → Step 3b(目次・概要を表示) |
| 条文の内容で検索 | "不法行為の条文" | → Step 2 → Step 3c(キーワードで条見出しを検索) |
| 不明な法令名 | "なんとか保護法" | → Step 3d(法令名の候補を提案) |
Step 2: 法令 ID の解決
2 段階で法令 ID を解決する:
Step 2a: 略称・別名の解決
skills/law-search/references/egov-api-guide.md を Read ツールで読み込み、略称マッピング(民訴法→民事訴訟法 等)とキーワード→条文マッピングを確認する。
Step 2b: 法令 ID の検索
skills/law-search/references/law-id-list.tsv に対して Grep ツールで法令名を検索する。このファイルには全 2,078 件の日本の法律の ID と正式名称が含まれている。
Grep: pattern="民法", path="skills/law-search/references/law-id-list.tsv"
結果例: 129AC0000000089 民法
重要: law-id-list.tsv は 157KB あるため、Read ツールで全文読込しない。必ず Grep で部分検索する。
law-id-list.tsv は skills/law-search/references/law-id-list.tsv の先頭行に # Generated: YYYY-MM-DD とあるはず。6 ヶ月以上経過している場合は e-Gov の最新法令リストから再生成を検討する。
Grep で見つからない場合:
- ユーザーに正式名称を確認する
- 部分一致で候補を提示する(例: Grep で "個人情報" → "個人情報の保護に関する法律" がヒット)
Step 3a: 条文取得(条番号指定あり)
1 条ずつ個別に取得する。 付属スクリプトを呼び出す:
Bash: python3 skills/law-search/search.py fetch-article --law-id 129AC0000000089 --article 709
スクリプトが以下を自動で処理する:
- URL の安全な組み立て(引数はシェル経由で展開されない)
- 24 時間キャッシュの参照・更新
- 429/5xx 系エラーの指数バックオフ再試行(最大 3 回)
- 30 秒タイムアウト
出力は条文の XML。stderr に JSON 形式のエラーを出した場合は status フィールドで失敗理由を判別する。
Cowork 環境での fallback (v3.7.1〜)
search.py は Cowork surface(CLAUDE_CODE_IS_COWORK=1)を検知すると、
urllib を呼ばず stderr 最終行に以下の JSON を emit して exit 0 する:
{"use_webfetch": true, "url": "https://laws.e-gov.go.jp/api/1/articles;lawId=...;article=...;", "law_footer": {...}}
stderr の最終行をパースし、use_webfetch == true の場合は Claude の
WebFetch ツール で同 URL を取得する(Anthropic infra 経由なのでサンドボックス
ネットワーク制約を迂回できる)。WebFetch で取得した XML を Step 3a の通常
ルートと同じく references/law-xml-structure.md のスキーマで解析する。
法令フッター(出典・参照日)は stderr の law_footer を元に組み立てるが、
retrieved_at は WebFetch 完了直後の現在時刻に上書きする(TBD ...
プレースホルダのまま表示しない)。cache_status は "webfetch (cowork)"
のまま表示する。
枝番号への対応: 例えば「民法 第 766 条の 2」は --article 766_2 と指定する(アンダースコア区切り)。
取得するデータの上限:
- 1 リクエストにつき 1 条文
- 1 回の会話で最大 5 条まで(ユーザーが追加を求めた場合は順次取得)
- 条範囲の指定("709 条から 711 条")は 1 条ずつ順次取得する
XML レスポンスの解析:
レスポンスは以下の構造を持つ。skills/law-search/references/law-xml-structure.md を参照して解析する。
<DataRoot>
<ApplData>
<LawContents>
<LawContentsArticle>
<ArticleTitle>第七百九条</ArticleTitle>
<ArticleCaption>(不法行為による損害賠償)</ArticleCaption>
<Paragraph>
<ParagraphSentence>
<Sentence>故意又は過失によって他人の権利又は...</Sentence>
</ParagraphSentence>
</Paragraph>
</LawContentsArticle>
</LawContents>
</ApplData>
</DataRoot>
表示形式:
## 民法 第709条(不法行為による損害賠償)
故意又は過失によって他人の権利又は法律上保護される利益を侵害した者は、
これによって生じた損害を賠償する責任を負う。
表示ルール:
## 法令名 第X条(条文見出し) をヘッダーとする
- 項(Paragraph)が複数ある場合は番号付きで表示:
1 ... 2 ...
- 号(Item)はインデントして表示:
一 ... 二 ...
- 但書は改行して表示
Step 3b: 法令概要(法令名のみ指定)
法令全文は取得しない。 代わりに:
references/egov-api-guide.md の法令情報テーブルから概要を提示:
- 法令名、法令番号、公布日、最終改正日
- 主要な章・編の構成(マッピングに含まれている場合)
- 「どの条文を参照するか?」とユーザーに確認する
- ユーザーが条番号を指定したら Step 3a で取得する
Step 3c: トピック検索(条番号不明の場合)
条番号がわからない場合、付属スクリプトで条見出し(ArticleCaption)をキーワード検索する。スクリプトが法令全文 XML をローカルキャッシュにダウンロードし、条見出しを走査して一致した条番号を JSON 配列で返す。
1. キーワード検索:
Bash: python3 skills/law-search/search.py search-keyword --law-id 129AC0000000089 --keyword 監護
出力例(JSON 配列):
[
{"article_num": "766", "caption": "(離婚後の子の監護に関する事項の定め等)"},
{"article_num": "880", "caption": "(事情変更による後見人の辞任及び監護者の変更)"}
]
該当条文がない場合は空配列 [] が返る。
2. ヒットした条文を Step 3a で取得する:
Bash: python3 skills/law-search/search.py fetch-article --law-id 129AC0000000089 --article 766
スクリプトが全文 XML を既にキャッシュしているため、同一会話内では再ダウンロードは発生しない。
利点:
- 法令全文を Claude のコンテキストに載せない(ローカルで検索)
- 1000 条超の民法でも条見出しを一瞬で検索可能
- 枝番号(第 766 条の 3 等)も
article_num に含まれる
- 429 / 5xx エラー時は自動リトライされる
注意:
- 法令全文 XML は 1〜5 MB。大きな法令は初回取得に数秒かかる
- キャッシュは 24 時間有効。期限切れは自動で再取得する
- キーワードは最大 50 文字。正規表現ではなく単純な部分一致である
Cowork 環境では未対応 (v3.7.1〜)
search.py は Cowork surface で search-keyword が呼ばれた場合、全文 XML
を DL せず以下を stderr 最終行に emit して exit 0 する:
{"degraded": true, "reason": "cowork_no_fulltext_search", "message": "..."}
stdout には空の JSON 配列 [] を出す。SKILL は message をユーザーへその
まま表示し、「条番号がわかっていれば fetch-article で取得できる」と案内
する。law-id-list.tsv の Grep は Cowork でも動作する(Read ツール経由)
ため、Step 2 の法令 ID 検索は影響を受けない。
Step 3d: 法令名の候補提案
ユーザーが正式名称を知らない場合(例: "なんとか保護法"):
references/egov-api-guide.md のマッピングから部分一致で候補を提示する
- 例: "保護" → 個人情報保護法、消費者契約法、労働者災害補償保険法、...
Step 3.5: 出力フッター(必須、v3.3.0-iter3〜 code-emitted)
search.py fetch-article は stdout に XML を書くのと同時に、stderr に
{"law_footer": {...}} の JSON を emit する(v3.3.0-iter3〜 search.py 側で
強制)。これにより prompt だけに依存せずメタデータが必ず用意される。
SKILL はこの stderr JSON をそのまま読み、条文表示の直後に以下の体裁で
要約・省略せずに ユーザーへ転記する:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
出典: {law_footer.source}
参照日: {law_footer.retrieved_at}
法令 ID: {law_footer.law_id} / 条文: {law_footer.article}
キャッシュ: {law_footer.cache_status}
⚠ {law_footer.warning}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
retrieved_at はキャッシュ再利用時も「本セッションで参照した時刻」として
記録される(court filing で引用する際、どの時点の法令を参照したかの証跡)。
Bash 呼び出しで stderr を捕まえる例:
STDOUT=$(python3 skills/law-search/search.py fetch-article \
--law-id 129AC0000000089 --article 709 2>/tmp/law-meta.json)
Step 4: 他コマンドとの連携
取得した条文は会話コンテキストに残る。以下のコマンドで活用可能:
/typo-check: 書面中の法令引用が正確か検証(条番号の存在確認)
/lawsuit-analysis: 主張の法的根拠として関連条文を自動参照
- ユーザーが「さっきの条文を準備書面に引用して」と言った場合に対応
エラーハンドリング
search.py は失敗時に stderr へ {"error": "...", "status": N} 形式の JSON を出力し、終了コードで種別を示す:
| 終了コード | 意味 | ユーザー向けメッセージ |
|---|
| 0 | 成功 | — |
| 1 | バリデーションエラー | 「法令 ID または条番号が不正である。例: 民法なら 129AC0000000089、条番号は 709 や 766_2。」 |
| 2 | ネットワークエラー(404 含む) | status=404 → 「指定された法令または条文が見つからなかった。法令名と条番号を確認してほしい。」 その他 → 「e-Gov 法令 API に接続できなかった。時間をおいて再試行してほしい。」 |
| 3 | XML パースエラー | 「e-Gov API からの応答を解析できなかった。別の条番号で試してほしい。」 |
ネットワークエラー時は既に 3 回までリトライ済みである。即時リトライは避け、時間をおくよう案内する。
次の一手(ユーザーに提案する)
条文表示の後に以下を提案する:
💡 次の一手:
- 関連訴訟文書の分析: /lawsuit-analysis <訴状・答弁書など>
- 書面への引用: /typo-check で引用形式(民法第709条等)をチェック
- 計算器との連携: 条文に基づく計算(相続・養育費・残業代等)は各種 /*-calc