Layered configuration for governance, shell policy, hooks, and MCP permissions. Schema source: crates/castellan-governance/src/config.rs.
| Layer | Path | Precedence |
| User | ~/.castellan/config.toml | lowest |
| Project | castellan.toml (walk up from cwd) | middle |
| Local | .castellan/local.toml (same repo as project castellan.toml) | highest |
Later layers override earlier ones. CLI flags and environment variables override all files.
[governance]
session_spend_cap_usd = 12.5
max_risk_score = 0.85
denied_paths = ["/secret", "~/.ssh"]
[shell]
allowed_commands = ["echo", "cargo", "git"]
denied_commands = ["rm", "curl"]
denied_patterns = ["sudo .*"]
max_output_bytes = 65536
[permissions]
default_mode = "ask"
[permissions.tools]
castellan_propose_mutation = "deny"
castellan_deposit_signal = "allow"
[[hooks.hooks]]
event = "PreToolUse"
command = "./scripts/hooks/pre-tool.sh"
| Key | Type | Description |
backend | json | sqlite | Durable store backend (default: json) |
path | string | SQLite database path when backend = "sqlite" (default: .castellan/castellan.db) |
mirror_json | bool | Also write .castellan/episodes/*.json alongside SQL (default: true) |
auto_import | bool | Import existing JSON corpus on first SQLite open (default: true) |
See Memory architecture.
| Key | Type | Description |
session_spend_cap_usd | float | Session spend ceiling |
max_risk_score | float | Risk score threshold |
denied_paths | string[] | Paths blocked for tool/file access |
| Key | Type | Description |
allowed_commands | string[] | Allowlist for shell plugin |
denied_commands | string[] | Blocked command names |
denied_patterns | string[] | Regex patterns to block |
max_output_bytes | integer | Cap captured stdout/stderr |
| Key | Type | Description |
preset | cautious | balanced | permissive | Approval preset expanded into a base policy |
default_mode | allow | ask | deny | Default MCP tool policy (overrides preset base) |
[permissions.tools] | map | Per-tool overrides |
Permission modes filter tools/list before exposure to MCP clients. castellan doctor reports the active preset.
| Key | Type | Description |
default | string | Fallback model spec for all roles (default: mock) |
verify | string | Model for the verify client |
act | string | Model for the act client |
plan | string | Model for the plan client |
Per-role tiers; the scheduler never routes through an LLM. --model-tier on castellan run selects a role at the CLI.
| Key | Type | Description |
name | string | Recipe identifier for castellan recipes run <name> |
description | string | Shown by castellan recipes list |
command | string | Shell command executed via sh -c |
cwd | string | Optional working directory |
Recipes inherit [shell] denied_commands / denied_patterns — they are not a policy bypass. Later config layers override recipes by name.
[[recipes]]
name = "gridworld-smoke"
description = "Run gridworld reach-target and write an episode JSON"
command = "castellan run --goal 'reach target' --plugin gridworld --json"
| Key | Type | Description |
event | string | Hook event name |
command | string | Shell command to invoke |
See Agent hooks.
| Variable | Maps to |
CASTELLAN_SESSION_SPEND_CAP_USD | governance.session_spend_cap_usd |
CASTELLAN_MAX_RISK_SCORE | governance.max_risk_score |
CASTELLAN_SHELL_ALLOWED | CSV → shell.allowed_commands |
CASTELLAN_SHELL_DENIED | CSV → shell.denied_commands |
CASTELLAN_DENIED_PATHS | CSV → governance.denied_paths |
CASTELLAN_PERMISSION_MODE | permissions.default_mode |
CASTELLAN_MEMORY_BACKEND | memory.backend |
CASTELLAN_MEMORY_DB | memory.path |
CASTELLAN_MEMORY_MIRROR_JSON | memory.mirror_json |
Full list: Environment variables.