AI開発のファイル丸読みをゼロにするSQLite構造化術|コード・GSC・SKILL全統合の実測録
作成日:

AI開発のファイル丸読みをゼロにするSQLite構造化術|コード・GSC・SKILL全統合の実測録


論旨

AI エージェント(Antigravity / Claude Code / Cursor 等)にプログラム改修や大規模サイトの運用を任せたとき、画面上に Analyzed(ファイル読込)やディレクトリ探索のログが何十回も並び、本来の作業に入る前にトークン枠と待ち時間が溶けてしまった経験はないでしょうか。事前の構造化インデックスがない環境では、AI は目的の関数や設定値を探すだけで「800 行刻みの手探り read_file」を繰り返し、さらにはツール出力の 10KB 切り詰めによる「退避ログの再読込ループ」を引き起こしてしまいます。

結論からお伝えすると、手探りの Analyzed 連発と出力切り詰め地獄を根絶する最適解は、記事原稿だけでなく システムコード全拡張子・環境変数・管理ルール・Search Console 生 JSON・さらにはワークスペース外の SKILL.md と MCP ツールスキーマに至るまで「全本数・全領域」を Pure Rust × SQLite に直結し、あらゆる照会を 1.7〜21 ミリ秒・1 コールで完結させる構造化インデックス基盤 を組むことです。本記事では、当ラボが kb-search Rev. 2.12.0 で到達した全資産 SQLite 直結の内訳と、運用で判明したエッジケースの防御設計を余すところなく公開します。

合わせて読みたい深まる関連情報
対象となる方
  • AI エージェントが作業のたびに Analyzed(read_file)や grep を何十回も連発 し、コンテキスト膨張や応答遅延に悩んでいる方

  • ツールの検索結果が 10KB 上限で .system_generated/steps/*/output.txt へ切り詰められ、AI がそのログファイルをまた read_file する悪循環を止めたい方

  • 記事原稿だけでなく ソースコード(Rust / TS / Swift / Astro)・環境変数・GSC データ・外部スキル定義まで一括で SQLite 構造化 する具体的なテーブル設計と運用ノウハウを知りたい方

結論:手探りファイル丸読みを根絶する全資産SQLite直結

AI エージェントを用いた開発で最大の障壁(ボトルネック)となるのは、AI の推論能力そのものではありません。AI が「どこに何が書いてあるか」を把握するために繰り返す 手探りのファイル丸読み(Analyzed)とディレクトリ探索 です。

これまで当ラボでは、ベクトル DB に頼らず BM25 と SQLite でトークン破産を防ぐ設計 や、前後の定型処理を Pure Rust で一括化するサンドイッチ構造 を構築してきました。しかし、日々の開発と監査のトランスクリプト(実行履歴)を精査すると、記事本文以外の領域でまだ多くの Analyzed が発生している事実が判明しました。

そこで kb-search Rev. 2.12.0 では、ワークスペース内の全コード・環境変数・管理文書から、ワークスペース外にある AI エージェント自身のスキル定義(SKILL.md)や MCP ツールスキーマまで、AI が参照し得るすべての情報を単一の SQLite 知識データベース(knowledge.sqlite)へ完全統合 しました。

事前インデックス不在が招くAnalyzed連発の罠

事前インデックスを持たない一般的な開発環境で AI エージェントに「この機能を修正して」「SEO の未登録記事を調べて」と指示すると、AI は以下のような手探り行動を開始します。

  1. ディレクトリ構造を知るために ls や find を何度も実行する。
  2. 関数名や設定キーを探すためにシェルで grep を走らせ、大量のノイズ行をコンテキストに流し込む。
  3. 数千行あるソースコードや仕様書を、先頭から 800 行刻み(L1-L800, L801-L1600…)で何度も read_file(Analyzed) して目的の箇所を探す。
  4. 新規記事やコンポーネントを作る際、書き方の見本を見るためだけに既存の .mdx や .astro ファイルを何本も覗き見する。

実際に当ラボでも、全領域の構造化を完了する前は、1 記事の執筆・改修セッションあたり 平均 28 回の read_file(Analyzed) が発生していました。その内訳を解析したところ、実に半分以上が「仕様書の該当節を探すための分割読込」や「関数定義の行番号を探すためのコード丸読み」といった、データベースがあれば 1 コールで即決できる重複確認だったのです。

出力10KB切り詰めが引き起こす二次Analyzed地獄

さらに厄介なのが、AI エージェント環境に組み込まれている 「ツール出力の切り詰め(Truncation)機構」 です。

たとえば Antigravity などのエージェント環境では、1 回のコマンド実行(run_command)で返却される標準出力が一定の閾値(約 10KB 前後)を超えると、コンテキスト保護のために出力の途中が省略されます。そして、全文は .system_generated/steps/*/output.txt という一時ログファイルへ自動的に退避されます。

