Project Database — 構造化した成果を保存・検索する

schemaの作成から行の保存・検索・WebUIでの確認、SQL制限、migration競合、書き込み結果不明時の復旧までを説明します。

Project Databaseは、顧客記録、調査結果、在庫など、agentと人間が再利用する構造化データの保存先です。行の背景や判断はShared Documentsに残します。通常Projectごとにserver管理のCloudflare D1 databaseを持ち、最初のmigrationで必要になった時点で作成されます。schemaを読むだけでは作成されません。ローカルSQLiteファイルや、HTMLに自動接続されるbackendではありません。

前提と権限

active Projectをcoverageに持つrunning Sessionのagentへ操作を依頼します。SessionのProject roleがViewerならschemaとSELECTを読めます。CollaboratorとAdminはmigration、INSERT、UPDATE、DELETEも実行できます。archived、completed、deletingのProjectは新規Database操作を受け付けません。

chat dbはSession内のコマンドです。Team、Project、Database ID、Sessionを選ぶflagはありません。schemaqueryは現在のディレクトリ、migrateはcanonical migration file pathからProjectを解決します。例はProject rootで実行してください。外側のaachat project databaseはcatalogの取得用であり、任意SQLの実行口ではありません。agentへD1のcredentialを直接渡す必要はありません。

tableを作り、成果を1件保存する

acme/customer-researchをSessionのcoverageにある実在Projectへ置き換え、まず現在のschemaを読みます。

sh
cd aachat/projects/acme/customer-research
chat db schema

read-onlyのdb/schema.sql投影は、空のDBなら-- aachat-schema-version: root、migration後ならsha256:...のversionで始まります。このファイルは編集しません。以下は空のDBであることを確認してから、db/migrations/add_customer.sqlへそのまま保存する例です。既存schemaがある場合は、parent headerへ現在のversion全体を正確にコピーし、既存tableに合わせてSQLを修正してください。rootを再利用しません。

sql
-- aachat-parent: root
CREATE TABLE customer (
  id TEXT PRIMARY KEY,
  name TEXT NOT NULL,
  status TEXT NOT NULL
);
CREATE INDEX customer_status ON customer(status);

parent headerはbyte 0から始めます。BOMやNULを含まないUTF-8の通常ファイルを使い、symlinkは使いません。migration IDは英小文字・数字・_-、先頭は英小文字または数字、最大128文字です。ファイル同期はSQL sourceの保存であり、DBへの適用ではありません。明示的に適用してから行を書き、読んで確認します。

sh
chat db migrate db/migrations/add_customer.sql
chat db schema
chat db query --sql 'INSERT INTO customer (id, name, status) VALUES (?, ?, ?)' --params '["c1", "Ada", "active"]'
chat db query --sql 'SELECT id, name, status FROM customer WHERE status = ? ORDER BY id LIMIT 100' --params '["active"]'
chat db query --sql 'UPDATE customer SET status = ? WHERE id = ?' --params '["reviewed", "c1"]'
chat db query --sql 'SELECT id, name, status FROM customer WHERE id = ?' --params '["c1"]'

migration成功後はschemaのversionが変わり、tableとindexが現れます。最初のSELECTはc1Adaactiveを返し、UPDATE後の最後のSELECTはc1Adareviewedを返します。各段階の実際のJSON応答を読んでから次へ進みます。同じ主キーでINSERTを繰り返しても新しい記録にはなりません。捨ててよい練習用の行なら、chat db query --sql 'DELETE FROM customer WHERE id = ?' --params '["c1"]'で削除し、同じキーのSELECTで不在を確認します。

queryとmigrationのSQL規則は異なる

両方ともSQLは最大100 KiBです。予約された_aachat_sqlite__cf_pragma_のrelation、database名で修飾したobject名、任意のSQLite拡張は使えません。

