diff --git a/documentation/ARCH__FUTURE.md b/documentation/ARCH__FUTURE.md index d7131fa..0f25895 100644 --- a/documentation/ARCH__FUTURE.md +++ b/documentation/ARCH__FUTURE.md @@ -1,7 +1,7 @@ # Architecture: Planned Features > What's next and how it's designed to work. -> Last updated: 2026-04-29 +> Last updated: 2026-05-11 For the current task list see `TODO__Agents.md`. For phases and priorities see `ROADMAP.md`. @@ -313,4 +313,89 @@ This pattern maps naturally to several existing concepts: 2. Define the schema document — what goes in a wiki page, cross-reference format, category taxonomy 3. Build an ingest tool/script that reads a source and updates wiki pages (LLM-driven) 4. Build a lint cron job that health-checks the wiki periodically -5. Consider Obsidian compatibility for human browsing of the wiki graph \ No newline at end of file +5. Consider Obsidian compatibility for human browsing of the wiki graph + +--- + +## 12. Spawner-Level Tool Restrictions — `spawn_agent` Permission Control + +**Status:** Design complete, not yet built. + +### Problem + +`spawn_agent` currently grants sub-agents the full tool set of whatever role they're assigned. The spawning agent (Inara) cannot restrict a sub-agent to a subset of tools — the role config is the only gate. This means every spawned agent implicitly has access to everything the role allows, including potentially destructive operations (`shell_exec`, `file_write`, `cortex_restart`). + +### Design + +Add two optional parameters to `spawn_agent`: **`allow_tools`** and **`deny_tools`**. + +- **`allow_tools`** — explicit allow list. If set, the sub-agent can *only* use tools in this list (intersected with what the role allows). If omitted, the role's full tool set is available. +- **`deny_tools`** — explicit deny list. If set, these tools are removed from whatever the sub-agent would otherwise have access to. If omitted, nothing is denied beyond what the role already excludes. + +**Effective tool set formula:** + +``` +effective = (role_base_tools ∩ allow_tools) ∩ (role_base_tools \ deny_tools) +``` + +Where `role_base_tools` is the full tool set the role config grants, `allow_tools` is the spawner's allow list (default: full set), and `deny_tools` is the spawner's deny list (default: empty set). + +### Usage Examples + +```python +# Research agent — web only, no file access, no shell +spawn_agent( + "Research the latest on Zigbee mesh repeaters", + role="chat", + allow_tools=["web_search", "web_read", "http_fetch"] +) + +# Code review — read-only, no shell +spawn_agent( + "Review this file for security issues", + role="coder", + deny_tools=["shell_exec", "file_write", "cortex_restart", "cortex_update"] +) + +# Full access (same as today — omit both params) +spawn_agent("Refactor the auth module", role="coder") + +# Narrow data migration — just file ops, no web +spawn_agent( + "Migrate the task files to the new format", + role="coder", + allow_tools=["file_read", "file_write", "file_list"] +) +``` + +### Implementation Plan + +**1. Model registry / role config — no changes needed.** + +The role config (`role_cfg.get("tools")`) remains the authoritative ceiling. No schema changes at this level. + +**2. `spawn_agent` function — new parameters + filtering logic.** + +File: `cortex/tools/agents.py`. Add `allow_tools` and `deny_tools` as optional `list[str] | None` parameters. After resolving `tool_list` from `role_cfg.get("tools")`, apply the filter: + +```python +if allow_tools is not None: + tool_list = [t for t in tool_list if t in allow_tools] +if deny_tools is not None: + tool_list = [t for t in tool_list if t not in deny_tools] +``` + +**3. Declaration — update the Gemini `FunctionDeclaration`.** + +Add `allow_tools` and `deny_tools` as optional parameters in the declaration so the orchestrator knows they exist. + +**4. Confirmation gate behavior — explicit.** + +If a sub-agent with restricted tools hits a confirmation gate (e.g., trying `shell_exec` with it denied), the gate blocks as normal — it does not silently fail. The sub-agent returns the "requires user confirmation" message as it already does. + +### What Doesn't Change + +- Existing `spawn_agent` calls with no `allow_tools`/`deny_tools` continue to work exactly as before +- Role config remains the authoritative max — no security regression +- No schema changes to `model_registry.json` +- No UI changes needed