すると AI エージェントは、「省略された真ん中のデータを読まなければ」と判断し、退避された output.txt に対して再び 800 行刻みの read_file(二次 Analyzed)を連発し始めます。

  • 複数の検索コマンドを && で 1 行に連結して実行する ➔ 出力合計が 10KB を超えて output.txt へ退避される ➔ AI が output.txt を read_file する。
  • 巨大な JSON(Search Console の生データなど)や長い SKILL.md を検索する ➔ 10KB を超えて切り詰められる ➔ 再び read_file が走る。

この連鎖が起きると、1 回の質問で済むはずの調査が 5〜10 ターンのファイル読込ループに化け、親エージェントのコンテキストウィンドウを急速に圧迫します。結果として、KV キャッシュの効率悪化や単一ターンのタイムアウト停止(30 分上限やツール呼び出し回数上限)を招く直接原因となります。

従来の手探りファイル探索 vs 全資産SQLite直結ナビ(kb-search Rev. 2.12.0)
Before:事前インデックスなし
手探りAnalyzed連発と10KB切り詰め地獄
  • 800行刻みの分割丸読み :4,000行のRustコードや長大な仕様書を先頭から何度も read_file して目的行を探す。
  • GSC生JSON・レポートの分割読込 :1.4MBのJSONや長文レポートを直接読み、10連発以上の Analyzed を消費する。
  • 10KB超過による二次Analyzed :出力が output.txt へ切り詰められ、退避ログを読むための追加 read_file が連鎖する。
  • 外部SKILL・MCPの毎回読込 :ワークスペース外の SKILL.md やMCP定義を確認するたびにファイル開閉が発生する。
After:kb-search Rev. 2.12.0
全領域SQLite直結・ミリ秒1コール抽出
  • コード6系統・全10領域の行範囲直結 :4,571行のコードも関数名や行範囲(L769-L912)指定でわずか 3.6ms でピンポイント抽出。
  • GSC診断の読取専用1コール化 :最大1.4MBのJSON 5種を約 20ms・9.2KB以内 の意思決定サマリーへ自動凝縮。
  • 8.6KB安全キャップ+続きコマンド案内 :10KB切り詰め閾値の手前で安全に止め、続きの行範囲取得コマンドを自動提示。
  • 仮想パス @agy/ による外部統合 :ワークスペース外の SKILL.md(24本)とMCPスキーマ(26本)も 1.71ms で即座に照会。
記事だけでなくコード・環境変数・GSC・外部SKILL・MCPまでSQLiteへ構造化することで、手探りのAnalyzedと10KB切り詰め再読込を同時に根絶します。
質問するおじさん

なるほどなぁ。AIが賢くなったから何でも自動で探してくれると思っとったけど、目次も索引もない図書館に放り込んで「端から全部めくって探せ」と命じとるようなものだったんじゃね。

解説ナビゲーター

まさにその通りです!しかも1回のメモ帳(出力)が10KBを超えると別室に保管されて、それをまたページめくりで読み直す二度手間が起きていました。最初から全資産の「構造化索引」をSQLiteで作っておけば、AIは最初から目的のページだけを数ミリ秒で開けるようになります。

知識DBと対話履歴DBの全収録内訳とミリ秒応答の実測値

では、手探りの Analyzed をゼロにするために、具体的にどのようなファイルをどの粒度で SQLite に収録しているのでしょうか。

2026年11月14日時点における、当ラボの Pure Rust 製インデックス・検索エンジン kb-search Rev. 2.12.0 の実測収録データをすべて公開します。データベースは役割に応じて 「知識 DB(knowledge.sqlite:597.7MB)」 と 「対話履歴 DB(conversations.sqlite:866.8MB)」 の 2 つに分離・連携させています。

全照会21ミリ秒以下!知識DBの全10収録領域

SQLite 公式のベンチマーク論文「35% Faster Than The Filesystem」 で実証されている通り、OS のファイルシステム上で数百〜数千個の個別ファイルを毎回 open() / read() / close() するよりも、単一の SQLite ファイルからデータを読み出す方がシステムコールとディスク I/O のオーバーヘッドが劇的に小さくなります。さらに Write-Ahead Logging(WAL モード) と FTS5 全文検索拡張(Trigram トークナイザー) を組み合わせることで、597.7MB の全資産に対するあらゆる構造照会・全文検索が 1.7〜21 ミリ秒(0.0017〜0.021 秒) で完了します。