操作許可する入力主な制限
chat db querySELECT、INSERT、UPDATE、DELETEのいずれか1文。RETURNINGとOUTPUTは不可placeholderは位置指定?のみ。--paramsは最大100個のstringのJSON配列で、placeholder数と一致させる
chat db migrate下記allowlistの1〜100文parameter bindingは不可。現在のparent versionが必要

queryでDDLやPRAGMAは実行できません。SELECT結果は最大1,000行かつdecoded 1 MiBで、超過は部分結果ではなくエラーです。必要なcolumn、WHERE、小さなLIMITを指定します。LIMITを指定するなら静的な非負整数を使い、placeholderや式にしません。queryのUPDATEとDELETEではORDER BYやLIMITを使えません。

migrationのallowlistは、通常のCREATE TABLEとCREATE INDEX、columnの追加・削除・改名またはtable改名のALTER TABLE、単一objectのDROP TABLEまたはDROP INDEX、RETURNINGとOUTPUTを伴わないINSERT・UPDATE・DELETE、そして**PRAGMA defer_foreign_keys = ON**です。このPRAGMAはmigrationだけの例外です。SELECT、任意PRAGMA、view、trigger、明示的なtransaction制御scriptはmigration操作ではありません。allowlistに含まれていてもSQLiteの全方言を許可するわけではありません。

WebUIで結果を見る

ProjectのDatabaseタブを開き、tableを選んでcolumnと行を確認します。閲覧専用で、SQL editorや更新操作はありません。column見出しをクリックするとsortが切り替わり、1ページ25・50・100行(既定100行)で移動できます。table、page、page size、sortはURLに保持されます。

データ変更時はUpdates availableが表示され、refreshで新しい行を読み込みます。schema変更時はcatalogを再取得します。空文字、NULL、BLOBは別の値として表示されます。1 MiB超過なら25行へ減らし、それでも失敗する場合はagentへcolumnや値を絞ったSELECTを依頼します。

書き込みを重複させずに復旧する

応答のerrorreason、次のactionを読みます。timeoutだけでは書き込み失敗と判断できません。

症状次の操作
Projectを解決できない・権限がないProject-rootのcwd、Session coverage、active状態、agentのroleを確認します。ファイルを移しても権限は増えません。
migration sourceが拒否された・見つからないdb/_errors.mdを読み、path、header、encoding、SQLを修正し、同期が受理してから適用します。
parent versionが古いcurrent schemaを読み、そのversion向けにmigrationを作り直します。1つのparentを進める子は1つで、force操作はありません。受理済みsourceは変更しません。
migrationがreconciling応答のread・復旧案内に従います。serverがoperationとprovider ledgerを照合し、解決までschema読取と次のmigrationを待たせます。SELECT/DMLは通常の受付条件で続行できる場合があります。
DML後にOPERATION_OUTCOME_UNKNOWN既知の主キーと現在値を読んで、追加書き込みが必要か判断します。INSERT・UPDATE・DELETEを盲目的に再送しません。
queryがbusy他のlive queryがProject leaseを保持しています。retry案内に従い、並列書き込みで回避しません。
結果が大きすぎるcolumnと行を絞り、区切って読みます。途中までのデータを全件と見なしません。

ローカルのmigrationやschemaファイルを消しても適用済みデータは戻りません。Project削除は受理済みqueryと未解決migration、物理DB削除の完了を待ちます。即時rollbackやbackupの仕組みではありません。信頼境界Projectsも確認してください。

空の状態とセルの全文

WebUIのDatabaseでNo database yetと表示されたら、最初のmigrationでDBを初期化していません。上の手順でAgentにmigrationの作成と適用を依頼します。No tables yetならuser tableがない状態なので、migrationでtableを作成して表示を更新します。schemaを読むだけではDBは初期化されません。

NULL以外のセルを押すと値の全文を開け、必要ならCopyを使えます。空文字はNULLと区別され、詳細を開けますが、NULLのセルには詳細buttonがありません。ここはread-onlyの確認面であり編集画面ではありません。Agentが行やschemaを変更した後は、Refresh/Updates availableで現在の状態を読み直します。