Claude CodeでVB6のコードを読み仕様書に起こす — イベント表と業務ルール表にする
VB6の.frm・.bas・.clsをClaude Codeに読ませ、イベント→処理→参照テーブルの表と業務ルール表に起こす手順。読み取り専用のサブエージェントをフォーム単位で回し、文字コードと抜け漏れの検算までまとめます。
VB6の古いコードから仕様書を起こすなら、成果物を「イベント表」と「業務ルール表」の2枚に分けると読み取りが安定します。イベント表は、どのコントロールのどのイベントで、どの処理が走り、どのテーブルを触るかを1行ずつ並べたものです。業務ルール表は、コードに埋まった条件分岐や計算式を、日本語の規則として一覧にしたものです。
Claude Codeには、この2枚を作る読み取りだけを任せます。ソースを書き換える権限は渡しません。この記事では、読み取り専用のサブエージェントの定義、フォーム単位の分担、文字コードの落とし穴、表の抜けを数で検算する方法を順に示します。
仕様書を「イベント表」と「業務ルール表」に分ける理由
VB6のプログラムは、画面(.frm)のイベントプロシージャに処理が散らばっています。共通処理は標準モジュール(.bas)やクラス(.cls)にあります。上から順に読んで文章にまとめると、どの操作がどの処理につながるのかが追えなくなります。
そこで、読み方の軸を2つ決めます。
| 表 | 1行の単位 | 主な列 |
|---|---|---|
| イベント表 | 1行の単位1つのイベントプロシージャ | 主な列画面・コントロール・イベント・呼ぶ処理・参照するテーブル |
| 業務ルール表 | 1行の単位1つの判定や計算 | 主な列ルール文・条件・メッセージ・根拠の位置 |
イベント表は機械的に作れるので抜けを数で検算できます。業務ルール表は解釈が入るので、根拠となるファイルと行を必ず添えさせます。人が確認するのは、この根拠の行です。
読む前に済ませる準備 — 文字コードと作業コピー
日本語環境で作られたVB6のソースは、Shift_JIS(CP932)で保存されていることがあります。Claude Codeのツールの扱いを知っておくと、準備の理由が分かります。
Readは、読めないバイト列を置換文字(U+FFFD)にして見せます。EditとNotebookEditは、UTF-8でないファイルの変更を拒否します。Shift-JISで保存された日本語を含むファイルがこれに当たります。WriteでShift-JISのファイルを置き換えると、新しい内容はUTF-8で保存され、元の文字コードは失われます。
読むだけの作業でも、原本を直接渡す理由はありません。原本とは別のディレクトリにUTF-8へ変換したコピーを作り、読ませるのはそちらだけにします。
mkdir -p spec-src
for f in src/*.frm src/*.bas src/*.cls; do
iconv -f CP932 -t UTF-8 "$f" > "spec-src/$(basename "$f")"
done
grep -c $'\xef\xbf\xbd' spec-src/* | grep -v ':0'最後の行は、変換後のファイルに置換文字が残っていないかの確認です。何も出なければ変換できています。CP932で表せない文字が混じっていると、iconvがエラーを返します。
フォームの見た目を持つ.frxはバイナリなので、読ませる対象に入れません。画面の項目名はテキストの.frm側にも書かれています。
読み取りだけのサブエージェントを定義する
サブエージェントは .claude/agents/ にMarkdownで置きます。必須の項目は name と description で、tools を書けば使えるツールを絞れます。
---
name: vb6-form-reader
description: VB6のフォーム1つを読み、イベント表と業務ルール表を返す。ソースは変更しない
tools: Read, Grep, Glob
permissionMode: plan
---
あなたはVB6の読解担当です。渡された.frmを1つ読み、次の2つの表を返します。
1. イベント表: 画面 | コントロール | イベント | 呼ぶ処理 | 参照テーブル
2. 業務ルール表: ルール文 | 条件 | メッセージ | 根拠(ファイル:行)
- 呼び先がmodule(.bas)やclass(.cls)にあるときは、そこも読んで追う
- SQL文字列からテーブル名を拾う。組み立て式で分からないときは「要確認」と書く
- コードに書かれていない目的や背景を推測で書かない
- ファイルは書き換えない。表をそのまま返す権限の掛け方は二重にしています。tools でRead・Grep・Globだけを許可すれば、書き込み系のツールはそもそも使えません。そのうえで permissionMode: plan を指定し、読み取り専用の探索モードに入れます。
permissionMode には注意点があります。メインの会話が bypassPermissions、acceptEdits、auto modeのいずれかで動いているときは、サブエージェントも同じモードで動き、指定は無視されます。メインがplan modeなら、サブエージェントも指定にかかわらずplan modeのままです。メインが通常のモードのときだけ、指定した値が効きます。
つまり、permissionMode: plan だけを頼りにすると、メインの設定次第で効かなくなります。読み取り専用の担保は tools の許可リストに置くのが確実です。
Bashを許可リストに入れていない点も意図しています。grepやwcが必要になったときは、メイン側で実行します。
組み込みのExploreやPlanではなく自作する理由
Exploreは読み取り専用の探索役で、WriteとEditが拒否されます。Planもplan mode中の調査役として同じく読み取り専用です。ただし、この2つはCLAUDE.mdを読み込まずに始まります。
自作のサブエージェントは、omitClaudeMd を指定しない限りCLAUDE.mdを読み込んで始まります。表の列名や「要確認」の書き方といった書式の決まりを、CLAUDE.mdに一度書いておけば、全フォームの読み手に同じ書式が届きます。
## VB6仕様書の書式
- 表はMarkdown。列名は固定: イベント表=画面|コントロール|イベント|呼ぶ処理|参照テーブル
- 根拠は「ファイル名:行番号」で書く
- テーブル名が動的に組み立てられているときは「要確認(動的SQL)」と書く
- 推測で補った記述には「推測」と付ける最初にプロジェクトファイルで読む範囲を決める
フォームに入る前に、メインの会話でプロジェクトファイル(.vbp)を読ませます。一覧に出てくるフォーム、モジュール、クラスの数が、後で検算する母数になるからです。起動時に最初に開くフォームも.vbpに書かれているので、仕様書の「画面遷移の入口」として先頭に置けます。
spec-src/の.vbpを読み、フォーム・標準モジュール・クラスの一覧と、
起動時に最初に開くフォームを表にしてください。ソースの読解はまだしないでくださいこの一覧を docs/spec/00-index.md として保存しておけば、フォームごとの表が揃ったときに、一覧との差で未着手のファイルが分かります。グローバル変数を多用した作りでは、標準モジュールの Public 変数が画面をまたいだ状態になります。これは1つのフォームを読むだけでは見えません。標準モジュールを専任で読む担当を別に1回走らせ、変数名と使われている画面の対応を、フォームの表とは別の表にしておくと後で効きます。
フォーム単位で分担して表を集める
サブエージェントは、メインの会話とは別のコンテキストで動きます。大きなソースをフォームごとに読ませても、読んだ全文はメインに残らず、返ってくるのは表だけです。
依頼は、フォーム名を列挙して並列に調べさせる形が基本です。
vb6-form-readerサブエージェントを使い、spec-src/にある次のフォームを
並列で読んでください。各フォームの結果は、イベント表と業務ルール表を
そのまま返してください: frmOrder, frmCustomer, frmInvoice並列に回すときの条件は2つあります。調査の経路が互いに独立していること、そして結果が返るたびにメインの会話の文脈を消費することです。詳細な表を返すサブエージェントを大量に走らせると、メインの文脈が先に埋まります。
同時に走らせられるサブエージェントは、既定で20個までです。フォームが数十ある画面群でも、1回の依頼に入れるのは数個から十数個に留め、終わったものから次を依頼するほうが扱いやすくなります。
読み取り専用に絞ったので、サブエージェントは仕様書のファイルを書けません。表を docs/spec/frmOrder.md のように保存するのは、メインの会話の役目です。
返ってきた表の抜けを数で検算する
イベント表は、行数をソースの数と突き合わせれば検算できます。VB6のイベントプロシージャは Private Sub コントロール名_イベント名( の形で宣言されます。
grep -c -E '^(Private|Public) Sub ' spec-src/frmOrder.frm
grep -c '^|' docs/spec/frmOrder.md1行目は宣言の数、2行目は表の行の数です。表には見出し行と区切り行があるので、イベント表だけを別ファイルに保存してから比べます。共通処理の Sub はイベントではないため、数が一致しなくても不具合とは限りません。差が出たときは、メインの会話にその差分を渡して、どの宣言が表に載っていないかを探させます。
業務ルール表は数で検算できません。確認の対象は根拠の行です。
- 表の中から数行を選ぶ
- 根拠の
ファイル:行を開く - そのルール文が、その行の条件と一致しているかを見る
ルール文に、コードに無い目的や理由が混じっていれば、サブエージェントの出力に「推測」の印が付いているはずです。付いていなければ、指示が守られていません。
出力の形の例
次は、架空の受注入力フォームから起こす例です。フォームの宣言は、実際のVB6の.frmの形式に沿っています。
Private Sub cmdRegister_Click()
If Val(txtQty.Text) <= 0 Then
MsgBox "数量を入力してください"
Exit Sub
End If
If CalcCredit(cboCustomer.ItemData(cboCustomer.ListIndex)) > 1000000 Then
MsgBox "与信限度額を超えています"
Exit Sub
End If
SaveOrder
End Subこの宣言から、次のような表が得られるのが期待する形です。サブエージェントの実際の出力ではなく、書式の見本です。
| 画面 | コントロール | イベント | 呼ぶ処理 | 参照テーブル |
|---|---|---|---|---|
| frmOrder | コントロールcmdRegister | イベントClick | 呼ぶ処理CalcCredit, SaveOrder | 参照テーブル要確認(modCredit.bas内のSQL) |
| ルール文 | 条件 | メッセージ | 根拠 |
|---|---|---|---|
| 数量は1以上で登録する | 条件Val(txtQty.Text) <= 0 | メッセージ数量を入力してください | 根拠frmOrder.frm:48 |
| 与信限度額を超える受注は登録できない | 条件与信額が1,000,000を超える | メッセージ与信限度額を超えています | 根拠frmOrder.frm:52 |
参照テーブルが「要確認」になっているのは、CalcCredit の先が別ファイルにあるためです。呼び先を追わせる指示を入れておくと、modCredit.basまで読んで埋まります。
落とし穴
表が整って見えても、根拠の行がずれている
行番号は、読ませた変換後のコピーのものです。原本と変換後で行数は変わりませんが、原本を別の編集で書き換えると番号が合わなくなります。仕様書に載せる根拠は、確定させた作業コピーの時点のものに固定します。
つまずきやすい点
- コピーでなく原本を渡してしまう: 原本の文字コードを壊すおそれがあります。読ませるのは
spec-src/だけにします - 動的SQLのテーブル名を推測で埋める:
"SELECT * FROM " & tblのような組み立て式は、実行時の値でしか決まりません。「要確認」のまま残し、人が実行ログやDB側で確かめます - 1回の依頼にフォームを詰め込みすぎる: 返ってくる表の量でメインの文脈が埋まります。数個ずつに分けます
- 業務ルールに目的を書き足される: 「顧客満足のため」のような背景は、コードから読めません。指示に「推測と付ける」を入れて、付いていない行は疑います
まとめ
VB6の読解では、サブエージェントに任せる範囲を「読んで表を返す」までに絞り、保存と判断はメインの会話と人が受け持つと、権限も文脈も扱いやすくなります。読み取り専用の担保は tools の許可リストに置き、イベント表は宣言の数との突き合わせで検算し、業務ルール表は根拠の行を人が開いて確かめる。この3点で、仕様書の信頼度をコードから直接たどれる形で保てます。
COBOLのような別の言語で同じ読解をする場合は、Claude CodeでCOBOLを移す手順のように、元の出力を固定してから突き合わせる検証ループが仕上げに入ります。サブエージェントを読み取り専用に絞る設定の一般形は、サブエージェントをhookで読み取り専用のDB分析役にする記事にもあります。仕様書を読み終えたあとの移行の進め方は、Claude Codeでレガシー移行を進める考え方を参照してください。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。