This commit is contained in:
@@ -54,29 +54,29 @@ grep -c "engine/tools/" src/bridge/tools-api.ts
|
||||
## 2. 既存モジュールにツールを追加した場合
|
||||
|
||||
**対象ファイル:**
|
||||
- `pieces/*.yaml` — 必要な piece の `allowed_tools` にツール名を追加
|
||||
- `src/engine/tools/tool-categories.ts` — 新ツールを適切なカテゴリに割り当てる(sensitive は既定 OFF)。ツールの利用可否は workspace tool policy(設定→ツール)が決めるので、**piece 側に追加する必要はない**
|
||||
- `CLAUDE.md` — 「ツールモジュール構成」テーブルの該当モジュール行に新ツール名を追加
|
||||
- `docs/tools/{name}.md` — 新ツールの詳細ドキュメント(推奨)
|
||||
- ツール `description` — 1 文 + 「詳細は ReadToolDoc({ name: "XXX" })」を末尾に記述
|
||||
|
||||
**なぜ必要か:**
|
||||
`allowed_tools` に載っていないツールは LLM に提示されない。ツールを実装しても piece に追加しなければエージェントが使えない。
|
||||
ツールの提示は workspace tool policy が決める(カテゴリ単位。sensitive 以外は既定 ON)。カテゴリ未割り当てだとどのワークスペースでも出ない。
|
||||
CLAUDE.md のテーブルが古いと、Claude Code 自身が既存ツールを認識せずに新規実装してしまうリスクがある。
|
||||
ツール description は毎 LLM 呼び出しに乗るため 1 文に絞り、詳細は ReadToolDoc 経由で必要時のみ読み込む(agent-loop が movement 開始時に description サマリを自動カタログ化する)。
|
||||
|
||||
**確認方法:**
|
||||
新ツールが使われるべき piece を特定し、`allowed_tools` に含まれているか確認する。
|
||||
`tool-categories.ts` で新ツールがカテゴリに割り当てられているか確認する。
|
||||
CLAUDE.md のモジュールテーブルに新ツール名が含まれているか確認する。
|
||||
|
||||
**実例: TestWorkspaceApp(2026-06-24):**
|
||||
`src/engine/tools/app-test.ts` に追加 → `tools/index.ts` で `tryLoadModule` 追加 → `src/bridge/tools-api.ts` のモジュール一覧に追加 → `pieces/workspace-app.yaml` の verify movement `allowed_tools` に追加 → `src/engine/tools/docs.ts` の `TOOL_DOC_ALIASES` に `testworkspaceapp: 'testworkspaceapp'` を追加 → `docs/tools/testworkspaceapp.md` を新規作成。
|
||||
`src/engine/tools/app-test.ts` に追加 → `tools/index.ts` で `tryLoadModule` 追加 → `src/bridge/tools-api.ts` のモジュール一覧に追加 → `tool-categories.ts` でカテゴリ割り当て → `src/engine/tools/docs.ts` の `TOOL_DOC_ALIASES` に `testworkspaceapp: 'testworkspaceapp'` を追加 → `docs/tools/testworkspaceapp.md` を新規作成。(旧手順の「piece の allowed_tools に追加」は撤去済み)
|
||||
|
||||
---
|
||||
|
||||
## 3. ツールをリネーム・削除した場合
|
||||
|
||||
**対象ファイル:**
|
||||
- `pieces/*.yaml` — 全 piece の `allowed_tools` から旧名を削除/リネーム
|
||||
- `src/engine/tools/tool-categories.ts` — カテゴリ定義・`SENSITIVE_TOOLS` から旧名を削除/リネーム
|
||||
- `src/engine/tools/raw-save.ts` — `RAW_SAVE_TOOLS` に旧名が残っていないか
|
||||
- `ui/src/components/settings/ToolsForm.tsx` — ヘルプテキスト等にツール名の言及がないか
|
||||
- `CLAUDE.md` — ツールモジュール構成テーブル
|
||||
@@ -205,7 +205,7 @@ grep -A 20 'LEGACY_SECTION_REDIRECT' ui/src/components/settings/SettingsSidebar.
|
||||
|
||||
**なぜ必要か:**
|
||||
Tool description は毎回 LLM のコンテキストに乗るため肥大化させたくない。詳細手順・ワークフロー例は `docs/tools/{name}.md` に置き、`ReadToolDoc` ツールで必要時に取得する設計。
|
||||
ReadToolDoc は META_TOOLS として常時利用可能なので、piece の `allowed_tools` に追加する必要はない。
|
||||
ReadToolDoc は META_TOOLS として常時利用可能(workspace tool policy でも常時 ON)。
|
||||
関連ツール(CheckItem / CreateChecklist / GetChecklist 等)は1つの doc にまとめてエイリアス経由で引けるようにする。
|
||||
|
||||
**確認方法:**
|
||||
@@ -465,23 +465,26 @@ grep -n "BEGIN\|COMMIT\|prepare(" src/ssh/*.ts | head -30
|
||||
- ssh-types.ts と API レスポンス shape (`SshConnection`, `SshGrant`, `SshAuditRow`) が一致しているか
|
||||
- 禁止フォントサイズ (`text-[11px]` 等) を導入していないか — 既存セクションの「UI フォントサイズスケール」参照
|
||||
|
||||
### 12-E. piece schema (`allowed_ssh_connections`) を変更したとき
|
||||
### 12-E. SSH 接続の認可 (workspace connection scoping) を変更したとき
|
||||
|
||||
SSH 接続の認可は **piece ではなくワークスペース**で決まる(設定→SSH の登録接続)。
|
||||
piece の `allowed_ssh_connections` は撤去済み。接続スコープは worker が解決して
|
||||
`workspaceSshConnections` として piece-runner に渡す。
|
||||
|
||||
**対象ファイル:**
|
||||
- `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-piece `allowed_ssh_connections`"
|
||||
- `src/worker.ts` — `parsedPolicy.enabledSensitive` に `ssh` があるとき `listBySpace(spaceId)` で接続 ID を解決(`workspaceSshConnections`)
|
||||
- `src/engine/piece-runner.ts` — `workspaceSshConnections ?? []` を `ctx.allowedSshConnections` / `movement.allowedSshConnections` に流す
|
||||
- `src/engine/tools/ssh.ts` — preflight で `ctx.allowedSshConnections` に対して接続 ID を検証
|
||||
- `docs/ssh.md` §"接続の認可"
|
||||
|
||||
**lint 規約:**
|
||||
- `allowed_tools` に SSH ツール名が含まれる場合、`allowed_ssh_connections` の宣言が必須 (`undefined` は reject)
|
||||
- 値は配列、各要素は `*` または lowercase hex + ハイフン UUID (≥ 8 chars)
|
||||
- 空配列 `[]` は "deny all" として明示扱い
|
||||
**規約:**
|
||||
- 接続が 1 つも登録されていない(空配列)→ SSH ツールはクリーンに reject
|
||||
- `'*'` ワイルドカードは worker からは渡さない(常に明示 ID リスト = クロススペース分離保証)
|
||||
|
||||
**確認方法:**
|
||||
```bash
|
||||
# 既存 piece に SSH 使用宣言があるか
|
||||
grep -l 'Ssh\(Exec\|Upload\|Download\)' pieces/*.yaml | xargs -I {} grep -l 'allowed_ssh_connections' {}
|
||||
# worker が ssh 接続を解決している経路
|
||||
grep -n 'workspaceSshConnections' src/worker.ts src/engine/piece-runner.ts
|
||||
```
|
||||
|
||||
### 12-F. config.yaml の SSH セクション (`SshRuntimeConfig`) を変更したとき
|
||||
@@ -517,7 +520,7 @@ SSH Console は SshExec/Upload/Download とは別系統の対話的 PTY 経路
|
||||
|
||||
## 13. Scheduler から呼ばない手動オペレーション endpoint
|
||||
|
||||
以下の endpoint は **UI からの手動操作専用** で、scheduler / Routine / 自動化経路から起動できない設計になっている。Routine 側の payload schema にこれらの override を追加してはいけない (scheduled task の `allowed_tools` 境界が想定外に拡大するリスクのため)。
|
||||
以下の endpoint は **UI からの手動操作専用** で、scheduler / Routine / 自動化経路から起動できない設計になっている。Routine 側の payload schema にこれらの override を追加してはいけない (scheduled task のツール境界〈ワークスペースのツールポリシーで決まる〉が想定外に拡大するリスクのため)。
|
||||
|
||||
- `POST /api/local/tasks/:id/continue` — 別 piece で task を続ける (handoff)
|
||||
- 実装: `src/bridge/local-tasks-api.ts` の `/continue` ハンドラ
|
||||
@@ -557,8 +560,67 @@ bwrap のマウント構成を変えた場合、セキュリティ境界が変
|
||||
|
||||
---
|
||||
|
||||
## 15. A2A 認可サーバー (`src/bridge/a2a/`)
|
||||
|
||||
外部エージェント連携(A2A)の OAuth2 認可サーバー関連を変更するときに連動が必要な箇所。
|
||||
|
||||
### DB テーブル・スキーマを変更するとき
|
||||
|
||||
- `src/db/schema.sql` の `CREATE TABLE`(`oidc_models` / `a2a_clients`)を更新(初期スキーマ)
|
||||
- `src/db/migrate.ts` に冪等 `ALTER TABLE ADD COLUMN` を追加(既存 DB 用)。**dual-path 必須**(どちらか片方だけ更新するとテストが大量に落ちる)
|
||||
- `src/db/repository.a2a.ts` / `src/bridge/a2a/oidc-adapter.ts` のクエリを合わせて修正
|
||||
|
||||
### `config.yaml` の `a2a` セクションを変更するとき
|
||||
|
||||
- YAML キーはスネークケース (`client_ttl_seconds`)、コード内はキャメルケース (`clientTtlSeconds`)
|
||||
- `src/config.ts` の `transformKeys` が自動変換するため、読み取り側では キャメルケースのみ使う
|
||||
- `config.yaml.example` にコメント付きで追記する
|
||||
- `A2aConfig` interface(`src/config.ts`)に対応フィールドを追加
|
||||
|
||||
### A2A ルーターを変更するとき
|
||||
|
||||
- `createConsentRouter` / `createA2aClientsAdminRouter` / `mountA2aOidc` はいずれも `src/bridge/server.ts` でマウントされる。新しい router を追加した場合は `server.ts` の配線を忘れずに
|
||||
- 管理者専用エンドポイントは `requireAdmin` ミドルウェアを必ず通すこと
|
||||
- ユーザー向け同意エンドポイントは `requireAuth` を通し、操作対象の `sub`(subject)をセッションの userId と照合する
|
||||
|
||||
### A2A 公開スキル(スペース許可リスト)を変更するとき
|
||||
|
||||
- 公開スキルは `spaces.a2a_skills`(JSON 配列カラム)に保存される。スキーマ変更時は `schema.sql` と `migrate.ts` の**両方**(dual-path 必須)を更新すること
|
||||
- 委任は `a2a_delegations` テーブルで管理し、`grant_id` で OAuth grant(`oidc_models`)にリンクする。`grant_id` の整合性は外部キーではなくアプリ層で保証しているため、grant 削除時は対応する delegation も削除すること
|
||||
- 委任フィルタは **`buildVisibilityWhere` の OR 句に追加しない**。タスク/ジョブの公開スコープ(private/org/public)とは独立したフィルタとして AND 交差で適用すること(OR に混ぜると cross-space IDOR の原因になる)
|
||||
- Agent Card の公開エンドポイント(`GET /.well-known/agent.json`)とスペースオーナー向け API(公開スキル設定 PATCH)は、いずれも `a2a.enabled` ゲートを通過した場合のみ有効。ゲートを外したルートを追加しないこと
|
||||
|
||||
### A2A スキル実行(executor)を変更するとき
|
||||
|
||||
- `a2a_tasks` テーブルは `schema.sql` と `migrate.ts` の**両方**(dual-path 必須)を更新すること
|
||||
- executor は `createLocalTask` → `createJob` の順に呼ぶ。`createLocalTask` 単体はジョブをエンキューしない(`createJob` で初めて Worker がポーリングで拾える状態になる)
|
||||
- ジョブ完了の検知はポーリング(`a2a_tasks` の `status` カラムを定期参照)で行い、進捗は SSE で外部エージェントに返す
|
||||
- 実行完了後、`output/` 以下のファイルは A2A Artifact として返却する
|
||||
- 委任スコープは executor でも `computeEffectiveScope` を通じて再強制する。トークンの委任スコープがスペースの公開スキル設定を上回ることは許容しない(fail-closed)
|
||||
- `buildVisibilityWhere` の OR 句に委任条件を追加しないこと(AND 交差で適用する)
|
||||
|
||||
### 非ブロッキング送信 + reconciler(`reconciler.ts` / `task-finalize.ts`)を変更するとき
|
||||
|
||||
- **非ブロッキング契約**: `message/send` の `params.configuration.blocking: false` は SDK ネイティブ機能。executor が初期 Task(`submitted`)を publish した時点で SDK が即座にレスポンスを返す(完了を待たない)。外部エージェントは後から `tasks/get`(`params.id`)で最新状態を取得する。executor 自体を非ブロッキング化する改造は不要(SDK 側で完結)。
|
||||
- **reconciler は単一起動**: `A2aTaskReconciler` は `server.ts` で `a2a.enabled` ゲート内から 1 インスタンスだけ `start()` する(多重起動は state churn の原因)。テストでは `start()` の interval を使わず `reconcileOnce()` を明示的に呼んで決定論化すること。
|
||||
- **DB が source of truth**: reconciler は `a2a_tasks`(非 terminal 行)を `listNonTerminalA2aTasks` で走査し、リンク先の MAESTRO ジョブ状態(`getJob`)と突き合わせて収束させる。live executor が切断・再起動で消えても、reconciler だけでタスクを terminal 化できる(再起動耐性)。in-memory の per-task detached promise には依存しない。
|
||||
- **終端化ロジックは共有**: `enumerateOutputArtifacts` / `finalizeStatusFromJob` / `TERMINAL_JOB_STATUSES`(`task-finalize.ts`)を executor と reconciler の**両方**が使う。ジョブ状態 → A2A state の写像や artifact 列挙を変えるときは、この共有ヘルパだけを直せば両経路に反映される(ロジックを片方に複製しないこと)。
|
||||
- **冪等な状態一致スキップ**: reconciler は `payload.status.state` が算出後の state と一致する場合は再書き込みしない(`waiting_human → input-required` の churn 防止)。`saveA2aTask` は task id の upsert なので executor と reconciler が競合しても二重書きは安全。
|
||||
- **委任カラムの保持**: reconciler が `saveA2aTask` を呼ぶ際は `payload.metadata` の `a2aDelegationId` / `a2aGrantId` / `a2aActingUserId` を `a2a_tasks` の `delegation_id` / `grant_id` / `acting_user_id` 列へ写す(`task-store.ts` の save 規約と同一)。列を増やすときは executor の初期 Task metadata・`SqliteA2aTaskStore.save`・`reconciler.persistTask` の 3 箇所を揃えること。
|
||||
|
||||
**確認方法:**
|
||||
```bash
|
||||
# A2A 関連テスト一括実行
|
||||
npx vitest run src/bridge/a2a/ src/db/migrate.test.ts src/db/repository.a2a.test.ts src/db/repository.a2a-deleg.test.ts
|
||||
# router のマウント漏れを確認
|
||||
grep -n "mountA2aOidc\|createA2aClients\|createConsent" src/bridge/server.ts
|
||||
# buildVisibilityWhere に委任条件が混入していないか確認
|
||||
grep -n "a2a_delegations\|a2a_skills" src/db/repository.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 自動検知の可能性
|
||||
|
||||
- **ツールモジュール登録漏れ**: `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` で影響範囲の見落としを防ぐ用途が現実的
|
||||
|
||||
Reference in New Issue
Block a user