maestro/docs/maintenance-checklist.md
2026-06-03 05:08:00 +00:00

31 KiB
Raw Permalink Blame History

メンテナンスチェックリスト

コード変更時に連動して修正が必要な箇所のリスト。 過去に実際に発生した不整合をもとに作成。


1. ツールモジュールを新規追加した場合

対象ファイル:

  • src/engine/tools/<module>.ts — 新モジュール本体
  • src/engine/tools/index.tstryLoadModule で動的ロード追加
  • src/bridge/tools-api.ts/api/tools のモジュール一覧に追加
  • CLAUDE.md — 「ツールモジュール構成」テーブルに行を追加

なぜ必要か: index.ts はエージェント実行時のツール dispatch に使われ、tools-api.ts は Settings UI のピース編集画面でツール候補を返す API。 tools-api.ts への追加を忘れると、エンジンでは使えるのに UI のドロップダウンに表示されないという不整合が起きる(実際に amazon, speech, checklist, knowledge の4モジュールで発生した

確認方法:

# index.ts でロードしているモジュール数と tools-api.ts のモジュール数を比較
grep -c 'tryLoadModule' src/engine/tools/index.ts
grep -c "engine/tools/" src/bridge/tools-api.ts
# 数が一致していなければ漏れがある

2. 既存モジュールにツールを追加した場合

対象ファイル:

  • pieces/*.yaml — 必要な piece の allowed_tools にツール名を追加
  • CLAUDE.md — 「ツールモジュール構成」テーブルの該当モジュール行に新ツール名を追加
  • docs/tools/{name}.md — 新ツールの詳細ドキュメント(推奨)
  • ツール description — 1 文 + 「詳細は ReadToolDoc({ name: "XXX" })」を末尾に記述

なぜ必要か: allowed_tools に載っていないツールは LLM に提示されない。ツールを実装しても piece に追加しなければエージェントが使えない。 CLAUDE.md のテーブルが古いと、Claude Code 自身が既存ツールを認識せずに新規実装してしまうリスクがある。 ツール description は毎 LLM 呼び出しに乗るため 1 文に絞り、詳細は ReadToolDoc 経由で必要時のみ読み込むagent-loop が movement 開始時に description サマリを自動カタログ化する)。

確認方法: 新ツールが使われるべき piece を特定し、allowed_tools に含まれているか確認する。 CLAUDE.md のモジュールテーブルに新ツール名が含まれているか確認する。


3. ツールをリネーム・削除した場合

対象ファイル:

  • pieces/*.yaml — 全 piece の allowed_tools から旧名を削除/リネーム
  • src/engine/tools/raw-save.tsRAW_SAVE_TOOLS に旧名が残っていないか
  • ui/src/components/settings/ToolsForm.tsx — ヘルプテキスト等にツール名の言及がないか
  • CLAUDE.md — ツールモジュール構成テーブル

なぜ必要か: BrowserAction を BrowseWeb に統合した際、5つの piece と UI ヘルプテキストに旧名の参照が残っていた。

確認方法:

grep -r '旧ツール名' pieces/ src/ ui/src/ CLAUDE.md

4. config.yaml に新しい設定キーを追加した場合

対象ファイル:

  • src/config.tsToolsConfig / AppConfig / LlmConfig / StorageConfig 等のインターフェースにフィールド追加
  • src/config-normalize.ts — v1 → v2 normalizer に新フィールドの mirror が要るか確認 (storage / llm 配下に置く場合)
  • config.yaml.example — YAML キー(スネークケース)でサンプル・コメント追加。config_version: 2 を必ず先頭に保つ
  • ui/src/components/settings/ — 該当セクションの Form コンポーネントに UI フィールド追加
  • CLAUDE.md — 設定セクションに説明追加(必要に応じて)

なぜ必要か: config.ts と config.yaml.example の不一致は「設定が効かない」「ドキュメントと実動作が違う」を招く。 Settings UI への追加を忘れると、YAML を直接編集しないと設定できなくなる。 v2 layout (llm.* / storage.*) では normalizer 側の backfill / migrate path も触らないと、v1 ファイルでの読み取り互換が壊れる。

確認方法:

# config.ts のフィールド数と config.yaml.example のキー数を目視比較
# Settings UI の各 Form ファイルで未対応フィールドがないか確認
# normalize の v1 fixture が落ちていないか
npx vitest run src/config-normalize.test.ts

4-B. 新しい Settings Form コンポーネントを追加した場合

対象ファイル (両方必須):

  • ui/src/components/settings/<Name>Form.tsx — Form 本体
  • ui/src/components/settings/ConfigForm.tsxrenderActiveForm()switch(section) に新 case 'new-id': return <NewForm {...formProps} />; を追加
  • ui/src/components/settings/SettingsSidebar.tsxCONFIG_GROUPS[].sections[]{ id: 'new-id', label: '...' } を追加。admin 限定なら親グループに adminOnly: true
  • ui/src/lib/urlState.ts — section id の許可リストにも追加 (URL state からの復元)
  • 旧 id をリネームした場合は LEGACY_SECTION_REDIRECT (SettingsSidebar.tsx) にエントリ追加してブックマーク互換を維持

なぜ必要か: ConfigForm の switch と SettingsSidebar の section リストは独立に管理されており、片方だけ追加すると「サイドバーには項目があるが何も描画されない」「描画はされるがサイドバーから飛べない」状態になる。Step 3 (sidebar 再編) / Step 7-9 (form 分割) で両方を毎回触る前提で設計されている。

禁止事項:

  • 削除した旧 Form (ProviderForm.tsx, WorkersForm.tsx, WorkspaceForm.tsx のような単一巨大 form) を復活させない。LLM Workers / Paths & Storage / Execution / Tools-* の分割は v2 design の前提
  • カンマ区切り入力で配列フィールドを作らない。chip エディタ / textarea / multiselect のいずれかを使うこと (値に , を含めるケースを壊さないため)
  • Secret 入力で '********' の magic string 判定を再導入しない。SecretInput (4-state: unchanged / literal / env_ref / cleared) を再利用すること

確認方法:

# section id が両方のファイルで揃っているか
grep -E "'[a-z-]+'" ui/src/components/settings/SettingsSidebar.tsx | grep "id:"
grep "case '" ui/src/components/settings/ConfigForm.tsx
# legacy redirect が漏れていないか
grep -A 20 'LEGACY_SECTION_REDIRECT' ui/src/components/settings/SettingsSidebar.tsx

5. SSRF 保護に関わる変更をした場合

対象ファイル:

  • src/engine/tools/shared/ssrf.ts — SSRF チェックロジック本体
  • src/engine/tools/browser.ts — BrowseWebsetupRouteInterception + ssrfCheck
  • src/engine/tools/web.ts — WebFetch / DownloadFile
  • ui/src/components/settings/ToolsForm.tsx — SSRF Allowed Hosts のヘルプテキスト

なぜ必要か: webfetchAllowedHosts は WebFetch と BrowseWeb の両方で使われている。片方だけ修正すると保護に穴が開くか、意図しないブロックが発生する。


6. ログ出力に関わる変更をした場合

対象ファイル:

  • src/engine/tools/raw-save.tsRAW_SAVE_TOOLS / RAW_LOG_ONLY_TOOLS の更新
  • 各ツールモジュール内の appendXxxHistory() 関数

なぜ必要か: 新ツールを追加したとき、RAW_SAVE_TOOLS への追加を忘れると logs/raw/ に出力が保存されない。 knowledge ツールのように独自で raw 保存する場合は RAW_SAVE_TOOLS に含めない(二重保存回避)。

保存先の整理:

ログ種別 パス 内容
生データ logs/raw/{tool}-{timestamp}.txt/.json ツール実行結果の生出力
WebFetch 履歴 logs/webfetch-history.jsonl URL, ステータス, サイズ
ダウンロード履歴 logs/downloads.jsonl 保存パス, サイズ
ナレッジ履歴 logs/knowledge-history.jsonl クエリ, ヒット数, 所要時間
チェックリスト logs/checklists/{name}.json チェックリスト状態
rawdata インデックス logs/rawdata-history.jsonl raw 保存のメタデータ

7. ツールの詳細ドキュメントを書く場合

対象ファイル:

  • docs/tools/{toolname-lowercase}.md — ツールの詳細な使い方ガイド
  • 該当ツールの description — 概要 + ReadToolDoc({ name: "XXX" }) で参照可能と明記
  • src/engine/tools/docs.tsTOOL_DOC_ALIASES — 関連ツール名を同じ doc にマップ(例: checkitem: 'checklist'
  • 既存 piece に同じガイダンスが書かれていれば削除する(重複解消)

なぜ必要か: Tool description は毎回 LLM のコンテキストに乗るため肥大化させたくない。詳細手順・ワークフロー例は docs/tools/{name}.md に置き、ReadToolDoc ツールで必要時に取得する設計。 ReadToolDoc は META_TOOLS として常時利用可能なので、piece の allowed_tools に追加する必要はない。 関連ツールCheckItem / CreateChecklist / GetChecklist 等は1つの doc にまとめてエイリアス経由で引けるようにする。

確認方法:

  • ファイル名は小文字(例: BrowseWebbrowseweb.md
  • description の末尾に「詳細は ReadToolDoc(...) で取得可能」を明記
  • 全 piece から対応する重複ガイダンスを削除

8. piece の movement 構造を変更した場合

対象ファイル:

  • 対象 pieces/*.yamlrules に遷移先を明示追加

なぜ必要か: default_next は機械的フォールバック専用。LLM が選べる遷移先は rules[].next に明示されたものだけ。 rules に追加せず default_next だけに頼ると、LLM が遷移先を選択できない。


9. Reflection に新しい memory type を追加した場合

対象ファイル:

  • src/engine/reflection/types.tsReflectionMemoryType の union を拡張
  • src/engine/reflection/reflection-schema.ts — LLM tool schema の type enum
  • src/engine/reflection/reflection-prompt.ts — システムプロンプトの type 説明
  • src/engine/reflection/semantic-validator.tsALLOWED_TYPES セット
  • src/bridge/memory-api.ts — PUT のバリデーション
  • ui/src/components/settings/MemoryLearningForm.tsx — type ドロップダウン

なぜ必要か: 4 種類 (user / feedback / project / reference) はメモリ意味論の単位。LLM は schema で型強制されるので、schema・prompt・validator のいずれかを忘れると LLM が「未知の type」を吐いて全 reflection が rejected_unknown_type で落ちる。UI ドロップダウンの更新を忘れるとユーザーが手動編集できなくなる。


10. Reflection に新しい rejection code を追加した場合

対象ファイル:

  • src/engine/reflection/types.tsReflectionRejectionCode の union を拡張
  • src/engine/reflection/semantic-validator.ts — 新しいケースで返す
  • src/engine/reflection/applier.ts — 必要に応じて applier 側の rejection 経路も追加
  • src/bridge/memory-api.ts — 同じコードを返す PUT バリデーションを更新
  • ui/src/components/settings/MemoryLearningForm.tsx — UI 側でコード → 日本語メッセージ変換
  • src/engine/reflection/applier.fuzz.test.ts — fuzz の "known code list" に追加

なぜ必要か: rejection code は metrics・UI 表示・fuzz invariant の3箇所で参照される。fuzz テストは「decision の code は known list のいずれか」と assertion しているので、追加し忘れると fuzz が落ちる。UI 側で未対応コードはユーザーに「不明なエラー」と表示されてしまう。


11. MCP サーバー追加 / authKind 仕様変更時

対象ファイル:

  • src/mcp/registry.tsauth_kind の受け入れ・バリデーション
  • src/mcp/token-manager.tshasToken / getValidToken の authKind 分岐
  • src/bridge/mcp-api.ts — admin (global server) ルート、/api/mcp/connections
  • src/bridge/user-servers-api.ts — user-owned server CRUD
  • ui/src/components/userfolder/McpServersPanel.tsx — authKind ラジオ + 条件付きフォーム
  • ui/src/components/userfolder/McpConnectionsPanel.tsx — authKind=api_key は Authorize ボタン非表示
  • docs/mcp.md — 運用者向け手順 (OAuth と api_key 両方)

なぜ必要か: authKind は server 行に保存され、token-manager・aggregator・UI のそれぞれで分岐する。Phase 8 で OAuth 専用設計から拡張したため、新しい authKind を入れる場合は schema migration + UI フォーム + docs の 3 点を必ず触る。OAuth start ルートは authKind=oauth でしか動かない (api_key は 400 を返す) ので、route 側のガードも忘れない。

確認方法:

  • grep -rn "authKind" src/mcp/ src/bridge/mcp-api.ts src/bridge/user-servers-api.ts ui/src/components/userfolder/Mcp*.tsx で参照漏れを確認
  • 統合テスト: npx vitest run src/mcp/integration.test.ts (OAuth + api_key 両 path をカバー)

UI フォントサイズスケール (Tailwind class 規約)

UI に新しいパネルやコンポーネントを追加するときは、以下の 6 段階スケール から選ぶ。それ以外の text-[Npx] を導入すると全体の字組が崩れる。

サイズ クラス 用途
10px text-[10px] セクションラベルuppercase、極小バッジ
11px text-2xs (Tailwind 拡張、tailwind.config.js で定義済み) ヘルプテキスト、キャプション、メタ情報
12px text-xs 本文小、ボタンラベル、フォーム入力、テーブルセル
13px text-[13px] (Tailwind 標準に該当なし) パネル本文、メイン段落
14px text-sm フォームラベル、ナビゲーション項目、見出し小
16px+ text-base / text-lg / text-xl / text-2xl h2 セクション見出し、ページタイトル、ヒーロー

禁止リスト

以下は 絶対に書かないこと。書いた場合は 2026-05 commit 993ef2f の正規化と同様の一括置換でやり直しになる。

書いてしまった 置き換え先
text-[11px] text-2xs
text-[12px] text-xs
text-[14px] text-sm
text-[15px] text-sm
text-[16px] text-base
text-[18px] text-lg
text-[9px] text-[10px] (極小に丸め)
text-[12.5px] text-[13px]
任意の非標準 px 上記スケールに最も近いものに丸める

なぜ必要か

  • 過去に新規パネル (Help, MCP, AGENTS.md 等) を追加するたびに implementer が独自に text-[Npx] を書き、累積で 13 種類のサイズ が混在した
  • 統一したフォントサイズは UI の一貫性 + 認知負荷の低下に直結する
  • Tailwind utility (text-xs/sm/base/lg/xl/2xl) は font-size と line-height がセット定義されているので、行間も自然に揃う
  • 不要な arbitrary value (text-[Npx]) は CSS の出力サイズも増やす

確認方法

cd ui
# 禁止サイズが残っていないか確認 — 何も出なければ OK
grep -rohE 'text-\[(9|11|12|12\.5|14|15|16|17|18)px\]' src --include='*.tsx'

# 全体のサイズ分布を確認
grep -rohE 'text-\[[0-9]+(\.[0-9]+)?px\]|text-(xs|sm|base|lg|xl|2xl|3xl|4xl|2xs)' src --include='*.tsx' | sort | uniq -c | sort -rn

期待される分布 (Tailwind utility が主、arbitrary は 10px / 13px のみ):

text-xs    (~250 ↑)
text-2xs   (~180 ↑)
text-sm    (~100 ↑)
text-[13px] (~100)
text-[10px] (~100)
text-base, text-lg, text-xl, text-2xl, text-4xl ... (少量)

触る場所

  • 新規 UI コンポーネント全般 (ui/src/**/*.tsx)
  • 既存パネルへの追加要素
  • 設定フォーム (ui/src/components/settings/)
  • ダイアログ・モーダル

