Skip to content

feat: Environment-level tool sandboxing for sub-agents (enforce tool_restrictions) #4042

Description

@JayBeest

Context

This issue tracks the runtime enforcement of tool restrictions across CodeWhale's different execution contexts — sessions, sub-agents, Fleet workers, and MCP servers.

What We've Confirmed (Without Checking the Code Directly)

  1. --disallowed-tools exists and works — It was implemented in PR v0.8.58: Headless exec hardening — --allowed-tools/--disallowed-tools, --max-turns, --append-system-prompt, stream-json input #3027. The flag is wired into the gate chain and filters the advertised tool catalog before the model sees it. Deny wins over allow. This is structural enforcement: the LLM never even sees the restricted tools.
  2. Scope is session-wide — The flag applies from session start to finish. Sub-agents inherit the parent's tool registry by default, so --disallowed-tools flows down to child agents automatically.
  3. Fleet workers do NOT inherit — Fleet workers are headless codewhale exec processes and do not inherit flags from the parent session. However, FleetExecConfig has a dedicated disallowed_tools field, meaning tool restrictions can be configured per Fleet worker — just not via inheritance from the parent CLI flag.
  4. **Dynamic MCP servers (**feat: add dynamic MCP server infrastructure to McpPool #3869) are a parallel path — Dynamic MCP servers allow the LLM to spawn new capabilities at runtime. This is powerful for emergent behavior, but it raises new questions about how static restrictions (like --disallowed-tools) interact with runtime-expanded capabilities.

The Problem

The constitutional crisis (#4032) arises because the "no temp scripts" rule currently lives in the SKILL.md prompt, which the LLM can rationalize its way around. --disallowed-tools provides a structural solution for session-wide and sub-agent contexts, but the scope inconsistencies (especially with Fleet workers and MCP servers) leave gaps.

What This Issue Covers

Rather than building a new mechanism from scratch, this issue focuses on:

  1. Clarifying scope — Documenting and testing where --disallowed-tools applies (session, sub-agent, Fleet) and where it doesn't.
  2. Wiring consistency — Ensuring that tool restrictions flow consistently across all execution contexts:
    • Sessions → --disallowed-tools flag
    • Sub-agents → inherited by default (but should be configurable per-role)
    • Fleet workers → FleetExecConfig.disallowed_tools (explicit per-task)
    • MCP servers → dynamic spawns should respect the same gate chain
  3. Testing the edge cases — Validating that structural enforcement actually prevents temp scripts, and that no side-doors (like python -c via execute) bypass the restriction.

Dependencies

Out of Scope for This Issue

  • Defining new schema/fields (that's Add per-sub-agent provider routing #3969, if needed)
  • Keyword-based or cost-based routing (future enhancement)
  • Modifying SKILL.md parsing (the constraint is moving from prompts to structural enforcement)

Acceptance Criteria

  1. Session-level: Start CodeWhale with --disallowed-tools write_file,execute_python — the LLM cannot write temp scripts via write_file or execute with python -c.
  2. Sub-agent inheritance: Spawn a sub-agent from the restricted session — the restrictions flow down automatically.
  3. Fleet worker: Define a Fleet task with disallowed_tools = ["write_file", "execute_python"] — the worker cannot write temp scripts.
  4. MCP (future): If dynamic MCP is used, spawned servers should not be able to bypass the gate chain.
  5. No prompt bypass: The LLM cannot work around the restrictions via prompt injection, because the tools simply aren't in its function-calling schema.

What This Issue Is Not

This is not "we need to build tool_restrictions from scratch." The mechanism (--disallowed-tools + gate chain) already exists. This issue is about:

  • Validating that it works across all contexts
  • Documenting the scope and inheritance rules
  • Identifying any gaps (especially around MCP and Fleet)
  • Testing the edge cases

Happy to help test once there's a build available. 🐋

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingenhancementNew feature or requestlane-fleetv0.9.0 delivery lane (retired)reliabilityReliability, flaky behavior, retries, fallbacks, and robustnesssandboxSandbox, container, or OS-level isolation behaviorsecuritySecurity, isolation, permissions, or trust-boundary worksubagentsSub-agent orchestration, lifecycle, and completion handlingtoolsTool execution, tool schemas, tool UX, and built-in tool behaviorv0.9.0Targeting v0.9.0

    Projects

    Status
    Done

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions