Claude Media
Claude Codeでテーブル定義書をtblsで作り、説明が空のカラムを補う

Claude Codeでテーブル定義書をtblsで作り、説明が空のカラムを補う

tbls docで定義書を生成し、tbls lintでコメントが空のカラムを洗い出します。説明案はClaude Codeに作らせ、COMMENT ONか.tbls.ymlのどちらかに戻して再生成します。

テーブル定義書は、tblsでデータベースから生成するのが手早い方法です。ただし、生成できるのは構造までです。カラムのコメントがデータベースに無ければ、説明の欄は空のまま出力されます。

その空欄を埋める作業はClaude Codeに向いています。tblsが「どのカラムが空か」を数え、Claude Codeが「コードでどう使われているか」を調べて説明案を作ります。この記事では、空のカラムの洗い出しから、説明の戻し先の選び方、再生成での確認までを通します。

tbls docで定義書を作り、空欄の量を測る

tblsは、データベースを解析してMarkdown形式のドキュメントを生成するCLIです。PostgreSQLのほか、MySQL、SQLite、BigQueryなどに対応しています。最短の使い方は、接続先を渡して tbls doc を実行するだけです。

brew install tbls
tbls doc postgres://dbuser:dbpass@localhost:5432/dbname

リポジトリで継続して使うなら、.tbls.yml に接続先と出力先を書きます。出力先の既定は dbdoc です。

# .tbls.yml
dsn: postgres://${DB_USER}:${DB_PASSWORD}@localhost:5432/dbname
docPath: doc/schema

dsn に環境変数を展開する書き方は、設定値すべてで使えます。パスワードを直書きしないために、この形にしておきます。理由は後の節で触れます。

定義書ができたら、説明の整備状況を測ります。tbls coverage はテーブルごとに、説明とコメントがどれだけ埋まっているかを割合で出します。

tbls coverage

出力は、全テーブルの割合の下に、public.users 20% のようにテーブル別の行が並ぶ形です。0%のテーブルから着手すれば、効果が一番見えやすくなります。

tbls lintで説明が空のカラムを一覧にする

どのカラムが空なのかを、Claude Codeに渡せる形で取り出します。使うのは tbls lint の requireColumnComment です。

# .tbls.yml(追記)
lint:
  requireTableComment:
    enabled: true
  requireColumnComment:
    enabled: true
    exclude:
      - id
      - created_at
      - updated_at

requireTableComment はテーブルの説明が空のものを、requireColumnComment はカラムの説明が空のものを検出します。tbls coverage が測る対象もテーブルとカラムの両方なので、lintの設定も両方に揃えておきます。requireColumnComment の exclude に挙げたカラムは警告の対象から外れます。主キーや作成日時のように、説明が自明なものを除いておくと、一覧に残るのは人が判断すべきカラムだけになります。

tbls lint

コメントの無いカラムは、users.username: column comment required. のように「テーブル名.カラム名」の形で1行ずつ出ます。テーブルのカラム数に上限を設ける columnCount も同じ出力に混ざるので、カラムだけを拾うなら文言で絞ります。

tbls lint | grep 'column comment required' \
  | sed 's/: column comment required\.//' > doc/missing_columns.txt

doc/missing_columns.txt が、Claude Codeへの入力になります。1行が1カラムなので、件数は wc -l で分かります。

テーブルの説明が空のものも、同じ tbls lint の出力に混ざります。テーブル単位の指摘は文言がカラムと違うため、まず tbls lint の素の出力でどう表示されるかを見てから、同じ要領で別ファイル(例: doc/missing_tables.txt)に抜き出します。カラムの説明案は、テーブルの役割が分かってから作るほうが根拠を探しやすいので、テーブルの説明を先に埋める順番が合います。コメントが空のカラムが数百件あるときは、テーブル単位に分けて渡したほうが、出力が混ざりません。

allOrNothingで着手の単位を決める

lintの設定には allOrNothing というオプションもあります。READMEの設定例では、requireTableComment に false、requireColumnComment に true が入っていて、コメントは「全部付いている」か「全部付いていない」かのどちらかに揃える、という意味のコメントが添えられています。

