Layered configuration for governance, shell policy, hooks, and MCP permissions. Schema source: crates/castellan-governance/src/config.rs.
Layer Path Precedence
User ~/.castellan/config.tomllowest
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
backendjson | sqliteDurable store backend (default: json)
pathstring SQLite database path when backend = "sqlite" (default: .castellan/castellan.db)
mirror_jsonbool Also write .castellan/episodes/*.json alongside SQL (default: true)
auto_importbool Import existing JSON corpus on first SQLite open (default: true)
checkpoint_interval_ticksinteger Persist mid-episode checkpoints every N scheduler ticks (default: 0 = episode-end only)
See Memory architecture .
Key Type Description
session_spend_cap_usdfloat Session spend ceiling
max_risk_scorefloat Risk score threshold
denied_pathsstring[] Paths blocked for tool/file access
[governance.plan_verify]table Opt-in Guardians-shaped prove-before-execute (default off)
Key Type Description
enabledbool Require verified workflow_plan for high-risk tools (default false)
high_risk_toolsstring[] Tools that need a certificate (default shell, exec)
allowlisted_toolsstring[] Tools permitted inside a workflow plan
taint_edgesarray Optional { source_ref_prefix, forbidden_sink_tools } constraints
policy_pathstring Optional TOML file overriding allowlists / taint
See Agent hooks — prove-before-execute .
Key Type Description
allowed_commandsstring[] Allowlist for shell plugin
denied_commandsstring[] Blocked command names
denied_patternsstring[] Regex patterns to block
max_output_bytesinteger Cap captured stdout/stderr
Key Type Description
presetcautious | balanced | permissiveApproval preset expanded into a base policy
default_modeallow | ask | denyDefault 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.
Fast-slow co-evolution flywheel. See Evolution .
Key Type Description
fast_remediationbool Deposit pheromone hints from failed episodes after each run (default: true)
slow_evolve_everyinteger Run in-tree castellan evolve every N episodes (0 = off, default)
slow_evolve_generationsinteger Generations per slow evolve pass (default: 2)
Key Type Description
providerstring Optional LLM provider: openrouter, openai, ollama, or openai_compatible
base_urlstring OpenAI-compatible API root; defaults by provider (openrouter → https://openrouter.ai/api/v1)
http_refererstring Optional HTTP-Referer header (OpenRouter attribution; Castellan default when provider = "openrouter")
x_titlestring Optional X-Title header (OpenRouter attribution; default Castellan)
defaultstring Fallback model id for all roles (default: mock)
verifystring Model for the verify client
actstring Model for the act client
planstring Model for the plan client
Per-role tiers resolve through one OpenAI-compatible client factory (scheduler never routes through an LLM). Auth is env-only — never put API keys in TOML:
Provider API key env (first wins)
openrouterOPENROUTER_API_KEY, then CASTELLAN_LLM_API_KEY, then OPENAI_API_KEY
openai / openai_compatibleOPENAI_API_KEY or CASTELLAN_LLM_API_KEY
ollamaoptional (CASTELLAN_LLM_API_KEY / OPENAI_API_KEY); local default URL from OLLAMA_URL + /v1
[models]
provider = "openrouter"
default = "openai/gpt-4o-mini"
verify = "anthropic/claude-sonnet-4"
act = "openai/gpt-4o"
# optional overrides:
# base_url = "https://openrouter.ai/api/v1"
# http_referer = "https://github.com/Alphabetsoup16/Flock"
# x_title = "Castellan"
--model / --model-tier on castellan run still override; rebuild CLI with --features llm-http for live HTTP providers.
Key Type Description
namestring Recipe identifier for castellan recipes run <name>
descriptionstring Shown by castellan recipes list
commandstring Shell command executed via sh -c
cwdstring 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
eventstring Hook event name
commandstring Shell command to invoke
See Agent hooks .
Variable Maps to
CASTELLAN_SESSION_SPEND_CAP_USDgovernance.session_spend_cap_usd
CASTELLAN_MAX_RISK_SCOREgovernance.max_risk_score
CASTELLAN_SHELL_ALLOWEDCSV → shell.allowed_commands
CASTELLAN_SHELL_DENIEDCSV → shell.denied_commands
CASTELLAN_DENIED_PATHSCSV → governance.denied_paths
CASTELLAN_PERMISSION_MODEpermissions.default_mode
CASTELLAN_PERMISSION_PROMPTHeadless Prompt resolution: allow | deny (default deny when non-TTY). Legacy shim: FLOCK_PERMISSION_PROMPT
CASTELLAN_MEMORY_BACKENDmemory.backend
CASTELLAN_MEMORY_DBmemory.path
CASTELLAN_MEMORY_MIRROR_JSONmemory.mirror_json
Full list: Environment variables .