Setting allow_shell = false still has issues:
allow_shell = false does not remove shell tools from the Constitution (system prompt)
Repo: Hmbown/CodeWhale
Area: prompt assembly / tool gating
Priority: medium
Reported: 2026-06-03
Summary
Setting allow_shell = false in config removes shell tools (exec_shell, exec_shell_wait, exec_shell_interact, task_shell_start, task_shell_wait) from the model-visible tool catalog, but the Constitution (system prompt, compiled from crates/tui/src/prompts/base.md / base.txt) unconditionally describes shell tools in the Toolbox section.
The model reads the Constitution, sees shell tools listed, attempts to call one, and gets "Tool 'exec_shell' is not available in the current tool catalog" — even with the improved error message from #2412.
Root Cause
The prompt assembly in crates/tui/src/prompts.rs uses include_str! to embed static .md/.txt files compiled into the binary:
tool taxonomy -> base.md -> personality overlay -> mode delta -> approval policy
base.md and base.txt contain an unconditional Toolbox section:
- **Shell**: `task_shell_start` + `task_shell_wait` for long-running commands,
diagnostics, tests, searches, and servers; `exec_shell` for bounded
cancellable foreground commands; `exec_shell_wait`, `exec_shell_interact`.
There is no conditional rendering in prompts.rs to strip or annotate this section based on session.allow_shell or the current mode.
The Gap
Tool availability is gated at two layers:
| Layer |
Conditionally respects allow_shell? |
| Tool catalog (tool registration) |
✅ Yes — tools are removed from catalog |
| Tool error messaging (PR #2412) |
✅ Yes — "not available" message explains why |
| Constitution / system prompt (Toolbox) |
❌ No — always describes shell tools |
The third layer is the problem. The model is led to believe shell tools exist, tries to use them, fails, and relies on the error message to recover. This wastes a turn, burns tokens, and creates a poor user experience.
Steps to Reproduce
-
Set allow_shell = false in config (either global [workspace.'/path'] or per-project overlay)
-
Start a session in Agent mode
-
Examine the system prompt — the Toolbox section lists exec_shell and related tools
-
Ask the model to run a shell command — it attempts exec_shell and gets:
Tool 'exec_shell' is not available in the current tool catalog. Shell tools are gated by allow_shell; enable allow_shell = true for trusted workspaces, or switch to an auto-approve mode that permits shell access. You can also use tool_search_tool_bm25 to discover tools.
Suggested Fix
Two approaches:
Approach A — Dynamic prompt assembly (preferred)
Replace the static include_str!("base.txt") with a function that renders the Toolbox section conditionally. prompts.rs already assembles the prompt from multiple layers — the Toolbox section should be generated in Rust code, not embedded as raw text:
fn render_toolbox_block(allow_shell: bool) -> String {
let mut tools = vec![
"- **Planning / tracking**: `checklist_write` ...",
"- **File I/O**: `read_file`, `list_dir`, ...",
"- **Structured search**: `grep_files`, `file_search`, ...",
];
if allow_shell {
tools.insert(2, "- **Shell**: `task_shell_start` + `task_shell_wait` ...");
}
tools.join("\n")
}
Approach B — Post-processing strip
Strip or comment out the shell line from base.txt after the full prompt is assembled, if allow_shell is false. Simpler but fragile — would break if the Toolbox section wording is edited.
Evidence
Related
Setting
allow_shell = falsestill has issues:allow_shell = false does not remove shell tools from the Constitution (system prompt)
Repo: Hmbown/CodeWhale
Area: prompt assembly / tool gating
Priority: medium
Reported: 2026-06-03
Summary
Setting
allow_shell = falsein config removes shell tools (exec_shell,exec_shell_wait,exec_shell_interact,task_shell_start,task_shell_wait) from the model-visible tool catalog, but the Constitution (system prompt, compiled fromcrates/tui/src/prompts/base.md/base.txt) unconditionally describes shell tools in the Toolbox section.The model reads the Constitution, sees shell tools listed, attempts to call one, and gets
"Tool 'exec_shell' is not available in the current tool catalog"— even with the improved error message from #2412.Root Cause
The prompt assembly in
crates/tui/src/prompts.rsusesinclude_str!to embed static.md/.txtfiles compiled into the binary:base.mdandbase.txtcontain an unconditional Toolbox section:There is no conditional rendering in
prompts.rsto strip or annotate this section based onsession.allow_shellor the current mode.The Gap
Tool availability is gated at two layers:
allow_shell?The third layer is the problem. The model is led to believe shell tools exist, tries to use them, fails, and relies on the error message to recover. This wastes a turn, burns tokens, and creates a poor user experience.
Steps to Reproduce
Set
allow_shell = falsein config (either global[workspace.'/path']or per-project overlay)Start a session in Agent mode
Examine the system prompt — the Toolbox section lists
exec_shelland related toolsAsk the model to run a shell command — it attempts
exec_shelland gets:Suggested Fix
Two approaches:
Approach A — Dynamic prompt assembly (preferred)
Replace the static
include_str!("base.txt")with a function that renders the Toolbox section conditionally.prompts.rsalready assembles the prompt from multiple layers — the Toolbox section should be generated in Rust code, not embedded as raw text:Approach B — Post-processing strip
Strip or comment out the shell line from
base.txtafter the full prompt is assembled, ifallow_shellis false. Simpler but fragile — would break if the Toolbox section wording is edited.Evidence
base.txt: https://github.com/Hmbown/CodeWhale/blob/main/crates/tui/src/prompts/base.txtbase.md(28KB): https://github.com/Hmbown/CodeWhale/blob/main/crates/tui/src/prompts/base.mdcrates/tui/src/prompts.rsSession.allow_shellfield:crates/tui/src/core/session.rsRelated
allow_shellconfig docs:docs/CONFIGURATION.md