# .tbls.yml
lint:
  requireColumnComment:
    enabled: true
    allOrNothing: true

true にすると、一部のカラムにだけ説明がある状態が違反になります。テーブル単位で「書き始めたら全カラムを埋める」と決めたいときに合います。数百カラムを一度に埋める必要はなく、tbls coverage で選んだ1テーブルずつ、このオプションで取りこぼしを防ぎながら進められます。

Claude Codeに説明案を作らせる

先に、tbls lint と tbls coverage を毎回の承認なしで実行できるようにします。どちらもデータベースを読むだけで、書き換えません。権限ルールは、サブコマンドの後ろに * を置く形で書きます。

{
  "permissions": {
    "allow": [
      "Bash(tbls lint *)",
      "Bash(tbls coverage *)",
      "Bash(tbls diff *)"
    ],
    "deny": [
      "Read(./.env)"
    ]
  }
}

末尾に空白付きの * を置いたルールは、引数なしの tbls lint にも一致します。tbls doc は接続してファイルを書き出すため、許可には入れず、承認を挟む設定です。Read(./.env) の拒否は、接続情報を含む環境変数ファイルを読ませないためです。

依頼は、入力ファイルと根拠の求め方を指定して出します。

doc/missing_columns.txt の users テーブルについて、
テーブル自体の説明案(1文)と、カラムの説明案を作ってください。
- src/ 以下でそのカラムが使われている箇所を検索し、
  列挙定数・バリデーション・外部キーから意味が分かるものを
  「確証」、名前と型からの推測を「推測」に分ける
- 手がかりがないカラムは説明を書かず、質問として返す
- 出力は doc/drafts/users_columns.md に、
  カラムごとに根拠のファイルと行を添えて書く
- データベースには接続しない

確証と推測を分けさせる理由は、定義書に載った説明は、すべて事実として読まれるからです。「税込か税抜か」のように、コードを読まないと分からない前提を推測のまま載せると、後から気づけません。区分の考え方とSkillへの固定のしかたは、Claude Codeでカラム定義書を作る手順に詳しく書いています。

出力の形は、例えば次のようになります(区分の考え方に沿った例示です。内容は対象のコードで変わります)。

| カラム | 区分 | 説明案 | 根拠 |
|---|---|---|---|
| users(テーブル) | 確証 | 会員アカウント。1行が1会員 | src/domain/user.ts のクラス定義 |
| users.status | 確証 | 0=仮登録、1=有効、2=退会 | src/domain/user.ts の UserStatus |
| users.phone_number | 推測 | [要確認] 連絡先電話番号 | 名前と型のみ |
| users.legacy_flag | 不明 | (質問)どの値が入るか | 参照するコードなし |

Claude Codeの共通ワークフロー集には、ドキュメント整備を「未記載の箇所を探す、生成する、見直す、基準に合うか検証する」の4段で進める例があります。カラム説明も同じ流れで、洗い出しにあたるのがtbls lintです。毎回この依頼文を書く代わりにSkillへ固定する方法は、Claude Code Skillsの書き方にまとめています。

説明の戻し先は2か所ある

人が確証のある分を選んだら、説明をどこに書き戻すかを決めます。tblsの定義書は、データベース上のコメントを読んで作られます。そのため戻し先は、データベースか、.tbls.yml の2つです。

戻し先書き方向く場面
データベースのコメント書き方COMMENT ON TABLE / COMMENT ON COLUMN をマイグレーションで適用向く場面定義書以外(psqlなど)でも説明を見せたいとき
.tbls.yml の comments:書き方tableComment にテーブルの説明、columnComments にカラムごとの説明を書く向く場面ALTER TABLEをせずに定義書だけ補いたいとき、ビューやSQLiteのカラム

データベース側に入れる場合は、確証の分だけを COMMENT ON TABLE と COMMENT ON COLUMN にして、所有者のロールで流し込みます。文面の書式と適用手順は、先に挙げたカラム定義書の記事が詳細です。

.tbls.yml 側に入れる場合は、次の形です。