12. SSH 関連変更時 (Phase 0-8)

12-A. SSH ツール (SshExec / SshUpload / SshDownload) を変更したとき

対象ファイル:

  • src/engine/tools/ssh.ts — TOOL_DEFS + executeTool + 12-step orchestration
  • src/engine/tools/ssh.test.ts — unit tests (23 件)
  • src/engine/tools/ssh.e2e.test.ts — in-process ssh2 server e2e (4 件、SKIP_SSH_E2E=1 で skip)
  • src/engine/tools/index.tstryLoadModule('./ssh.js') 経由のロード + dispatch
  • src/engine/tools/core.tsToolContext.pieceName (piece grants check に必要)
  • src/engine/piece-runner.tsToolContext 構築時に pieceName: piece.name を thread
  • src/engine/tools/docs.tsTOOL_DOC_ALIASES で 3 ツール名を 'ssh-tools' にマップ
  • docs/tools/ssh-tools.md — LLM 向け詳細ドキュメント
  • src/bridge/server.tssetSshSubsystem({...}) で DI

新ツールを SSH 系で追加する場合、または既存ツールに引数を増やす場合:

  • ssh.ts の TOOL_DEFS description は 1 文 + 「詳細は ReadToolDoc」 に絞る (毎呼び出しのトークン節約)
  • preflight (steps 1-7) を流用するため runExec/runUpload/runDownload の skeleton を踏襲
  • finallyclearBuffer(pem, passphrase) を必ず実行 — ssh2 の internal retention は防げないが我々の copy は zeroize する
  • 監査 action 名は ssh.<verb> 形式 (例: ssh.exec, ssh.upload)。command 全文は 記録せず SHA-256 16-char hexdetail.command_hash
  • piece grants check は subsystem.accessResolver.resolve() を必ず通す (piece membership → access decision → state checks → policy の順)