現在の knowledge.sqlite に収録されている全 10 領域の内訳は以下の通りです。

収録領域(カテゴリ) 対象拡張子・データ源 収録ファイル・項目数 容量・構造化要素数(2026/11/14実測) 主な照会コマンドと実測応答速度
公開記事・共通パーツ .mdx 公開 756記事+共通 7 件 解剖 9,222 節(約697万字)/内部リンク 6,923 本/アフィ辞書 492 件 card / tree <slug> --full(3〜13ms)
Astroコンポーネント .astro 49 本(985.2KB) 4層構造・Props定義 574 要素(MDXグローバル登録 10 本) tree components / tree <名>(2〜4ms)
TypeScript / JS / 設定 .ts / .mjs / .js 257 本(1,351.4KB) 型・関数・定数 604 要素(*.min.js / *.bundle.js 自動除外) tree ts / code "<語句>"(2〜5ms)
Pure Rust ツール基盤 .rs 56 本(3,571.9KB) 関数・構造体・impl 1,702 要素(最大5,029行のソースも網羅) tree rust / tree <file> L開始-L終了(3.6ms)
Swift Macアプリ群 .swift 30 本(659.0KB) View・型・関数・MARK 487 要素(6アプリ全ソース) tree swift / tree <file> --full(2〜4ms)
Shell / LaunchAgent .sh / .plist 18 本(92.1KB) Shell 12本(149要素)+plist 6本(59要素)=計 208 要素 tree sh / tree plist(1.8〜3ms)
環境変数・設定台帳 .env / 各種設定 29 種(生秘密値マスク済) コード内参照箇所 計 114 箇所 を自動マッピング env [<語句>](1.9ms)
管理ルール・TODO・下書き .md(文書・draft) ルール 13 文書 / 下書き 897 本 ルール 194 節・TODO 302 項目 / 下書き 28.5MB・18,979 節 manual / todo / tree drafts(2〜8ms)
Search Console 生JSON _local_db/gsc/*.json 生JSON 5 種(最大 1.4MB) 公開全記事の検索順位・CTR・未登録・AI検索クエリを統合 gsc [--unindexed|--opportunities](約20ms)
外部 SKILL / MCP 定義 @agy/ 仮想パス SKILL関連 24 本 / MCP 26 本 14スキル+付属10本(175.0KB)+2サーバー26ツールスキーマ skill / mcp(1.71ms)

公開記事 756記事 の内訳は、AI国家構想が 398本、実機検証録が 358本 であり、これに非公開の共通パーツ 7 本を含めたすべての .mdx ファイルが、フロントマター・見出し階層・生本文(raw_mdx)ごと格納されています。

さらにプログラムコードについても、単なるファイル名一覧ではなく、言語ごとの構文要素(関数・構造体・型・View・Props 等)である 「シンボル単位」 で幾つ抽出されているかに注目してください。

knowledge.sqlite に構造化収録されたコード・文書の要素(シンボル・節)数
下書き・技術資料 (.md 897本)
18,979 節 (28.5MB)
公開記事・解剖節 (.mdx 全編)
9,222 ブロック (約697万字)
Pure Rust 基盤 (.rs 56本)
1,702 要素 (3,571.9KB)
TS / JS / 設定 (.ts等 257本)
604 要素 (1,351.4KB)
Astro コンポーネント (49本)
574 要素 (985.2KB)
Swift Macアプリ群 (30本)
487 要素 (659.0KB)
管理ルール・TODO (13文書)
見出し194節 + TODO 302項目
Shell / LaunchAgent (18本)
208 要素 (92.1KB)
環境変数・外部SKILL・MCP
env参照114 + SKILL24 + MCP26
2026年11月14日時点(kb-search Rev. 2.12.0 実測)。ファイル丸読みをせずとも、これらの構造化要素から行番号を指定して数ミリ秒で該当コードを引き抜けます。

対話履歴DBによる3043スレッドと記事の逆引き結線

もうひとつの柱である対話履歴データベース(conversations.sqlite:866.8MB)には、これまでの開発や壁打ちで蓄積された 総会話 3,043 スレッド が完全収録されています。

  • Antigravity ローカル対話ログ :2,180 件
  • Web 版 Gemini(Google Takeout 抽出)履歴 :863 件
  • 記事 × 会話の逆引き結線インデックス :計 17,807 リンク

この 17,807 本の逆引きリンクにより、ある記事をリライトしたり過去の設計意図を確認したいとき、AI は _gemini_history/ フォルダ内の何千ものテキストファイルを探し回る必要がありません。kb-search card <slug> や kb-search convos "<語句>" --article <slug> を 1 回叩くだけで、「この記事のどの数値が、いつのどのチャット履歴で議論・決定されたか」を数ミリ秒で特定できます。

コードと環境変数を丸読みせず1コール抽出する構造化設計

記事本文の検索だけでなく、普段のプログラミングやツール改修で Analyzed(read_file)をゼロにするために最も威力を発揮しているのが、コード・設定 6 系統(11 拡張子)の構文シンボル構造化(workspace_files × code_symbols テーブル) と 環境変数レジストリ(env) です。

コード6系統と原稿のシンボル抽出・行範囲直結

システム開発において、1 ファイルが数千行に成長することは珍しくありません。たとえば当ラボの Rust 製エンジン内部でも、データベース同期を担う db_sync.rs は 4,571 行、コード構文解析を担う code_outline.rs は 4,428 行、ドキュメント階層ナビを担う doc_nav.rs は 4,136 行 あります。

もし SQLite インデックスがなければ、AI エージェントは 4,500 行超のファイルを把握するために、1 回 800 行上限の read_file を 6 回連続で実行するか、曖昧な grep を何度も繰り返すことになります。

これを防ぐため、kb-search は Rust 標準ライブラリのファイルメタデータ操作(std::fs::Metadata) と SHA-256 ハッシュ比較によって変更ファイルだけを高速検知し、コード・設定 6 系統(11 拡張子:計 410 本・3,575 シンボル) と 原稿・ルール文書 2 系統 の計 8 系統それぞれに専用の構文パーサーを備え、開始行・終了行・シグネチャと生テキストを SQLite へ同期しています。

🛠️ SQLiteへ自動構造化されるコード・設定6系統+文書2系統の抽出粒度
  1. Pure Rust(.rs:56本・1,702要素) : fn(関数)、struct(構造体)、enum(列挙型)、impl(実装ブロック)、mod(モジュール)の定義名と正確な行範囲(L開始-L終了)を抽出します。

  2. TypeScript / JavaScript(.ts/.tsx/.js/.mjs/.cjs:257本・604要素) : export function、interface、type、const 定数群を抽出します。この際、検索ノイズやトークン肥大化の元凶となる *.min.js や *.bundle.js などの圧縮ファイルはインデックス段階で自動的に完全除外 します。

  3. Astro コンポーネント・ページ(.astro:49本・574要素) : フロントマター(サーバー処理・Props 型定義)、テンプレート HTML、<script>、<style>(CSS @media ブロック)の 4 層構造および、MDX にグローバル自動注入されている 10 本のコンポーネント設定を構造化します。

  4. Swift Mac アプリ群(.swift:30本・487要素) : BlogLedger.app を含む 6 つの自作 macOS アプリから、SwiftUI の View、struct、class、func、および // MARK: - セクション境界を抽出します。

  5. Shell スクリプト(.sh/.command:12本・149要素) : RAMDisk 構築やデプロイ自動処理を担うシェルスクリプトから、ヒアドキュメント境界を考慮したうえで関数定義・export 変数・エイリアスを行範囲付きで抽出します。

  6. macOS LaunchAgent 設定定義(.plist:6本・59要素) : プログラミング言語ではなく XML 形式の設定ファイルである Property List 専用パーサーにより、launchd 自動実行ジョブのキー定義(Label, ProgramArguments, StartInterval 等)と設定値を構造化します。

  7. 公開記事の生 MDX(公開 756記事+共通パーツ 7 本) : 文書系パーサーとして、フロントマター(fm)、import ブロック(imports)、および見出しごとの生 MDX 本文を articles.raw_mdx カラムから行番号指定で直接引き抜けます。

  8. 管理ルール・仕様書・下書き・SKILL(.md:ルール 13 文書・下書き 897 本・SKILL 関連 24 本) : 3 層分離された設計書や外部スキル定義のすべての章節を doc_sections テーブルへ収録し、kb-search manual "3.1" --full や kb-search skill <名> の 1 コール(1.7〜2.4ms)で該当節のみを取得できます。

この仕組みにより、AI が 4,571 行の db_sync.rs の中にある特定の同期処理を確認・修正したい場合は、以下のように動作します。

  1. kb-search tree db_sync.rs で関数一覧と行番号を確認する(または最初から関数名を指定する)。
  2. kb-search tree db_sync.rs L769-L912 --full(またはカンマ区切りで複数箇所 L1-L55,L769-L912)を実行する。
  3. わずか 3.6ms で、物理行番号付きの該当コード(144 行分)だけがコンテキストに返却される。

手探りの read_file は 0 回 です。事前にコード・設定 6 系統と文書 2 系統の構文シンボルおよび物理行番号を SQLite に構造化しておくことで、4,500 行超の巨大ファイルであっても「必要な関数範囲だけを 3.6 ミリ秒で引き抜いて即座に edit_file する」という最短動線が成立します。

生の秘密値を保存しない環境変数レジストリと参照追跡

コードと並んで AI が頻繁に手探り検索してしまうのが、「どの環境変数が、どのスクリプトや Rust コードの何行目で使われているか」という設定調査です。

しかし、.env ファイルをそのままデータベースに格納したり、AI に無造作に read_file させるのはセキュリティ上のリスクが伴います。そこで kb-search の環境変数レジストリ(env テーブル)では、「秘密値の完全マスク保護」と「コード内参照箇所の自動マッピング」 を両立させました。

  • 生秘密値の非保存(マスク徹底) :.env 等に記述された API キーやトークンの「生の値」は一切 SQLite に保存せず、キー名・設定ファイルの場所・値の有無(マスク表示)のみを記録します。
  • 29 種の環境変数 × 114 箇所のコード参照追跡 :Rust の std::env::var("...")、TypeScript / Astro の import.meta.env.... や process.env....、シェルスクリプトの $VAR 展開を静的解析し、29 種の環境変数がどのファイルの何行目で参照されているか(計 114 箇所) をすべて紐付けています。

これにより、AI は kb-search env を 1 回呼ぶだけで(約 1.9ms)、機密情報を一切露出させることなく、環境変数の影響範囲を漏れなく把握できます。こうした堅牢なテキスト解析とゼロコピーの高速 CLI を自作するうえで、Rust の所有権と型システムは最高の武器になります。

オライリー・ジャパン『プログラミングRust 第2版』

オライリー・ジャパン『プログラミングRust 第2版』

最後の死角だったGSC生JSONと外部SKILLの統合

記事原稿とワークスペース内のコードをすべて SQLite 化した後、最後に残っていた「Analyzed 連発の死角」が 2 つありました。それが 「Search Console(GSC)の大型生 JSON・診断レポート」 と 「ワークスペース外にある AI エージェント自身の SKILL.md・MCP ツール定義」 です。

kb-search Rev. 2.12.0 では、この最後の 2 大死角も SQLite へ完全統合しました。

最大1.4MBのGSC生JSONを20ミリ秒で凝縮

当ラボでは、Search Console API を用いた無料自動監査システム により、全記事のインデックス登録状態、検索クエリ、表示回数、クリック率(CTR)、さらには生成 AI 検索(AI Mode / AI Overviews)経由の長文クエリをローカルの _local_db/gsc/ に自動収集しています。

しかし、この生データ(JSON 5 種類)は最大で 1.4MB に達し、自動生成される Markdown レポートも数千行の規模になります。そのため、以前は「今日の Search Console で改善すべき記事はある?」と AI に尋ねると、AI が _local_db/gsc/*.md や *.json を先頭から分割で read_file し、たった 1 回の確認で 10 連発以上の Analyzed を発生させていました。

これを根絶するため、新設した kb-search gsc サブコマンドでは、生 JSON と SQLite の記事台帳をメモリ上で高速結合し、以下の 5 つの切り口を 読み取り専用・副作用ゼロの 1 コール(約 20ms・出力最大 9.2KB 以内) で即座に取り出せるようにしました。

  • kb-search gsc(全体サマリー:インデックス登録率・急上昇クエリ・優先対応枠の一覧)
  • kb-search gsc --unindexed(未登録記事のステータス別一覧と経過日数)
  • kb-search gsc --opportunities(表示回数が多いのに CTR が低い「タイトル・スニペット改善候補」の抽出)
  • kb-search gsc --top(クリック数・表示回数の上位牽引記事)
  • kb-search gsc --genai(AI 会話検索・長文相談クエリの検出)
  • kb-search gsc --slug <slug>(特定記事 1 本の検索クエリ内訳とインデックス履歴)

さらにここで、運用上の極めて重要な知見から 「14 日クールダウン判定の基準日ロジック」 を刷新しました。

💡 OSの物理更新日時(mtime)ではなくSQLite論理更新日を使う理由
  • OS の物理 mtime が引き起こす「クールダウン汚染」の罠 : SEO リライトを行った記事は、Google のクローラーが再評価するまで最低 14 日間は様子を見る(クールダウン期間を置く)のが鉄則です。しかし、判定基準にファイルの物理更新日時(OS の mtime)を使うと、全記事に対して「表記揺れの一括置換」や「フロントマターの軽微な整形」を走らせた瞬間、全 700 記事以上の mtime が今日の日付に書き換わり、「全記事が今日リライトされた(=すべてクールダウン中)」と誤判定されて改善候補がゼロになる事故 が起きます。

  • SQLite 論理更新日 COALESCE(updatedDate, pubDate) による解決 : そこで kb-search gsc では、OS のファイルシステム上の mtime を一切参照せず、SQLite の articles テーブルに格納されたフロントマターの論理日付 COALESCE(updatedDate, pubDate) を基準に 14 日クールダウンを計算します。これにより、機械的な一括校正を行っても SEO 上の実質的な最終リライト日が 1 ミリも汚染されず、真にテコ入れすべき記事だけを正確に抽出できます。

ワークスペース外のSKILLとMCPを仮想パスで同期

もうひとつの死角が、AI エージェントの機能を拡張する スキル定義ファイル(SKILL.md) と Model Context Protocol(MCP)公式仕様 に基づくツールスキーマ(JSON) です。

Antigravity などのエージェント環境では、これらのファイルはプロジェクトのフォルダ(ワークスペース)の中ではなく、ユーザーのホームディレクトリ配下(~/.gemini/antigravity/builtin/skills/ や ~/.gemini/antigravity/skills/、~/.gemini/antigravity/mcp/ など)に配置されています。そのため、AI がスキルや MCP ツールの使い方・引数スキーマを確認しようとするたび、毎回必ず外部パスへの read_file(Analyzed)が発生していました。

そこで kb-search Rev. 2.12.0 では、同期の対象領域をワークスペース外へも拡張し、仮想パス @agy/ プレフィックス を付与して knowledge.sqlite へ一括インデックス化しました。

  • 外部・内蔵スキル定義(SKILL.md 関連) :計 24 本(14 スキル本体+付属リファレンス・スクリプト 10 本、合計 175.0KB)を見出しセクション単位まで分解して収録。
  • MCP ツールスキーマ定義 :計 26 本(2 サーバー分の全ツール名・説明文・必須パラメータ・JSON Schema)を構造化収録。
  • 実測照会スピード :kb-search skill [<スキル名> [<節|L1-L99>]] [--full] および kb-search mcp [<server> [<tool>]] により、わずか 1.71ms で必要なセクションや引数定義だけをピンポイント抽出。
knowledge.sqlite(597.7MB)が統合する4層のデータ領域
Layer 1:Content & History
公開記事・下書き・対話履歴(.mdx / .md / Takeout)

公開 756記事(+共通パーツ7本・計9,222節)、下書き897本(18,979節)、管理ルール13文書、および対話履歴3,043スレッド(逆引き17,807リンク)を全文検索・行番号直結で保持。

Layer 2:System Code & Env
システムコード・設定6系統&環境変数レジストリ(.rs / .ts・.js / .astro / .swift / .sh / .plist + env)

計410本のコード・設定ファイル(6系統・11拡張子)から3,575個の構文シンボル(関数・型・View・Props・plistキー)を抽出し、.env の生秘密値をマスクしたうえで29種の環境変数と114箇所の参照行をマッピング。

Layer 3:SEO & Telemetry
Search Console 生JSON(最大1.4MB×5種)× 論理日付クールダウン統合

GSC APIから取得した大型JSONを直接 read_file させず、COALESCE(updatedDate, pubDate) 基準の14日クールダウン判定と結合して約20msで要約出力。

Layer 4:External Agent Specs (@agy/)
ワークスペース外の SKILL.md(24本)& MCP ツールスキーマ(26本)

~/.gemini/antigravity/ 配下の内蔵・カスタムスキルとMCP定義を仮想パス @agy/ で差分同期し、1.71msでセクション・引数単位の照会を実現。

ワークスペース内の原稿・コードだけでなく、ローカル統計JSONやワークスペース外のシステム拡張定義(@agy/)まで単一のSQLiteで一元管理します。

運用で判明した2大エッジケースと再発防止ガードの実装

このように「すべてのファイルを SQLite に入れて CLI から引けるようにする」だけでも大きな効果がありますが、実際の AI エージェント環境(特にセキュリティサンドボックスと出力制限がある環境)で毎日運用してみると、単純な実装では防げない 2 つの重大なエッジケース(境界条件の罠) に直面しました。

読者の方がご自身の開発環境に同様の SQLite インデックスを導入する際、必ず役立つ防御設計として、当ラボが実装した 2 つの対策を詳しく共有します。

出力切り詰めを防ぐ8.6KBキャップと続き行の自動案内

1 つ目のエッジケースは、前半でも触れた 「エージェントのコマンド出力 10KB 切り詰め閾値との衝突」 です。

いくら SQLite から 2 ミリ秒でデータを引き出せても、--full オプションで長大な仕様書の章節や大きな SKILL.md を一括出力した際、出力テキストが 10KB を超えてしまえば、エージェント環境側で .system_generated/steps/*/output.txt への強制退避が発動します。すると AI は退避されたテキストファイルを読むために結局 read_file(二次 Analyzed)を実行してしまい、せっかくの SQLite 直結が台無しになります。