# .tbls.yml
comments:
  - table: users
    tableComment: "会員アカウント。1行が1会員"
    columnComments:
      status: "0=仮登録、1=有効、2=退会"
      phone_number: "連絡先電話番号"

ここで注意が要るのは、.tbls.yml のコメントがデータベース上の既存コメントを上書きする点です。tblsのドキュメントにも、その旨の注記があります。データベース側に人が書いた説明があるテーブルやカラムを、Claude Codeの下書きでうっかり tableComment や columnComments に入れると、エラーも警告も出さずに定義書の表示だけが置き換わります。lintが拾うのは空の説明だけですが、comments: は空でない説明にも効きます。書き戻す前に、既存のコメントと重なる行がないかを見ておきます。

comments: には、テーブルとカラム以外の戻し先もあります。インデックス用の indexComments、制約用の constraintComments、トリガー用の triggerComments、テーブルに付ける labels です。READMEの例では、posts_user_id_idx のインデックスに user.id index と書いています。requireColumnComment が検出するのはカラムだけなので、これらはlintの一覧には出ません。説明が欲しい制約やトリガーがあれば、依頼文に加えて別枠で下書きさせます。

落とし穴

定義書の説明とデータベースのコメントが食い違う

.tbls.yml の comments: に書いた説明は、定義書の出力でデータベースのコメントより優先されます。psqlで見える説明と定義書の説明が別物になり、どちらが正か分からなくなります。戻し先はカラムごとに1か所に決め、ビューやSQLiteのように COMMENT ON が使えないものだけを .tbls.yml に置くと、食い違いを避けられます。

再生成して、空欄が減ったことを確かめる

説明を戻したら、定義書を作り直します。既存のドキュメントを上書きするには --force、出力先を空にしてから作るには --rm-dist を付けます。--force は、削除したテーブルのファイルを消しません。テーブルを落とした後は --rm-dist のほうが確実です。

tbls doc --rm-dist
tbls coverage
tbls lint | grep -c 'column comment required'

tbls coverage の割合が上がり、lintの件数が減っていれば、補完は反映されています。残ったカラムが、「不明」として返された質問の分です。担当者の回答が入ったところで、同じ手順をもう一周します。

CIで空欄の再発を止める

新しいカラムが説明なしで増えないよう、CIで tbls lint を回しておく方法もあります。tblsのドキュメントは、定義書をコミットし、スキーマを変えたら tbls diff と tbls lint をCIで確認する流れを示しています。

# .github/workflows/doc.yml
name: Document
on:
  pull_request:
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: k1low/setup-tbls@v1
      - run: tbls diff
      - run: tbls lint

tbls diff は、データベースの現状とコミット済みの定義書のずれを検出します。定義書にER図を含める場合の描き分けは、Claude CodeでER図をMermaidで起こす記事が扱っています。

接続情報をClaude Codeに読ませない

tblsの接続先は dsn に書くので、パスワードを直書きした .tbls.yml をClaude Codeが読める状態にしておくと、秘密がそのまま会話に載ります。

  • dsn は環境変数の展開で書き、実値はシェルの環境かCIのシークレットに置く
  • 接続情報を置く .env は、上で示した Read(./.env) の拒否ルールで読ませない
  • Claude Codeには doc/ 以下の生成物と missing_columns.txt だけを渡し、tbls doc は人が実行する

DSNにパスワードの記号が含まれるときは、URLエンコードが必要です。# や < を含むパスワードは、そのままでは接続できません。

まとめ

tblsは、定義書の生成と、説明が空のカラムの検出までを自動で行います。説明の中身を考える部分だけが人の仕事で、そこをClaude Codeが下書きします。

分担の要点は、空欄の特定をtbls lintに任せ、説明案の根拠をコードから探させ、書き戻す場所をカラムごとに1つに決めることです。まずは tbls coverage で0%のテーブルを1つ選び、確証の分だけを戻して再生成すると、効果と手間を測れます。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. github.com/k1LoW/tbls
  2. code.claude.com/docs/en/permissions
  3. code.claude.com/docs/en/common-workflows
この記事を共有:XはてブLinkedIn