diff --git a/agents/AGENTS.md b/agents/AGENTS.md index 5ef48c3..0fcdae9 100644 --- a/agents/AGENTS.md +++ b/agents/AGENTS.md @@ -121,6 +121,20 @@ credentials or customer-personal data. - **Always run commands sandboxed first.** Only use `dangerouslyDisableSandbox: true` as a last resort after a sandbox-related failure — never preemptively. - **On sandbox failure:** analyze the error message for the blocked path, then suggest adding it to `sandbox.filesystem.allowWrite` in `~/.claude/settings.json`. Only fall back to `dangerouslyDisableSandbox: true` if the path can't be determined or the user prefers it. +- **Commands that must run unsandboxed belong in `sandbox.excludedCommands`** (e.g. `git *`, the pinned + `bin/srv`-style wrappers), not behind the flag: the exclusion is the owner's decision, the flag is the + model's. Without a hook, the flag is only a convention: an unsandboxed command that matches an allow + rule (`Bash(git *)`, `Bash(pytest *)` …) runs without a prompt in default mode, and auto mode may wave it + through as well. +- **Removed hook (2026-10-04, kept here for reference).** Until then a `PreToolUse` hook on `Bash` in + `~/.claude/settings.json` intercepted every call with `dangerouslyDisableSandbox: true` and forced a + permission prompt (`ask`); it was removed because an unattended overnight session would hang on that + prompt until morning. To reinstate it, add under `hooks.PreToolUse` (use `"deny"` instead of `"ask"` for + a hard block without a prompt): + ```json + {"matcher": "Bash", "hooks": [{"type": "command", "statusMessage": "Checking sandbox bypass...", + "command": "jq -e '.tool_input.dangerouslyDisableSandbox == true' > /dev/null 2>&1 && printf '{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"ask\",\"permissionDecisionReason\":\"Sandbox bypass requested. Retry with dangerouslyDisableSandbox omitted; set it only after a confirmed sandbox-caused failure.\"}}' || true"}]} + ``` ## Temporary Files