31 KiB
メンテナンスチェックリスト
コード変更時に連動して修正が必要な箇所のリスト。 過去に実際に発生した不整合をもとに作成。
1. ツールモジュールを新規追加した場合
対象ファイル:
src/engine/tools/<module>.ts— 新モジュール本体src/engine/tools/index.ts—tryLoadModuleで動的ロード追加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.ts—RAW_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.ts—ToolsConfig/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.tsx—renderActiveForm()のswitch(section)に新case 'new-id': return <NewForm {...formProps} />;を追加ui/src/components/settings/SettingsSidebar.tsx—CONFIG_GROUPS[].sections[]に{ id: 'new-id', label: '...' }を追加。admin 限定なら親グループにadminOnly: trueui/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— BrowseWeb(setupRouteInterception+ssrfCheck)src/engine/tools/web.ts— WebFetch / DownloadFileui/src/components/settings/ToolsForm.tsx— SSRF Allowed Hosts のヘルプテキスト
なぜ必要か:
webfetchAllowedHosts は WebFetch と BrowseWeb の両方で使われている。片方だけ修正すると保護に穴が開くか、意図しないブロックが発生する。
6. ログ出力に関わる変更をした場合
対象ファイル:
src/engine/tools/raw-save.ts—RAW_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.tsのTOOL_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 にまとめてエイリアス経由で引けるようにする。
確認方法:
- ファイル名は小文字(例:
BrowseWeb→browseweb.md) - description の末尾に「詳細は ReadToolDoc(...) で取得可能」を明記
- 全 piece から対応する重複ガイダンスを削除
8. piece の movement 構造を変更した場合
対象ファイル:
- 対象
pieces/*.yaml—rulesに遷移先を明示追加
なぜ必要か:
default_next は機械的フォールバック専用。LLM が選べる遷移先は rules[].next に明示されたものだけ。
rules に追加せず default_next だけに頼ると、LLM が遷移先を選択できない。
9. Reflection に新しい memory type を追加した場合
対象ファイル:
src/engine/reflection/types.ts—ReflectionMemoryTypeの union を拡張src/engine/reflection/reflection-schema.ts— LLM tool schema のtypeenumsrc/engine/reflection/reflection-prompt.ts— システムプロンプトの type 説明src/engine/reflection/semantic-validator.ts—ALLOWED_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.ts—ReflectionRejectionCodeの 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.ts—auth_kindの受け入れ・バリデーションsrc/mcp/token-manager.ts—hasToken/getValidTokenの authKind 分岐src/bridge/mcp-api.ts— admin (global server) ルート、/api/mcp/connectionssrc/bridge/user-servers-api.ts— user-owned server CRUDui/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 orchestrationsrc/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.ts—tryLoadModule('./ssh.js')経由のロード + dispatchsrc/engine/tools/core.ts—ToolContext.pieceName(piece grants check に必要)src/engine/piece-runner.ts—ToolContext構築時にpieceName: piece.nameを threadsrc/engine/tools/docs.ts—TOOL_DOC_ALIASESで 3 ツール名を'ssh-tools'にマップdocs/tools/ssh-tools.md— LLM 向け詳細ドキュメントsrc/bridge/server.ts—setSshSubsystem({...})で DI
新ツールを SSH 系で追加する場合、または既存ツールに引数を増やす場合:
- ssh.ts の
TOOL_DEFSdescription は 1 文 + 「詳細は ReadToolDoc」 に絞る (毎呼び出しのトークン節約) - preflight (steps 1-7) を流用するため
runExec/runUpload/runDownloadの skeleton を踏襲 finallyでclearBuffer(pem, passphrase)を必ず実行 — ssh2 の internal retention は防げないが我々の copy は zeroize する- 監査 action 名は
ssh.<verb>形式 (例:ssh.exec,ssh.upload)。command 全文は 記録せず SHA-256 16-char hex をdetail.command_hashに - piece grants check は
subsystem.accessResolver.resolve()を必ず通す (piece membership → access decision → state checks → policy の順)
新しい SshSessionError code を追加する場合:
src/ssh/session.tsのSshSessionErrorCodeunion を拡張src/engine/tools/ssh.tsのformatSessionErrorswitch に 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 / rotationsrc/ssh/maintenance.ts— in-memory maintenance flagsrc/ssh/admin-rate-limit.ts— token bucket for force-unlock (10/hr)src/bridge/server.ts—ssh.enabledゲートで両 router をマウントsrc/ssh/session.ts—sshTest()(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.tsのSshAuditOutcomeと Phase 5 設計書の enum を踏襲 - admin-only フラグ (
allow_remote_unrestricted,allow_private_addressesper-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.sql—ssh_connections,ssh_connection_grants,ssh_audit_log,ssh_abuse_counters,system_dekssrc/db/migrate.ts—PRAGMA 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 sweepsrc/ssh/crypto.ts— DEK ラップ / マスター鍵検証docs/ssh.md§"Connection Model" / §"Access Grants" / §"Audit Log"
スキーマ列を追加するとき:
schema.sqlのCREATE TABLEに列追加 (初期スキーマ)migrate.tsに冪等 ALTER TABLE 追加 (既存 DB 用)- 既存テストが影響を受けないか
npm testで検証 - 列をエンドポイントから書く場合、
POST/PATCHハンドラのバリデーションに追加し、admin-only フラグなら user 経路で reject
新しい監査 action を追加するとき:
src/ssh/audit-repo.tsのSshAuditOutcomeは触らない (固定 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— 一覧 + actionsui/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— グローバル接続 CRUDui/src/components/settings/SshGrantsForm.tsx— grants CRUDui/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.tsx—SshFormの登録 (新規 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.ts—allowed_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-pieceallowed_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.ts—SshRuntimeConfiginterface +SSH_DEFAULTS+mergeSshConfigsrc/config.ts—transformKeysでスネーク→キャメル変換、AppConfigに統合config.yaml.example— コメント付きデフォルト値ui/src/components/settings/SshForm.tsx— UI で編集可能にする場合docs/ssh.md§"config.yamlReference"
確認方法:
# 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.tsのTOOL_DEFSに追加src/engine/tools/index.tsの dispatch + aggregation に追加src/engine/tools/docs.tsのTOOL_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.sqlとsrc/db/migrate.ts— dual path で両方更新 (知識テーブル追加時)src/engine/tools/index.ts— 新ツールの dynamic importpieces/*.yaml—allowed_toolsに必要なツール名を追加src/engine/tools/docs.tsのTOOL_DOC_ALIASES— 関連ツールを同じ doc にまップui/src/components/userfolder/FileTree.tsxのFILE_SUBDIRS— サイドバーに新ディレクトリを追加config.yaml.example—notes.injectセクションのサンプル設定を更新
セキュリティ・可視性チェックリスト:
src/db/schema.sqlとsrc/db/migrate.tsの両方を更新 (dual path)- 新ツールを
src/engine/tools/index.tsの dynamic import に追加 pieces/*.yamlのallowed_toolsに必要なツール名を追加src/engine/tools/docs.tsのTOOL_DOC_ALIASESにエイリアスを追加ui/src/components/userfolder/FileTree.tsxのFILE_SUBDIRSを更新config.yaml.exampleのnotes.injectセクションを更新- FM の
visibility=orgチェックは publisher の所属 org で行う (getUserOrgIds) - inject 注入経路 (
agent-loop.tsbuildSystemPrompt) は 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.ts—executeBashの分岐 (ctx.bashUnrestricted)、ToolContextインターフェースsrc/engine/piece-runner.ts—safetyConfig.bashUnrestricted→ToolContextへの伝播src/worker-bootstrap.ts— 起動時 bwrap 可用性チェックsrc/config.ts—SafetyConfig.bashUnrestricted定義・バリデーション
なぜ必要か:
bwrap のマウント構成を変えた場合、セキュリティ境界が変わる。テスト (sandbox.test.ts, core.test.ts の bashUnrestricted mode セクション) を必ず更新すること。
自動検知の可能性
- ツールモジュール登録漏れ:
index.tsとtools-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で影響範囲の見落としを防ぐ用途が現実的