新しい SshSessionError code を追加する場合:

  • src/ssh/session.tsSshSessionErrorCode union を拡張
  • src/engine/tools/ssh.tsformatSessionError switch に LLM-actionable message を追加
  • docs/tools/ssh-tools.md の「共通エラーコード一覧」表に追記
  • docs/ssh.md の「Troubleshooting → Symptom → cause table」に追記

確認方法:

# tool が grants check を通っているか
grep -n "accessResolver\.resolve\|preflight" src/engine/tools/ssh.ts
# 監査 action 名が既存と整合
grep -n "action:" src/engine/tools/ssh.ts src/bridge/ssh-api.ts | sort -u
# tests
npx vitest run src/engine/tools/ssh.test.ts
SKIP_SSH_E2E=  npx vitest run src/engine/tools/ssh.e2e.test.ts  # 明示的に run

12-B. SSH HTTP API (src/bridge/ssh-api.ts) を変更したとき

対象ファイル:

  • src/bridge/ssh-api.ts — User router + Admin router (25 endpoints)
  • src/bridge/ssh-api.test.ts — auth / maintenance / reason / CRUD / TOFU / grants / rotation
  • src/ssh/maintenance.ts — in-memory maintenance flag
  • src/ssh/admin-rate-limit.ts — token bucket for force-unlock (10/hr)
  • src/bridge/server.tsssh.enabled ゲートで両 router をマウント
  • src/ssh/session.tssshTest() (HTTP test endpoint で使用)
  • docs/ssh.md §"HTTP API Reference" — endpoint table

新しい admin write エンドポイントを追加するとき:

  • body.reason 必須 (≥ 8 chars)。validateReason() を必ず呼ぶ
  • 操作直前に maintenance503() ガードを呼ぶ (read 系は不要)
  • 成功・失敗どちらも auditRepo.beginAndComplete()ssh_audit_log に記録
  • 監査 action は src/ssh/audit-repo.tsSshAuditOutcome と Phase 5 設計書の enum を踏襲
  • admin-only フラグ (allow_remote_unrestricted, allow_private_addresses per-connection) は user 経路で常に reject

新しい user write エンドポイントを追加するとき:

  • getUserId() で取得した userId をオーナーチェックに使う
  • 他人の所有物に対しては 404 を返す (存在を漏らさない)

確認方法:

# admin endpoint で reason check / maintenance ガードが漏れていないか
grep -n "deps.requireAdmin\|maintenance503\|validateReason" src/bridge/ssh-api.ts
# audit log の action 名が既存と整合しているか
grep -n "action:" src/bridge/ssh-api.ts

12-C. SSH repo / schema を変更したとき

対象ファイル:

  • src/db/schema.sqlssh_connections, ssh_connection_grants, ssh_audit_log, ssh_abuse_counters, system_deks
  • src/db/migrate.tsPRAGMA table_info → 列存在チェック → ALTER TABLE ADD COLUMN パターン (バージョン管理テーブル不使用)
  • src/ssh/connection-repo.ts / grants-repo.ts / audit-repo.ts / abuse-repo.ts / access.ts
  • 各 repo に対応する *.test.ts
  • src/ssh/recovery.ts — boot 時 pending → aborted sweep
  • src/ssh/crypto.ts — DEK ラップ / マスター鍵検証
  • docs/ssh.md §"Connection Model" / §"Access Grants" / §"Audit Log"