この問題を 100% 防ぐため、kb-search の出力フォーマッタには 「8.6KB 安全キャップ(GSC 統合サマリーでは 9.2KB 上限)」 と 「続き行範囲コマンドの自動案内」 を実装しました。

🛡️ 二次Analyzedを物理遮断する『8.6KB安全キャップ』の動作仕様
  1. 行単位のバイト数積算と安全停止 : kb-search がコードやドキュメントの行を出力する際、1 行ごとに UTF-8 バイト数を積算します。エージェント側の 10KB 切り詰め閾値に到達する手前の 8.6KB(8,800 バイト前後) に達した時点で、行の途中で文字化けや構文崩壊を起こさないよう、直前の改行境界で出力をピタリと止めます。

  2. 続きを取得するための「完全コピペ用コマンド」を自動提示 : 出力を止めた末尾に、単なる「省略されました(truncated)」というメッセージではなく、💡 続きを取得するには: ./scripts/run_kb_search.sh skill <name> L121-L240 --full のように、次に叩くべき正確な開始行・終了行入りのコマンドを自動生成して添えます。

  3. 二次 read_file の完全消滅 : これにより、AI エージェント側で .system_generated/steps/*/output.txt のファイル退避が一切発生しなくなり、万が一長文の後半が必要な場合でも、提示された行範囲コマンドをもう 1 回(約 2ms)呼ぶだけで安全に読み進められます。

サンドボックス権限エラー時のピンポン削除防止ガード

2 つ目のエッジケースは、「隔離サンドボックス実行時における外部ファイル(@agy/*)のピンポン削除問題」 です。

Antigravity をはじめとする最新の AI エージェントは、安全性のためにデフォルトで 標準サンドボックスモード(BypassSandbox: false) でコマンドを実行します。このサンドボックス内では、プロジェクトのワークスペース(/Users/$USER/Desktop/ai-blog-project 等)や RAMDisk(/Volumes/RAMDisk/$USER)への読み書きは許可されていますが、ワークスペース外にあるホームディレクトリ配下(~/.gemini/antigravity/ 等)へのアクセスは OS レベルで遮断され、PermissionDenied(権限エラー)が返ります。

ここで、一般的なデータベース同期(sync)のアルゴリズムを考えてみてください。通常、インデックス同期処理では「現在ディスク上に存在するファイル一覧」と「SQLite 内に記録されているファイル一覧」を照合し、ディスク上から消えたファイルを SQLite からも DELETE する(孤立レコードの自動パージ) という処理を行います。

もしこの削除ロジックをそのまま動かしてしまうと、以下のような 「ピンポン削除現象」 が発生します。

  1. サンドボックス外(人間のターミナルやデプロイ処理)で kb-search が動く ➔ ~/.gemini/antigravity/ が読めるため、@agy/* の 50 レコード(SKILL 24 本+MCP 26 本)が SQLite に登録される。
  2. 次に AI エージェントがサンドボックス内(BypassSandbox: false)から検索を実行し、自動差分同期が走る ➔ ~/.gemini/antigravity/ の走査が PermissionDenied で 0 件になる ➔ 同期エンジンが「外部ファイルがすべて削除された!」と誤認し、SQLite から @agy/* レコードを全削除してしまう。
  3. 結果として、AI がサンドボックス内から kb-search skill や kb-search mcp を叩いた瞬間、せっかく登録したレコードが消えて検索ヒットが 0 件になる。
質問するおばさん

あらまぁ!お掃除機能が真面目に働きすぎるせいで、鍵がかかって外が見えないだけの時に「外の荷物が全部なくなった!」と勘違いして台帳から消しちゃうわけね!

解説ナビゲーター

そうなんです!普通にテストしているだけでは気づきにくい、サンドボックス環境ならではの落とし穴でした。そこで「本当にファイルが消えたのか、それともサンドボックス制限で見えないだけなのか」を厳密に区別する保護ガードを組み込みました。

具体的には、db_sync.rs の外部リソース同期フェーズにおいて、以下の 「ピンポン削除防止ガード」 を実装しています。

  • 外部ディレクトリ(~/.gemini/antigravity/builtin/skills 等)を走査する際、ディレクトリ自体のメタデータ取得や read_dir が PermissionDenied 等の I/O エラーを返した場合は、「サンドボックスによるアクセス制限中(Unreachable)」 というフラグを立てる。
  • 孤立レコードの削除(パージ)処理を行う際、外部ディレクトリが Unreachable 状態であれば、仮想パス @agy/ で始まるすべてのレコード(workspace_files, code_symbols, doc_sections)を削除対象から完全除外して既存のキャッシュを 100% 温存 する。
  • さらに kb-search skill や kb-search mcp などの読み取りコマンド側でも、すでに SQLite 内に @agy/* レコードが存在する場合は無駄な再同期を走らせず、即座に既存テーブルから 1.71ms で結果を返す。

この 2 つのエッジケース対策によって、サンドボックスの内外を問わず、いつでも安定してミリ秒応答・出力切り詰めゼロで全資産を引き出せる盤石な基盤が完成しました。

まとめ:自分の開発環境に全資産SQLite索引を導入する手順

最後に、本記事で解説した「手探り Analyzed ゼロ・全資産 SQLite 直結アーキテクチャ」をご自身のプロジェクトや AI 開発環境へ導入する際のステップを整理します。

最初からすべての言語パーサーを作る必要はありません。以下の 4 ステップで段階的に対象領域を広げていくのが最も確実です。

手探りAnalyzedをゼロにする全資産SQLiteインデックス構築の4ステップ
Step 1
仕様書と原稿の節分割

Markdown原稿やルール文書を見出し(##/###)単位で行番号とともにSQLiteへ格納し、章節の1コール抽出を作る。

Step 2
コードのシンボル構造化

主要言語の関数・型・View定義の開始/終了行を抽出し、*.min.js 等を除外したうえで行範囲ダイレクト取得を実装する。

Step 3
大型JSON・外部定義の統合

GSC等の大型JSONを論理日付基準で要約し、外部の SKILL.md やMCP定義も仮想パス(@agy/)で同一DBへ取り込む。

Step 4
8.6KB上限と権限ガード

出力切り詰めを防ぐ8.6KBキャップ+続きコマンド案内と、サンドボックス時のピンポン削除防止ガードを入れて完成。

まずは頻度が高い仕様書と原稿から始め、コードシンボル、外部JSON・SKILLへと段階的に対象を広げるボトムアップ手順がおすすめです。

推論ですが、1 回の機能改修や記事執筆で発生していた 20〜30 回の手探り read_file(800 行×25 回=約 20,000 行分のコンテキスト流入)と、10KB 切り詰めによる二次 Analyzed をこの SQLite 直結ナビへ置き換えることで、1 タスクあたりの入力トークン消費量は約 70〜85% 削減され、AI が最初のコード編集に着手するまでの初動時間も数分から十数秒へと劇的に短縮 されます。

✅ 全資産SQLiteインデックス化で劇的に改善する開発環境
  • 手探りの Analyzed(read_file)と grep 連発が消える : 597.7MB の知識 DB と 866.8MB の対話履歴 DB から、記事・コード6系統・環境変数・GSC・外部 SKILL・MCP の全 10 領域を 1.7〜21 ミリ秒 でピンポイント抽出できます。

  • 10KB 出力切り詰めによる「退避ログ再読込」が起きない : 8.6KB 安全キャップと続き行範囲コマンドの自動案内により、.system_generated/steps/*/output.txt への切り詰め退避と二次 Analyzed を物理的に防げます。

  • サンドボックス環境でも外部スキル・MCP を高速参照できる : 仮想パス @agy/ とピンポン削除防止ガードにより、PermissionDenied が発生する隔離環境からでも SKILL.md(24 本)と MCP スキーマ(26 本)を 1.71ms で照会できます。

「AI エージェントにファイルを端から丸読みして探させる」のではなく、「Pure Rust と SQLite で構造化した高速な地図を渡して、AI には本来の思考と実装だけに集中してもらう」。規模が大きくなればなるほどこの差は何十倍もの生産性の違いとなって表れますので、ぜひご自身の開発環境にも SQLite 直結インデックスを取り入れてみてください。

オライリー・ジャパン『プログラミングRust 第2版』

オライリー・ジャパン『プログラミングRust 第2版』

手探りのファイル探索から解放されて安心して眠る猫