Describe the bug
The generated system prompt contains instructions for tools that are not available to the model after mode and tool filtering.
For example, execute_command is only part of the command tool group, so it is available in the built-in Code and Debug modes but not in Architect, Ask, or Orchestrator. Despite that, the common capabilities and rules sections tell every mode that it can use execute_command and include command-execution guidance.
This is not limited to execute_command. Other examples include:
- Orchestrator has no tool groups, but the prompt recommends
list_files and refers to read_file.
- Ask does not have the
edit group, but the common capabilities text claims general file-writing and editing capabilities.
- Architect restricts edits to Markdown files, but the common capabilities text describes unrestricted writing and editing.
- MCP guidance can be included when no MCP tool or resource is effectively available.
- Instructions can require
skill, ask_followup_question, attempt_completion, new_task, or other control tools even when the corresponding tool has been removed through disabledTools or model-specific exclusions.
As a result, the model can receive instructions that it cannot follow. This can cause invalid tool attempts, retries, unnecessary token usage, and an increased mistake count. Runtime validation generally prevents a disallowed tool from executing, so this report is about prompt/tool-policy consistency rather than a confirmed permission bypass.
To Reproduce
Steps to reproduce the behavior:
- Select the built-in Architect, Ask, or Orchestrator mode, or create a custom mode without the
command group.
- Start a task so that the system prompt and native tool definitions are generated.
- Inspect the effective native tools sent for the active mode and confirm that
execute_command is not logically allowed.
- Inspect the generated system prompt.
- Observe that the capabilities and rules sections still say that commands can be executed with
execute_command and include terminal-specific instructions.
Additional variants:
- Use Orchestrator mode and observe that the prompt recommends
list_files even though the mode has no read group.
- Use Ask mode and observe that the common capabilities section claims file-writing/editing capability even though the mode has no
edit group.
- In Code or Debug mode, disable
execute_command through disabledTools and observe that command instructions remain in the prompt.
- Disable an otherwise always-available tool such as
skill or attempt_completion and observe that the prompt can still require its use.
- Connect an MCP server for which no tool is enabled for the prompt and no accessible resource exists; MCP guidance can still be generated based on server presence rather than effective tool availability.
Expected behavior
System-owned prompt text should only advertise or require a tool when that tool is present in the final logical tool-availability set for the request.
The same effective tool policy should be shared by:
- system prompt generation;
- API tool-definition construction;
- runtime tool-use validation; and
- system-prompt preview generation.
The effective set should account for mode groups, custom modes, disabledTools, model-specific included/excluded tools, feature flags, experiment state, MCP allowlists, enabled MCP tools, and accessible MCP resources.
Screenshots
Not applicable. The mismatch is visible by comparing the generated system prompt with the effective tool definitions for the same request.
Video
Not applicable.
What version of zoo are you running
3.76.0
Additional context
Relevant implementation paths
- Tool groups and always-available tools are defined in
src/shared/tools.ts.
- Built-in mode groups are defined in
packages/types/src/mode.ts.
- Effective native-tool filtering is performed in
src/core/prompts/tools/filter-tools-for-mode.ts.
- Native and dynamic MCP tool definitions are assembled in
src/core/task/build-tools.ts.
- The common prompt sections are assembled unconditionally in
src/core/prompts/system.ts.
- Static capability claims are in
src/core/prompts/sections/capabilities.ts.
- Static command, list, read, MCP, and control-tool instructions are spread across
src/core/prompts/sections/rules.ts, tool-use-guidelines.ts, system-info.ts, objective.ts, and skills.ts.
- Runtime system-prompt generation and API tool construction occur at different points in
src/core/task/Task.ts.
- Preview generation follows a separate path in
src/core/webview/generateSystemPrompt.ts.
Existing Architect and Ask prompt snapshots include the stale execute_command text, so the snapshots currently approve the inconsistent output instead of detecting it.
Root cause
Tool availability and prompt generation use separate sources of truth. The API tool path computes a filtered set, but prompt sections do not receive that final set and instead emit mostly static capability and rule text.
Checking only whether the mode has a particular group would fix the simplest built-in-mode cases but would remain incorrect when a tool is removed by disabledTools, model customization, feature flags, or MCP availability rules.
Suggested direction
Resolve one request-scoped effective tool policy before generating the system prompt. Pass its normalized logical tool-name set to prompt generation, API metadata construction, preview generation, and runtime validation.
The logical allowed set must remain separate from the tool definitions physically sent to a provider. This is particularly important for Gemini, where all tool declarations may be sent for conversation-history compatibility even though only a subset is logically permitted.
Prompt sections should then be composed from tool-specific fragments. For example:
- Include terminal and command guidance only when
execute_command is logically available.
- Recommend directory listing only when
list_files is available.
- Describe read, search, and edit capabilities using the specific available tools and active file restrictions.
- Include MCP guidance only when at least one MCP operation is effectively available.
- Include mandatory
skill, follow-up, completion, delegation, mode-switching, or todo instructions only when the respective control tool is available.
Protocol-critical tools need an explicit product decision. With the current task loop, attempt_completion is part of the completion protocol rather than an ordinary optional capability. A low-risk approach would be to make such lifecycle tools non-disableable and to prevent mode-essential tools such as Orchestrator's new_task from being disabled while that mode is active. Fully supporting their removal would require plain-text completion/question fallbacks in the task state machine, not only prompt changes.
User-authored custom instructions should not be silently rewritten. If they reference unavailable tools, a preview-time diagnostic would be safer than altering their content. Built-in instructions, however, should always follow the effective policy.
Suggested acceptance criteria
- Code and Debug include command guidance when
execute_command is available.
- Architect, Ask, and Orchestrator do not mention
execute_command by default.
- Orchestrator does not advertise read, list, or edit capabilities it does not have.
- Ask does not advertise editing capabilities.
- Architect's prompt reflects its Markdown-only edit restriction.
- Disabling or model-excluding an individual tool removes system-owned instructions that advertise or require it.
- MCP text depends on effective MCP operations, not merely on the presence of a connected server.
- No prompt requires a tool when the effective allowed-tool set is empty.
- Gemini may receive compatibility tool declarations, but its prompt and runtime validator use the logical allowed set.
- Runtime and preview generation produce the same effective-tool-dependent prompt sections.
- Focused mode-by-tool and disabled-tool assertions cover the behavior; snapshots are supplementary rather than the only verification.
Describe the bug
The generated system prompt contains instructions for tools that are not available to the model after mode and tool filtering.
For example,
execute_commandis only part of thecommandtool group, so it is available in the built-in Code and Debug modes but not in Architect, Ask, or Orchestrator. Despite that, the common capabilities and rules sections tell every mode that it can useexecute_commandand include command-execution guidance.This is not limited to
execute_command. Other examples include:list_filesand refers toread_file.editgroup, but the common capabilities text claims general file-writing and editing capabilities.skill,ask_followup_question,attempt_completion,new_task, or other control tools even when the corresponding tool has been removed throughdisabledToolsor model-specific exclusions.As a result, the model can receive instructions that it cannot follow. This can cause invalid tool attempts, retries, unnecessary token usage, and an increased mistake count. Runtime validation generally prevents a disallowed tool from executing, so this report is about prompt/tool-policy consistency rather than a confirmed permission bypass.
To Reproduce
Steps to reproduce the behavior:
commandgroup.execute_commandis not logically allowed.execute_commandand include terminal-specific instructions.Additional variants:
list_fileseven though the mode has noreadgroup.editgroup.execute_commandthroughdisabledToolsand observe that command instructions remain in the prompt.skillorattempt_completionand observe that the prompt can still require its use.Expected behavior
System-owned prompt text should only advertise or require a tool when that tool is present in the final logical tool-availability set for the request.
The same effective tool policy should be shared by:
The effective set should account for mode groups, custom modes,
disabledTools, model-specific included/excluded tools, feature flags, experiment state, MCP allowlists, enabled MCP tools, and accessible MCP resources.Screenshots
Not applicable. The mismatch is visible by comparing the generated system prompt with the effective tool definitions for the same request.
Video
Not applicable.
What version of zoo are you running
3.76.0
Additional context
Relevant implementation paths
src/shared/tools.ts.packages/types/src/mode.ts.src/core/prompts/tools/filter-tools-for-mode.ts.src/core/task/build-tools.ts.src/core/prompts/system.ts.src/core/prompts/sections/capabilities.ts.src/core/prompts/sections/rules.ts,tool-use-guidelines.ts,system-info.ts,objective.ts, andskills.ts.src/core/task/Task.ts.src/core/webview/generateSystemPrompt.ts.Existing Architect and Ask prompt snapshots include the stale
execute_commandtext, so the snapshots currently approve the inconsistent output instead of detecting it.Root cause
Tool availability and prompt generation use separate sources of truth. The API tool path computes a filtered set, but prompt sections do not receive that final set and instead emit mostly static capability and rule text.
Checking only whether the mode has a particular group would fix the simplest built-in-mode cases but would remain incorrect when a tool is removed by
disabledTools, model customization, feature flags, or MCP availability rules.Suggested direction
Resolve one request-scoped effective tool policy before generating the system prompt. Pass its normalized logical tool-name set to prompt generation, API metadata construction, preview generation, and runtime validation.
The logical allowed set must remain separate from the tool definitions physically sent to a provider. This is particularly important for Gemini, where all tool declarations may be sent for conversation-history compatibility even though only a subset is logically permitted.
Prompt sections should then be composed from tool-specific fragments. For example:
execute_commandis logically available.list_filesis available.skill, follow-up, completion, delegation, mode-switching, or todo instructions only when the respective control tool is available.Protocol-critical tools need an explicit product decision. With the current task loop,
attempt_completionis part of the completion protocol rather than an ordinary optional capability. A low-risk approach would be to make such lifecycle tools non-disableable and to prevent mode-essential tools such as Orchestrator'snew_taskfrom being disabled while that mode is active. Fully supporting their removal would require plain-text completion/question fallbacks in the task state machine, not only prompt changes.User-authored custom instructions should not be silently rewritten. If they reference unavailable tools, a preview-time diagnostic would be safer than altering their content. Built-in instructions, however, should always follow the effective policy.
Suggested acceptance criteria
execute_commandis available.execute_commandby default.