スキーマ列を追加するとき:

  • schema.sqlCREATE TABLE に列追加 (初期スキーマ)
  • migrate.ts に冪等 ALTER TABLE 追加 (既存 DB 用)
  • 既存テストが影響を受けないか npm test で検証
  • 列をエンドポイントから書く場合、POST/PATCH ハンドラのバリデーションに追加し、admin-only フラグなら user 経路で reject

新しい監査 action を追加するとき:

  • src/ssh/audit-repo.tsSshAuditOutcome は触らない (固定 5 値: pending|success|failed|denied|aborted)
  • action 名は ssh.<entity>.<verb> 形式 (例: ssh.connection.host_key.replace)
  • docs/ssh.md §"Audit Log → Actions" 表に追加
  • docs/tools/ssh-tools.md の「監査ログ」セクションは tool 経由 action のみなので、tool 起因なら追記

確認方法:

# 監査 action 一覧 (重複/typo 検出)
grep -rn "action: 'ssh\." src/ | awk -F"'" '{print $2}' | sort -u
# repo CAS / transaction が崩れていないか
grep -n "BEGIN\|COMMIT\|prepare(" src/ssh/*.ts | head -30

12-D. SSH UI を変更したとき

対象ファイル:

  • ユーザー向け:
    • ui/src/components/userfolder/SshConnectionsPanel.tsx — 一覧 + actions
    • ui/src/components/userfolder/SshConnectionForm.tsx — 作成・編集フォーム
    • ui/src/components/userfolder/SshHostKeyDialog.tsx — TOFU verify ダイアログ
  • 管理者向け:
    • ui/src/components/settings/SshForm.tsx — Settings → SSH のルート
    • ui/src/components/settings/SshGlobalConnectionsForm.tsx — グローバル接続 CRUD
    • ui/src/components/settings/SshGrantsForm.tsx — grants CRUD
    • ui/src/components/settings/SshAuditLog.tsx — 全テナント監査ログ
    • ui/src/components/settings/SshMasterKeyRotationForm.tsx — 鍵 rotation
  • 型定義: ui/src/lib/ssh-types.ts
  • ui/src/components/settings/ConfigForm.tsx / SettingsSidebar.tsxSshForm の登録 (新規 Form 追加時)

確認方法:

  • 新 form を追加した場合 ConfigForm.tsx の section リストに登録、SettingsSidebar.tsx のナビ項目に追加
  • ssh-types.ts と API レスポンス shape (SshConnection, SshGrant, SshAuditRow) が一致しているか
  • 禁止フォントサイズ (text-[11px] 等) を導入していないか — 既存セクションの「UI フォントサイズスケール」参照

12-E. piece schema (allowed_ssh_connections) を変更したとき

対象ファイル:

  • src/engine/piece-runner.tsallowed_ssh_connections の lint (validateMovement)
  • src/engine/types.ts (or piece schema 定義箇所) — allowed_ssh_connections?: string[]
  • pieces/*.yaml — SSH ツールを allowed_tools に含む movement は 必ず allowed_ssh_connections 宣言が必要 (空配列 [] でも可)
  • docs/ssh.md §"Per-piece allowed_ssh_connections"

lint 規約:

  • allowed_tools に SSH ツール名が含まれる場合、allowed_ssh_connections の宣言が必須 (undefined は reject)
  • 値は配列、各要素は * または lowercase hex + ハイフン UUID (≥ 8 chars)
  • 空配列 [] は "deny all" として明示扱い

確認方法:

# 既存 piece に SSH 使用宣言があるか
grep -l 'Ssh\(Exec\|Upload\|Download\)' pieces/*.yaml | xargs -I {} grep -l 'allowed_ssh_connections' {}

12-F. config.yaml の SSH セクション (SshRuntimeConfig) を変更したとき

対象ファイル:

  • src/ssh/config.tsSshRuntimeConfig interface + SSH_DEFAULTS + mergeSshConfig
  • src/config.tstransformKeys でスネーク→キャメル変換、AppConfig に統合
  • config.yaml.example — コメント付きデフォルト値
  • ui/src/components/settings/SshForm.tsx — UI で編集可能にする場合
  • docs/ssh.md §"config.yaml Reference"

確認方法:

# config.ts と config.yaml.example の SSH キー数が一致するか
grep -E '^\s+[a-z_]+:' config.yaml.example | grep -A 30 '^# ssh:' | head -40

12-G. SSH Console (interactive PTY) を変更したとき

SSH Console は SshExec/Upload/Download とは別系統の対話的 PTY 経路。Phase 8 で新規追加。

  • 新ツール SshConsoleEnsure / SshConsoleSend / SshConsoleSnapshot を追加した時:
    • src/engine/tools/ssh-console.tsTOOL_DEFS に追加
    • src/engine/tools/index.ts の dispatch + aggregation に追加
    • src/engine/tools/docs.tsTOOL_DOC_ALIASES にエイリアス
    • docs/tools/ssh-console-tools.md を更新
  • 新 WS endpoint を追加した時:
    • src/bridge/server.ts に upgrade handler 配線
    • auth / visibility / access の 4 段階チェックを記述
  • SessionCloseReason を追加した時:
    • src/ssh/console-protocol.ts (server) と ui/src/lib/ssh-console-types.ts (UI) の両方に追加
    • ConsoleHeader.tsx の disconnected reason 表示に文言を追加

13. Scheduler から呼ばない手動オペレーション endpoint

以下の endpoint は UI からの手動操作専用 で、scheduler / Routine / 自動化経路から起動できない設計になっている。Routine 側の payload schema にこれらの override を追加してはいけない (scheduled task の allowed_tools 境界が想定外に拡大するリスクのため)。

  • POST /api/local/tasks/:id/continue — 別 piece で task を続ける (handoff)
    • 実装: src/bridge/local-tasks-api.ts/continue ハンドラ
    • terminal 状態 (succeeded / failed / waiting_human / cancelled) のときのみ有効
    • 新カテゴリを追加する場合: scheduled-tasks-api.ts / scheduler.ts 側に「実行する piece を override する」機能を持たせない。実行する piece は task 作成時に固定し、人間が UI から明示的に切り替える経路だけ残す

確認方法:

# scheduler 経路から /continue を叩いている箇所が無いか
grep -rn "/continue\b\|continueTaskWithPiece" src/scheduler.ts src/bridge/scheduled-tasks-api.ts
# 無いことが期待値

14. Knowledge Notes 追加・変更時

Knowledge Notes は data/users/{userId}/notes/ 以下のマークダウンファイルで管理される共有ナレッジ機能。 FM (frontmatter) の visibility / scope_org_id で公開範囲を制御し、他ユーザーが検索・購読・inject できる。

対象ファイル:

  • src/db/schema.sqlsrc/db/migrate.ts — dual path で両方更新 (知識テーブル追加時)
  • src/engine/tools/index.ts — 新ツールの dynamic import
  • pieces/*.yamlallowed_tools に必要なツール名を追加
  • src/engine/tools/docs.tsTOOL_DOC_ALIASES — 関連ツールを同じ doc にまップ
  • ui/src/components/userfolder/FileTree.tsxFILE_SUBDIRS — サイドバーに新ディレクトリを追加
  • config.yaml.examplenotes.inject セクションのサンプル設定を更新

セキュリティ・可視性チェックリスト:

  • src/db/schema.sqlsrc/db/migrate.ts の両方を更新 (dual path)
  • 新ツールを src/engine/tools/index.ts の dynamic import に追加
  • pieces/*.yamlallowed_tools に必要なツール名を追加
  • src/engine/tools/docs.tsTOOL_DOC_ALIASES にエイリアスを追加
  • ui/src/components/userfolder/FileTree.tsxFILE_SUBDIRS を更新
  • config.yaml.examplenotes.inject セクションを更新
  • FM の visibility=org チェックは publisher の所属 org で行う (getUserOrgIds)
  • inject 注入経路 (agent-loop.ts buildSystemPrompt) は visibility WHERE を必ず通る
  • cross-user read は audit_log に記録される

なぜ必要か: visibility=org の org チェックを publisher 側の org で行わないと、異なる org のユーザーが他 org のートを閲覧できる。inject 経路で visibility チェックを省略すると、private なートがシステムプロンプト経由で漏洩する。cross-user read の監査記録が欠けると、後からアクセス追跡ができなくなる。

確認方法:

# visibility WHERE が inject 経路にあるか
grep -n "visibility\|getUserOrgIds" src/engine/agent-loop.ts

# audit_log への記録が行われているか
grep -n "audit_log\|read_note" src/engine/tools/knowledge.ts

# SearchNotes / ListNotes ツールが tools-api.ts に登録されているか
grep -n "knowledge\|notes" src/bridge/tools-api.ts

Bash Unrestricted モード (safety.bash_unrestricted) の変更時

対象ファイル:

  • src/engine/tools/sandbox.ts — bwrap サンドボックスのマウント構成・実行ロジック
  • src/engine/tools/core.tsexecuteBash の分岐 (ctx.bashUnrestricted)、ToolContext インターフェース
  • src/engine/piece-runner.tssafetyConfig.bashUnrestrictedToolContext への伝播
  • src/worker-bootstrap.ts — 起動時 bwrap 可用性チェック
  • src/config.tsSafetyConfig.bashUnrestricted 定義・バリデーション

なぜ必要か: bwrap のマウント構成を変えた場合、セキュリティ境界が変わる。テスト (sandbox.test.ts, core.test.tsbashUnrestricted mode セクション) を必ず更新すること。


自動検知の可能性

  • ツールモジュール登録漏れ: index.tstools-api.ts のモジュール一覧を比較するスクリプトで CI チェック可能
  • piece の allowed_tools 不整合: 全 piece の allowed_tools に含まれるツール名が実際の TOOL_DEFS に存在するか検証するスクリプトで CI チェック可能
  • code-review-graph: importers_of で各ツールモジュールの参照元を列挙できるが、「tools-api.ts にも登録すべき」というルールの自動適用は困難。変更時の detect_changes + get_impact_radius で影響範囲の見落としを防ぐ用途が現実的