bypass-mode perms + deny list, drop allow-list plumbing

claude-settings.json now sets permissions.defaultMode=bypassPermissions
with a small deny list (WebFetch, WebSearch, Task, TodoWrite). The
per-flavor allow list and --tools / --allowedTools CLI flags are gone
— anything not denied auto-approves. mcp.rs loses ALLOWED_BUILTIN_TOOLS,
builtin_tools_arg, allow_list, allowed_mcp_tools. The extraMcpServers
allowedTools field is parsed for back-compat but no longer wired
anywhere; restrict via permissions.deny instead.
This commit is contained in:
müde 2026-05-16 15:17:30 +02:00
parent 3d2a7ffec7
commit 8e7405db13
3 changed files with 27 additions and 82 deletions

View file

@ -22,9 +22,13 @@ use crate::mcp;
/// to read and edit; we ship it via `include_str!`. We turn off claude's
/// in-session auto-compaction and its cross-session auto-memory because
/// hyperhive owns those concerns (`/compact` on overflow, notes
/// persistence under `/state`). Unknown keys are silently ignored by
/// claude-code; if a key gets renamed we'll spot it because the
/// corresponding behavior will start firing mid-turn again.
/// persistence under `/state`). `permissions.defaultMode =
/// bypassPermissions` skips the per-tool approval prompt entirely;
/// `permissions.deny` keeps a short list of tools we don't want claude
/// reaching for (web egress, nested agents, the ephemeral todo list).
/// Unknown keys are silently ignored by claude-code; if a key gets
/// renamed we'll spot it because the corresponding behavior will start
/// firing mid-turn again.
const CLAUDE_SETTINGS: &str = include_str!("../prompts/claude-settings.json");
/// Regex-ish marker claude-code emits when context overflows. Same string
@ -81,7 +85,10 @@ pub async fn write_mcp_config(socket: &Path) -> Result<PathBuf> {
/// Drop the static `--settings` JSON next to the MCP config so we can
/// pass a path (`--settings <file>`) instead of an ever-growing inline
/// blob — the CLI argv has a finite length budget.
/// blob — the CLI argv has a finite length budget. The file carries
/// `permissions.defaultMode = bypassPermissions` + a small `deny` list,
/// so everything not in `deny` auto-approves without a per-flavor allow
/// list.
pub async fn write_settings(socket: &Path) -> Result<PathBuf> {
let parent = socket.parent().unwrap_or_else(|| Path::new("/run/hive"));
tokio::fs::create_dir_all(parent).await.ok();
@ -247,11 +254,7 @@ async fn run_claude(prompt: &str, files: &TurnFiles, bus: &Bus) -> Result<bool>
cmd.arg("--system-prompt-file").arg(&files.system_prompt);
cmd.arg("--mcp-config")
.arg(&files.mcp_config)
.arg("--strict-mcp-config")
.arg("--tools")
.arg(mcp::builtin_tools_arg())
.arg("--allowedTools")
.arg(mcp::allowed_tools_arg(files.flavor));
.arg("--strict-mcp-config");
let mut child = cmd
.stdin(Stdio::piped())
.stdout(Stdio::piped())