Configuration¶
claude-toolbox provides opinionated defaults for permissions, statusline, hooks, and project settings.
How Configuration Works¶
Note
Claude Code settings are split between two project-scoped files:
.claude/settings.json— upstream-managed defaults, synced from this template (permissions baseline, env vars, model, plugins, statusline).claude/settings.local.json— your per-repo overrides, never synced (hooks, MCP server enables, additional permissions, personal preferences)
Use settings.local.json for personal settings. Template sync merges most settings, but replaces permissions.deny with the upstream secrets baseline and reports removed entries; permissions.allow remains union-merged. The guard protects both settings files from agent edits. A person can edit them directly, or enable the scoped disable_selfmod exception described below.
Permission Baselines¶
The permission guard separates secrets, destructive operations and changes to its own configuration. Its baseline allows ordinary logs, dependencies, build output and .env.example; projects can add their own restrictions. A settings allow entry cannot override a secrets deny.
The tables below are generated from klaude-plugin/scripts/guard/guard-rules.json with make generate-guard. Template sync replaces permissions.deny with the secrets projection; project additions belong in .claude/kk-guard.json. See template sync for dropped-entry reports and the sync_exclusions opt-out. Per-repo MCP tool permissions go in settings.local.json.
Self-modification protection also blocks an agent from adding an allow entry to .claude/settings.json or .claude/settings.local.json. The disable_selfmod example below lets the user authorize those edits for a chosen project; it does not loosen secrets.
Secrets¶
These globs generate the Claude settings deny list and apply in the guard. Add project globs in .claude/kk-guard.json under secrets; user exceptions never loosen secrets.
| Scope | Glob |
|---|---|
| Project | ./**/*.pem |
| Project | ./**/*.tfstate |
| Project | ./**/*.tfstate.backup |
| Project | ./**/.env |
| Project | ./**/.env.*.local |
| Project | ./**/.env.local |
| Project | ./**/.terraform/** |
| Project | ./**/id_ecdsa |
| Project | ./**/id_ed25519 |
| Project | ./**/id_rsa |
| Project | ./**/service-account*.json |
| Home | ~/.aws/** |
| Home | ~/.claude/.credentials.json |
| Home | ~/.config/gcloud/** |
| Home | ~/.docker/config.json |
| Home | ~/.gnupg/** |
| Home | ~/.kube/** |
| Home | ~/.netrc |
| Home | ~/.pypirc |
| Home | ~/.ssh/** |
Destructive commands¶
Add rules in project config under destructive. User config at ~/.claude/kk-guard.json can disable categories or exempt individual commands with allow_patterns. Native Codex forbids take precedence over those exceptions.
| Category | Command | Denied operation | Codex forbid |
|---|---|---|---|
| filesystem | rm | rm deletes files and directories with no undo | Yes |
| filesystem | shred | shred overwrites file contents before deleting them | Yes |
| filesystem | find | find -delete removes every file the search matches | No |
| filesystem | rsync | rsync --delete (and its --del alias) removes destination files missing from the source | No |
| git | git clean | git clean deletes untracked files, which are not recoverable from git | No |
| git | git reset | git reset --hard discards every uncommitted change | No |
| git | git checkout | git checkout -- <path> and git checkout . discard uncommitted edits | No |
| git | git restore | git restore without --staged discards uncommitted edits in the working tree | No |
| git | git restore | git restore --worktree discards uncommitted edits in the working tree even alongside --staged | No |
| git | git branch | git branch -D deletes a branch even when it is not merged | No |
| git | git branch | git branch --delete --force (also -d -f and -df) deletes a branch even when it is not merged | No |
| git | git push | force pushes and remote deletes rewrite or remove history that may exist only on the remote | No |
| git | git stash drop | git stash drop discards stashed work that git cannot recover | No |
| git | git stash clear | git stash clear discards every stash entry | No |
| infra | terraform destroy | terraform destroy tears down live infrastructure | No |
| infra | terraform apply | terraform apply -destroy tears down live infrastructure | No |
| infra | kubectl delete | kubectl delete removes live cluster resources | No |
| infra | helm uninstall | helm uninstall removes a live release and its resources | No |
| infra | helm delete | helm delete removes a live release and its resources | No |
| infra | docker rm | docker rm removes containers and their writable layers | No |
| infra | docker rmi | docker rmi removes images | No |
| infra | docker container rm | docker container rm removes containers and their writable layers | No |
| infra | docker image rm | docker image rm removes images | No |
| infra | docker system prune | docker system prune removes every unused container, network and image | No |
| infra | docker volume rm | docker volume rm deletes persistent data volumes | No |
| infra | docker volume prune | docker volume prune deletes every unused data volume | No |
| privilege | sudo | sudo runs a command as the administrator | Yes |
| privilege | su | su switches to another user account | Yes |
| privilege | doas | doas runs a command as another user | Yes |
The hook exempts literal rm targets strictly beneath its temporary roots: /tmp, /private/tmp, /var/folders, /private/var/folders, $TMPDIR. Secrets and protected configuration still apply. Codex native rules forbid rm even for temporary targets.
Protected configuration¶
The guard blocks mutations of these paths, including moving their parent directories:
.claude/settings.json.claude/settings.local.json.claude/kk-guard.json~/.claude/settings.json~/.claude/settings.local.json~/.claude/kk-guard.json.codex/hooks.json.codex/rules/**.codex/scripts/**~/.claude/plugins/**
Project config may add paths under selfmod. To let an agent edit settings or guard files for one checkout, the user can add this entry to ~/.claude/kk-guard.json (substitute the absolute project path):
This exception does not allow reading or writing secrets.
Guard Configuration¶
The baseline ships inside the Claude plugin and runs even when neither configuration file exists. The Codex template carries the same engine and declaration. These files are independent of provider permission settings:
| File | Owner and purpose |
|---|---|
<project>/.claude/kk-guard.json | Committed project restrictions; adds secrets globs, destructive rules or protected paths |
~/.claude/kk-guard.json | Machine owner's exceptions; loosens destructive categories or self-modification protection for selected projects |
Project restrictions¶
Project configuration only adds protection. For example:
{
"version": 1,
"secrets": ["./**/local-secrets.json"],
"selfmod": [".project-policy.json"],
"destructive": {
"deployment": [
{"program": "deploy", "subcommand": "prod", "reason": "deploy prod changes production"}
]
}
}
Secrets globs use ./**/ for project paths, ~/ for home paths, or // for absolute paths. They match requested and resolved paths. Project-relative policy stays anchored to the project root even when a shell runs in a subdirectory. Destructive rules use program, optional ordered subcommand, argument regex lists flags_any/flags_all/flags_none, and a reason; use the shipped declaration as the complete rule reference. The only supported named exemption is targets_under_tmp. Project config cannot disable categories or remove baseline rules. Template sync leaves this project-owned file alone.
User exceptions¶
The user edits this file directly; the guard protects it from agent writes. Merge entries into an existing projects object rather than replacing other project entries. For example:
{
"version": 1,
"projects": {
"*": {"allow_patterns": ["^git clean -n"]},
"/absolute/path/to/ops": {"disable_categories": ["infra"]},
"/absolute/path/to/claude-toolbox": {"disable_selfmod": true}
}
}
Use physical absolute project paths (pwd -P). The engine combines * with the single longest matching directory prefix; shorter matching prefixes contribute nothing. Lists are combined, and disable_selfmod is enabled if either selected entry enables it. A parent path covers nested repositories and worktrees.
allow_patterns applies separately to each normalized simple command, including extracted shell bodies. Thus ^git clean -n can exempt git clean -nd, but not the rm in git clean -nd; rm -rf ./work. These patterns never exempt secrets or protected configuration. disable_selfmod permits settings/guard edits only; it also leaves secrets protected. On Codex, native forbids for rm, shred, sudo, su and doas still win over guard exceptions.
Missing config files leave the baseline active. Invalid JSON or invalid supported values produce a visible systemMessage and skip that file's changes; the other valid layer still applies. Unknown keys are reported and ignored. Secrets are never loosened by user configuration.
Hooks¶
The Claude plugin ships two hooks. It needs Bash, jq, Python 3.8+ and Claude Code 2.1.295+ for the declared onFailure: "block" behavior.
| Hook | Trigger | Description |
|---|---|---|
| Plugin root export | SessionStart | Exports TOOLBOX_PLUGIN_ROOT into the session environment so every Bash call has a reliable path to the plugin installation directory |
| Permission guard | PreToolUse on Bash, Read, Grep, Glob, Edit, Write, NotebookEdit, and capy execution tools | Enforces secrets, destructive-command rules, and protected configuration paths; denies on guard failures |
Ordinary allowed calls produce no output and exit 0; invalid-config warnings may emit systemMessage. Denials emit JSON, a reason on stderr, and exit 2. Missing/broken interpreters, a corrupt declaration, crashes and malformed engine output deny the call. Claude also blocks hook failures/timeouts through onFailure: "block". A machine without a working Python interpreter blocks every matched tool, including reads, until repaired.
The wrapper runs the standard-library-only engine with -I -S, isolating Python environment/user-site settings and skipping unused site startup. On macOS it prefers Python at the standard Homebrew locations, then system Python; elsewhere it checks system Python first. PATH lookup remains the final fallback. Homebrew is not required.
Destructive operations are denied in every permission mode, including bypass mode. The reason names the matched category and the way through: the user runs the operation directly or configures an applicable exception. Disabling Claude hooks removes destructive and self-modification protection. Template users retain the native secrets settings baseline; plugin-only users have no such fallback.
The guard checks capy_execute, capy_execute_file, and capy_batch_execute even when capy is registered under a different MCP server name. Shell code uses the same checks as Bash; other languages use the existing literal-path and write-call scans. Every batch command is checked independently, and one denied command blocks the entire batch before execution.
For capy code, omitted cwd means the project root. Relative cwd overrides resolve from that root; absolute overrides select that directory. Each batch command starts in the selected directory. The capy_execute_file.path input stays project-root-relative regardless of where its processing code runs. These path parameters are literal paths, without shell-variable or tilde expansion.
Inspection is static: the guard does not execute submitted code or read the contents of an execute-file input. Paths assembled dynamically are outside its detection coverage, and non-shell mutation checks cover recognized literal write-call forms. Grep/Glob checks cover the search root, not every result's contents. Other execution tools need their own payload mapping. The Codex template supplies Bash, patch and capy adapters; see Codex limitations.
For shell paths, the guard retains possible directories after literal relative changes and checks existing matches of unquoted filename wildcards. Quoted or escaped wildcard characters remain literal. Interpreter checks decode common character escapes in literal paths while preserving raw strings. These checks inspect filenames and submitted text, without executing code or reading matched file contents.
Statusline¶
Rich statusline with model, context %, git branch, session duration, thinking mode, and rate limits.
Themes: Set CLAUDE_STATUSLINE_THEME to darcula, nord, or catppuccin, and CLAUDE_STATUSLINE_MODE to dark (default) or light to match your terminal background.
Recommended Settings¶
Tip
Configure via claude /config. The config file is usually at ~/.claude.json.
I can't recommend enough disabling auto-compact — I've seen many a time claude starting to compact conversations in the middle of a task, which produces very poor results for the remaining work it does after compacting.
Full /config settings
> /config
────────────────────────────────────────────────────────────
Configure Claude Code preferences
Auto-compact false
Show tips true
Reduce motion false
Thinking mode true
Prompt suggestions true
Rewind code (checkpoints) true
Verbose output false
Terminal progress bar true
Default permission mode Default
Respect .gitignore in file picker true
Auto-update channel latest
Theme Dark mode
Notifications Auto
Output style default
Language Default (English)
Editor mode vim
Show code diff footer true
Show PR status footer true
Model opus
Auto-connect to IDE (external terminal) false
Claude in Chrome enabled by default false
Project Instructions¶
CLAUDE.md— project-specific instructions for Claude Code (checked into the repo).claude/CLAUDE.extra.md— behavioral instructions (independent thinking, fail-loud, assumptions)AGENTS.md— equivalent instructions for Codex