Skip to content

Configuration

View Markdown~17,381 tokens

Settings go in caudra.toml. It has two places, and both are optional:

  • Global: ~/.config/caudra/caudra.toml
  • Project: .caudra/caudra.toml (relative to your working directory)

When both exist, project settings override global ones field by field. A few settings are global-only, and their descriptions say so. /reload reads both files again, except for the experimental switches, which apply from startup.

Settings apply in this order, and each layer overrides the ones before it:

  1. Built-in defaults
  2. Global caudra.toml
  3. Global init.lua, only with Lua plugins turned on
  4. Project .caudra/caudra.toml
  5. Project .caudra/init.lua, only with Lua plugins turned on
  6. Command-line flags

Remote sessions load only the client's global configuration. They skip both project layers, project environment files, and project MCP configuration. Remote project context uses a bounded declarative asset manifest instead. See Remote Workspaces.

caudra.toml holds the settings that only you write. A file stays separate from it when Caudra also writes the file, when the file decides where credentials or processes go, or when it has its own rules for trust, errors, or privacy.

FileScopeHoldsKept separate becauseReference
caudra.tomlglobal, projectsettings, and in the global file the [experimental] switchesIt is the main file, and only you write itcaudra config example caudra
permissions.tomlglobal, projectpermission rules for tools and MCP serversIt has its own error rule: a file that fails to load denies every tool callcaudra config example permissions
mcp.tomlglobal, projectMCP serversCaudra writes it when /mcp turns a server on or off, and it starts processescaudra config example mcp
providers.tomlglobalmodel providers and their modelscaudra auth login and caudra auth logout write it, and it can hold API keyscaudra config example providers
workcell.tomlglobalprofiles for direct remote Workcell connections (needs experimental.remote_workcell)It decides where credentials go, so it has to be a private filecaudra config example workcell
sandboxes.tomlglobalmanaged sandbox providers, networks, transfers, and profiles (needs experimental.sandboxes)The /sandbox manager writes it, and it has to be a private filecaudra config example sandboxes
init.luaglobal, projectLua code that sets up plugins (needs experimental.lua_plugins)It is a program, not settings-
.envglobal, projectenvironment variables, such as API keys, for any the environment does not setIt holds secrets-
commands/global, projectcustom slash commands, one Markdown file eachEach command is a file of its own-

caudra config files lists where each file lives on your machine and whether it is there. caudra config example FILE prints the reference of a TOML file, such as caudra config example mcp. See caudra config.

[ui]
splash_animation = true
mouse_scroll_lines = 5
theme = "tokyonight"
[ui.tool_output_lines]
bash = 8
read = 5
[agent]
max_output_lines = 3000
[provider]
default_model = "anthropic/claude-sonnet-4-6"
allowed_models = ["anthropic/*", "openai/gpt-5"]
excluded_models = ["*/*-preview"]
[storage]
max_log_files = 5
[plugins.bash]
timeout_secs = 180
[plugins.index]
max_file_size_mb = 4

All fields are optional. A file may start with version = 1, and a file without it counts as version 1. Typos in field names and values of the wrong type cause an error right away, with the file and line.

For every setting in one file, with its type, default, and description, see Reference configs or run caudra config example.

provider.allowed_models is a list of glob patterns for qualified provider/model-id specs. * also matches /, so opencode/* includes nested model IDs. When the list is empty or omitted, every model is allowed. provider.excluded_models removes matching models after that, so exclusions always win. A project list replaces the matching global list. Omit it to inherit, or use [] to clear it. The policy applies to selectors, CLI and API model changes, delegation, and caudra models.

Some features are experimental and stay off until you turn them on. Each one has its own switch in the [experimental] table of the global caudra.toml:

[experimental]
workflows = true
decision_engine = true
KeyDefaultTurns on
workflowsfalseWorkflows: the workflow tool, the workflow commands and inspector, and the caudra-workflow-dev skill.
sandboxesfalseManaged sandboxes: caudra sandbox, caudra auth sandbox, --sandbox, /sandbox, and the workbench Transfer view. Sandboxes bring their own connection to Workcell and do not need remote_workcell.
remote_workcellfalseDirect remote Workcell connections: the --workcell-* flags and caudra auth workcell.
lua_pluginsfalseEvery use of Lua: plugins, the Lua API, global and project init.lua, and the caudra-plugin-dev skill. --no-plugins still turns Lua off for one run.
decision_enginefalseThe decision engine, Auto mode, caudra decisions, and workflow decide() calls.
cross_session_messagingfalseLocal cross-session messaging: the list_sessions, send_message, publish_message, read_topic, and work_assignment tools, /peers, /messages, /topics, /groups, caudra message, live session inboxes, consumer groups, and the message history. Both processes must opt in.
automationsfalseAutomations: scripts that act on session events when their conditions hold, within the limits in [automations], and the caudra-automation-dev skill. Messaging triggers and actions also need cross_session_messaging, and workflow triggers and actions also need workflows.

Each switch is independent, so turning one on never turns on another. A missing file, table, or key leaves a switch off, and an unknown key is an error. caudra remote and /remote work when either sandboxes or remote_workcell is on, and each session checks the switch for its own source.

Only the global file may hold [experimental]. Caudra rejects a project .caudra/caudra.toml that contains the table, even an empty one, so a repository cannot opt you in. Lua, tool allowlists, and saved sessions cannot turn a feature on either.

Caudra reads the switches once at startup and keeps them until it exits. /reload, session switches, and ACP sessions all use the startup values. When the table changes on disk, Caudra shows a notice asking for a restart.

A feature that is off is hidden and does no work. Its tools, commands, shortcuts, help entries, and status chips are gone, and startup skips it. Asking for it directly, such as typing its command or passing its flag, fails with a message that names the switch. A saved session attached to a sandbox or a remote workspace does not resume while its switch is off, and it never falls back to local execution. Turning a feature off keeps its data and leaves external resources alone, so a running sandbox keeps running until you stop it.

With decision_engine off, always_auto = true and sessions saved in Auto start in Ask. Caudra keeps the saved choice, so Auto returns once the switch is on again.

Earlier releases read settings from init.lua through caudra.setup(). Caudra now runs init.lua only when lua_plugins is on. With Lua off, Caudra shows one notice that names each init.lua it skipped. It does not read, run, or change those files.

To migrate, move the table you passed to caudra.setup() into the caudra.toml of the same scope. Keys and values stay the same. Top-level values come first, and each nested table becomes a TOML table:

caudra.setup({
always_fast = true,
ui = { theme = "tokyonight" },
agent = { disabled_tools = { "websearch" } },
})
always_fast = true
[ui]
theme = "tokyonight"
[agent]
disabled_tools = ["websearch"]

Lists become arrays, and deeper tables become dotted headers such as [agent.steering.rules.repetition]. Quote a key that holds other characters, as in [agent.steering.models."openai/gpt-5"]. Leave out any key you set to nil.

To keep using init.lua, set lua_plugins = true under [experimental]. Its caudra.setup() values then apply on top of the caudra.toml of the same scope, in the order shown above.

FieldTypeDefaultDescription
always_yoloboolfalseStart every session with YOLO mode (skip permission prompts, deny rules still apply); global config only
always_autoboolfalseStart every session with Auto permission mode (preserve required prompts and screen unmatched calls); global config only. Needs experimental.decision_engine, otherwise sessions start in Ask
always_fastboolfalseStart every session with fast mode, on the models that sell a fast tier (ignored otherwise)
always_thinkingbool | stringunsetStart every session with extended thinking (true/"adaptive", "off", an effort level ("minimal" to "max"), or a token budget)
FieldTypeDefaultEnvMinDescription
splash_animationbooltrue--Show splash animation on startup
scrollbarbooltrue--Show vertical scrollbar in scrollable areas
touchstringauto--Touch-friendly pointer handling: auto, on, or off. Widens the scrollbar's hit zone so a finger can tap it, scrolls one line per wheel event instead of mouse_scroll_lines, and leaves text selection to the terminal. Auto detects Termux around Caudra itself, which SSH does not carry, so set this to on when reaching Caudra from a phone over SSH
notificationsstringauto--Terminal notification method: auto, osc9, bell, or off. Auto is off in a Herdr pane, where Herdr shows its own notification when Caudra is blocked or finished
mathstringunicode--How LaTeX maths renders: unicode (approximate with Unicode) or raw (show the LaTeX source)
mermaidstringunicode--How mermaid flowcharts render: unicode (draw them with box-drawing characters) or off (leave the fence as code)
flash_duration_msu6410000--Duration of ordinary status-bar messages (ms). Confirmation prompts use a fixed 3-second window
which_key_delay_msu64250--How long Ctrl+X waits before listing the chords it can still reach (ms). 0 shows the list at once
typewriter_ms_per_charu644--Typewriter effect speed (ms/char)
mouse_scroll_linesu323-1Lines per mouse wheel scroll
scroll_card_linesu3210--Rows of body a shell, python_execution or task card draws. The window follows new output while it sits at the bottom and pauses when scrolled up. Click inside a window to give it the wheel, which passes back to the transcript at either edge, and drag the bar in its last column to move it directly. 0 turns scrolling off, restoring the ui.tool_output_lines budget for those tools. A write is never windowed: it is drawn whole at any setting, as the file it created or as the diff of what it replaced
always_collapsedstring[]["file_read", "file_glob", "file_grep", "file_index", "webfetch"]--Tools whose card never opens on its own: the call stays a single row in every view mode until you click it. A server-qualified name still matches, so file_read also covers mcp_File_read. Set to [] to opt out
max_input_linesu3220-1Maximum visible input lines
show_thinkingbooltrue--Show full model reasoning live and persisted. Turn this off to start every reasoning block collapsed behind a Thinking or Thought header that can be clicked to expand
thinking_linesu3210--Rows of body an open reasoning block draws. The window follows the reasoning while it streams and pauses when scrolled up, and a footer reports how much sits above and below. Click inside a window to give it the wheel, which passes back to the transcript at either edge, and drag the bar in its last column to move it directly. Click the footer to follow again. A finished block rests on its last rows until you move it. 0 draws every block whole
show_remindersbooltrue--Show the messages Caudra writes into the conversation on your behalf: standing reminders, goal check-ins, nudges, and continuations. Each is one dim row that expands on click to the exact text the model was sent. Turn this off to keep the transcript to the conversation alone
clock_formatStringsystem--Clock format for timestamps: "12h", "24h", or "system" (follow the OS preference, 24h when unknown)
update_checkboolfalseCAUDRA_ENABLE_UPDATE_CHECK-Ask GitHub for the latest release on startup and show it in the splash. Off by default, so Caudra makes no such request unless you turn this on
themestringunset--Name of the color theme to load at startup, overriding the theme you last picked with /theme. Unset keeps your last pick
theme_lightstringunset--Light theme to pair with theme, in place of the one from the pairing table or for a theme that has no pair. theme becomes the dark half

Name of the color theme to load at startup, overriding the theme you last picked interactively. If unset, Caudra keeps your last selection, which starts out as caudra-dark. An unknown name is ignored with a warning.

Available themes: ayu_dark, ayu_light, ayu_mirage, carbonfox, catppuccin_frappe, catppuccin_latte, catppuccin_macchiato, catppuccin_mocha, caudra-dark, caudra-light, dark_daltonized, dracula, everforest_dark, fleet_dark, github_dark, gruvbox, gruvbox_light, kanagawa, kanagawa_ink, kanagawa_plum, material_darker, monokai_pro, night_owl, nightfox, nord, onedark, rose_pine, rose_pine_dawn, rose_pine_midnight, rose_pine_moon, solarized_dark, solarized_light, tokyonight, vscode_dark_plus, zenburn.

You can add your own themes too. Drop a <name>.toml file into themes/ inside your Caudra config directory, for example ~/.config/caudra/themes/. If it reuses a built-in name, yours wins.

Themes use 24-bit colors, but not every terminal can show them. Caudra checks the environment, terminfo, and the terminal itself, and when truecolor is missing it quietly falls back to the closest of the 256 classic terminal colors. If detection gets it wrong, set CAUDRA_TRUECOLOR=1 to force truecolor or CAUDRA_TRUECOLOR=0 to force the fallback.

Some themes ship as a light and dark pair: ayu_dark and ayu_light, catppuccin_mocha and catppuccin_latte, caudra-dark and caudra-light, gruvbox and gruvbox_light, rose_pine and rose_pine_dawn, solarized_dark and solarized_light. Choosing either half makes Caudra ask the terminal whether it is in light or dark mode and show the half that matches. Caudra changes halves as soon as the terminal reports a new mode, for example when your desktop switches to dark mode. A terminal that cannot report its mode is asked for its background color instead. Themes outside these pairs stay as you left them.

Caudra asks again every ten minutes, and also when the terminal regains focus or changes size, so reattaching a multiplexer to another terminal updates the theme. Following the terminal only changes the running session, and the theme you saved from /theme stays saved. A terminal that answers neither question is asked for its background color only a few times. After that, Caudra asks only whether it is in light or dark mode.

Mosh drops the request for mode reports before it reaches your terminal. Turn the reports on yourself when you connect, and off again when you leave:

Terminal window
printf '\033[?2031h'; mosh user@host; printf '\033[?2031l'

Light half to use in place of the one from the pairing table, or to give a theme that has no pair. ui.theme becomes the dark half:

[ui]
theme = "tokyonight"
theme_light = "catppuccin_latte"

Leave ui.theme unset to pair the light theme with whatever you last picked from /theme.

When on, Caudra asks the GitHub releases API for the latest version once at startup and shows it in the splash when yours is older. The request carries a caudra user agent and nothing else: no session id, no machine id, not even your current version.

It is off by default, so a normal run sends no update request. A normal run still contacts your model provider, fetches the public models.dev model catalog when the cached copy is more than a day old, and sends web searches to Exa when the agent uses websearch. Set CAUDRA_ENABLE_UPDATE_CHECK=1 to turn it on for a single run, or CAUDRA_ENABLE_UPDATE_CHECK=0 to turn it off when your config has it on. The caudra update command always checks, because that is what you asked it to do.

How many terminal rows of output an open card shows per tool before it says how many it is holding back. A line that wraps spends a row for each row it wraps to, so an abridged card is the same height whatever its lines are. Clicking the card shows all of it regardless. All values are usize with a minimum of 1.

The bash, python_execution, and task entries apply only when ui.scroll_card_lines is 0. Above that, those tools draw a fixed window of that many rows instead, and the budget here goes unused. write does not reach a file_write that created a file, whose body is that file and is always drawn whole. It is also a floor rather than a bound for anything drawn as a diff, since a diff is already only the part that changed: an edit, a patch, and an overwrite are drawn whole until they run long, and raising write past that point is what makes this number matter to them.

FieldDefaultTools
bash5shell
python_execution5python_execution
task12task, task_control
index3file_index, code_map, code_context, code_refs, code_impact, code_expand
grep3file_grep, file_glob
read3file_read
write7file_write, file_edit, file_apply_patch, image_generate, memory, plan
web3webfetch, websearch
other3automation, batch, execution_environment, list_sessions, publish_message, question, read_topic, send_message, skill, todo_write, tool_output, view_image, work_assignment, workflow
FieldTypeDefaultMinDescription
system_prompt_profileStringbuiltin-Default user system prompt profile from the system-prompts config directory
max_output_bytesusize512001024Host-enforced default max tool-result size (bytes)
max_output_linesusize200010Host-enforced default max tool-result lines
compaction_bufferu32 | string20%, or 10% when the model's window excludes output-Context reserved for compaction: token count or percent of the context window (e.g. "20%")
compaction_instructionsStringunset-Extra instructions appended to the compaction summary prompt
post_compaction_instructionsStringunset-Extra instructions the agent receives after any compaction (e.g. re-read plan.md)
compaction_requirementsbooltrue-Append a # User requirements section to every compaction summary: what the user asked for, constrained, and decided, read from their own messages and answered questions across every earlier compaction, and extracted by the Extract model so the conversation model never sees the request
background_reminder_turnsu320-Committed main-agent response groups between unchanged active background-work reminders; 0 disables periodic refresh only, not state-change or post-compaction reminders
todo_reminderbooltrue-Before the main agent hands control back with pending or in-progress todos and no background work running, remind it once per run, repeating the full todo list, to verify the work and update the list
task_executionstringauto-Task delivery: sync waits for the completed result, auto lets the model choose, async returns an admission receipt
shell_executionstringauto-Shell delivery: sync waits for termination, auto routes by requested timeout, async returns an admission receipt
shell_async_threshold_secsu641201Requested shell timeout above which auto delivery returns an admission receipt; independent of the enforced execution deadline
generate_titlesbooltrue-Name a new session by summarizing its first prompt with the Title model
stale_read_checkbooltrue-Block a write to a file that changed on disk since it was read, and point a failed edit or patch at the change
tool_json_repairbooltrue-Repair malformed tool JSON syntax locally, with one bounded isolated model fallback; independent of eager dispatch
eager_tool_dispatchbooltrue-Start tools and batch children as soon as their complete arguments arrive, instead of waiting for the whole message
shell_output_filterbooltrue-Filter completed model-facing shell output with built-in rules
shell_workdir_redirectbooltrue-Refuse shell commands with a leading literal cd ... && in favor of the shell workdir parameter. Set to false to disable this nudge independently of shell_native_redirect
shell_native_redirectstringenforce-What happens when a shell command only re-implements a native tool, such as bare rg or cat: enforce refuses it and names the tool to call instead, annotate only logs the finding, off disables the check. A command using any flag the native tool cannot express is never affected
defer_builtin_toolsstringauto-When the on-demand built-in tools start outside the request array: auto defers them for a small model or one with no supply metadata and declares them upfront for a known non-small model, always defers for every model, never declares them upfront
image_modelstringsunburst-GPT Image 2.5 model behind image_generate: sunburst is the most capable and the better editor, flare is faster at the same price
disabled_toolsstring[][]-Tools to withhold from the model: built-in names, server.tool, or server.* for a whole MCP server. A project list extends the global one
FieldTypeDefaultMinDescription
inboundstringauto-Inbound cross-session messages: auto accepts only compatible trusted peers, accept allows wider delivery, hold requires approval, refuse rejects messages. Project settings may only tighten policy: accept < auto < hold < refuse. Needs experimental.cross_session_messaging; accepting messages can start billable turns
inbound_per_minuteusize641Most peer messages a session admits per minute from all senders together. Project settings may only lower it
sender_per_minuteusize161Most peer messages a session admits per minute from one sending session. Project settings may only lower it
publish_per_minuteusize161Most topic and broadcast publications a session sends per minute. Project settings may only lower it
max_fanoutusize321Most live sessions one topic or broadcast publication reaches. Extra recipients are skipped and counted. Project settings may only lower it
history_daysu64301Days the shared message history keeps a message. The newest message on each topic outlives this until history_max_messages evicts it. Global config only
history_max_messagesu64500001Most messages the shared message history keeps; the oldest go first. Global config only

Automatic steering repairs unusable model output and can add bounded guidance about repeated behavior or needlessly long tool paths. Every rule is enabled by default. Configure overrides in the [agent.steering] table. All fields are optional.

FieldTypeDefaultMinMaxDescription
enabledbooleantrue--Master switch for automatic steering, including truncation recovery and repeat-policy blocking.
max_recoveriesinteger3201024Corrective continuations per externally initiated invocation. Zero prevents optional recovery continuations.
max_advisoriesinteger401024Advisory injections per invocation. Zero suppresses advisories.
max_stalled_turnsinteger501024Consecutive turns carrying neither a tool call nor visible text before the run ends, whichever rule intervened. Zero disables the backstop.
rulestable{}--Overrides by rule name, listed below. Omission uses built-in defaults.
modelstable{}--Up to 256 exact provider/model-id keys, each with its own overrides.
Rule in rulesBehavior
truncationContinue output cut off by the response token limit, up to 3 corrective requests per externally initiated invocation.
empty_responseContinue after empty output, with separate per-episode limits after recent tools and while idle.
repeated_tool_callRefuse the third consecutive identical top-level tool name/input before execution. Native batch children do not acquire this hard blocker.
protocol_mismatchCorrect an explicit provider tool-use indication with no actual tool calls, up to 2 continuations per episode.
missing_task_reportRequest a missing task summary or required structured report, up to 2 corrections.
abandoned_turnContinue a turn that ended by announcing work the response never performed, up to 2 continuations per episode. Spending the allowance accepts the text rather than failing the turn.
repetitionAdvise on short exact tool cycles, including normalized native batch leaf calls, or repeated normalized assistant text.
tool_planningAdvise after consecutive failed tool attempts across responses, including attempts with different tools or inputs. Any successful tool result ends the failure episode. Repeating a successful call is insufficient.
relative_pathsSuggest up to two shorter relative forms when file, patch, code-graph, or shell workdir paths spell out the working directory or its parent. The hint appears once per context.

Recovery and advisory budgets are separate. Advisory rules allow at most 4 total injections per invocation. Repetition and tool-planning advisories each wait a default cooldown of 3 completed model responses.

Tool-planning evidence starts after the last response containing any successful tool result, including results outside the retained batch window. A background admission ends the failure episode without proving that the background work succeeded. Later terminal outcomes do not retroactively change that admission into a failed attempt.

Relative-path evidence is the latest response only, and the hint yields to repetition and tool-planning advisories. While an earlier hint remains in context, even across user turns, no new hint is added. Once compaction removes it, another hint appears only if a later response uses absolute paths again. A suggestion climbs at most one directory with ../. Local sessions get suggestions only when the working directory the model sees is the canonical project path. Remote workspaces, sandboxes, and code-graph scopes get suggestions inside the working directory only. Paths with backticks, angle brackets, control characters, or invisible Unicode formatting characters are never quoted. Caudra never rewrites the paths a model sends.

An empty-response episode lives in the transcript tail, so it survives a restore and a new invocation. A message typed into a stall is answered, but it does not refill the budget: only a response carrying a tool call or visible text ends the episode. max_stalled_turns bounds the turns that interleaved rules spend between them, independently of any single rule's allowance.

Advisories only accompany an independently scheduled next request. They never reopen a valid final answer. Tool-looking prose, JSON, XML, code fences, and quoted examples do not independently trigger protocol correction. Caudra does not scrape tool names or arguments from text and execute them. Only actual tool calls pass through normal validation and authorization. Ordinary assistant answers do not have to be JSON.

Each table at agent.steering.rules.<rule> accepts these common fields:

FieldTypeDefaultDescription
enabledbooleantrueExplicit false disables this rule.
promptstringunsetUse built-in guidance when omitted. Custom text must be nonblank and at most 16,384 UTF-8 bytes.

Custom prompts replace guidance only. They are literal user-configured text, without template expansion or executable expressions. They do not change triggers, budgets, enforcement, or factual tool-failure information. A custom prompt cannot authorize a tool or turn a rejected call into an executed one.

The remaining fields are integers. All ranges are inclusive. Set enabled = false to disable a rule rather than setting a positive threshold to zero.

Field under rulesDefaultRangeUnit and meaning
truncation.max_attempts31–1024Actual truncation-correction requests per externally initiated invocation, shared across truncation episodes.
empty_response.max_after_tools31–1024Empty-output continuations per episode after recent tool results.
empty_response.max_idle21–1024Empty-output continuations per episode without recent tool results.
empty_response.max_barren11–1024Continuations per episode after a response that carried no content at all. Clamped by the limit above; repeating an unchanged request is not a retry.
empty_response.recent_tool_window51–4096Non-padding history messages inspected for recent tool results.
repeated_tool_call.threshold32–1024Consecutive identical top-level calls. Refuse the call reaching this threshold.
protocol_mismatch.max_attempts21–1024Protocol corrective continuations per episode.
missing_task_report.max_attempts21–1024Additional report-correction prompts per task invocation.
abandoned_turn.max_attempts21–1024Continuations per episode after a turn that announced work instead of doing it.
repetition.window241–4096Recent normalized leaf tool calls retained for cycle detection.
repetition.cycle_repeats32–1024Exact repetitions of a tool cycle needed for an advisory.
repetition.max_cycle42–1024Maximum cycle length in leaf calls. Candidate cycle lengths start at 2.
repetition.text_window81–4096Recent completed assistant responses retained for text repetition.
repetition.text_repeats32–1024Matching nontrivial normalized assistant responses needed for an advisory.
repetition.cooldown31–1024Completed model responses between this rule's advisories.
tool_planning.after_calls61–1024Number of most recent leaf tool calls that must all have failed since the last response containing a successful result.
tool_planning.after_responses31–1024Distinct completed model responses represented by those failed calls.
tool_planning.cooldown31–1024Completed model responses between this rule's advisories.
relative_paths.min_saved_chars121–1024Characters a relative form must save over its absolute path before the path is suggested.

Validation also requires:

  • repetition.window >= repetition.max_cycle * repetition.cycle_repeats.
  • repetition.text_window >= repetition.text_repeats.
  • tool_planning.after_calls >= tool_planning.after_responses.

Unknown fields, invalid types, out-of-range values, and impossible threshold/window combinations are rejected, even for disabled rules. Cooldowns count completed model responses, not seconds, stream chunks, tool children, or injected messages. Advisory eligibility excludes synthetic messages, empty markers, reasoning-only padding, and private title, compaction, or evaluator requests. Advisory evidence is the responses to the request in flight: a new user message ends it, as a compaction or a model change does, so an ordinary conversation is never advised. Recent-pattern windows reset with it, without refilling an active invocation's budgets.

Tool-planning guidance asks the model to reconsider its tool choices and identify the next useful action. It does not switch Plan Mode or require a todo list.

This example disables repetition guidance globally, then enables it with a higher threshold for one exact model and adjusts that model's tool-planning guidance:

[agent.steering.rules.repetition]
enabled = false
[agent.steering.models."openai/gpt-5".rules.repetition]
enabled = true
text_repeats = 4
[agent.steering.models."openai/gpt-5".rules.tool_planning]
after_calls = 8
prompt = "Reassess your recent tool choices. Choose a different useful action if these calls are not helping."

Model entries accept enabled, max_recoveries, max_advisories, max_stalled_turns, and rules with the same types and limits as the global fields. They cannot contain another models table. Omitted fields inherit through the resolution order below.

Keys are case-sensitive exact IDs, at most 512 UTF-8 bytes each. Use a nonempty provider and model suffix separated by /. Additional slashes inside the suffix are allowed, but every segment must be nonempty. Whitespace, control characters, *, ?, [, ], {, }, and backslashes are rejected. Matching requires no authentication or model discovery. There are no glob overrides, provider-wide layers, capability guesses from model names, or Lua detector callbacks.

Global and project settings merge field by field, with project values taking precedence. Model maps merge by exact key and rules merge by rule name and field. Omission inherits. Explicit false and 0 survive merging. An empty table does not clear inherited entries. Disable an inherited model policy or rule with enabled = false.

After merging, resolve against the effective routed model for Chat, Plan, or a delegated task:

  1. Start with built-in policy and rule defaults.
  2. Apply explicit global fields and rule fields.
  3. Apply explicit matching model fields and rule fields.

A child resolves its own effective model using the inherited unresolved configuration, rather than inheriting the parent's resolved policy or runtime counters.

A new externally initiated main-agent or task invocation gets its own allowance. An explicit user/caller resume starts a fresh bounded invocation. Automatic continuations, internal retries, task report-correction prompts, compaction, and mid-run queued instructions do not refill the active allowance, including when report correction constructs a fresh agent. Separately delegated children have independent allowances. Counters are not durable across process restarts or explicit task resume.

Charge one recovery for a completed-response-to-next-request transition caused by empty or truncated output, all-invalid tool calls, a response consisting entirely of repeat-policy refusals, an explicit protocol mismatch, or a missing task report. Corrective tool-error feedback can supply the guidance without a supplemental prompt and still consumes the transition. Malformed-argument and schema repair use this allowance without a separate rule table. Per-rule limits apply underneath the combined recovery cap.

A mixed batch with useful successful siblings proceeds normally. It is not replayed or charged once per child. Transport and authentication retries, ordinary tool execution failures, permission denials, normal successful tool progress, explicit goal evaluation, and manual steering are separate from model-format recovery. The recovery budget does not bound every possible agent loop. Outer turn limits and cancellation still apply.

At most one supplemental steering message is added per request. Recovery takes priority, then repetition, tool planning, and relative paths. Advisory exhaustion only suppresses hints. Recovery exhaustion with an unmet output contract reports a failure and retains partial output, except for abandoned_turn, which stops intervening and lets the turn end. A valid captured structured task report remains usable after an empty tail, but cancellation, transport/permission failures, and hard outer-limit failures do not become success.

abandoned_turn reads the tail of a response that called no tool and would otherwise end the turn. It fires on a text stopping at a bare colon, or on a last sentence that opens on an intent to act. It does not fire on a question, an offer, a completion, or a promise deferred behind another event, and code spans and quoted prose are removed before any of that is matched. Tool-looking prose is not executed here either; the rule only decides whether to ask for one more response.

The resolved enabled = false disables automatic recovery, including truncation, advisories, and repeat-policy blocking. It leaves malformed-input rejection, schema validation, permissions, mode restrictions, cancellation, explicit goals, manual steering, and compaction policy intact. A rule-level switch disables only that rule. Zero budgets prevent the corresponding continuations or hints without bypassing input validation or repeat-policy enforcement.

Truncation recovery counts corrective requests, not ordinary responses or tool rounds. Each request consumes one attempt from rules.truncation.max_attempts and one recovery from max_recoveries. Automatic report-correction prompts and compaction do not refill either allowance. The last allowed correction may complete the answer. If another correction is needed, exhaustion reports an error with partial output and usage retained, including when max_recoveries = 0.

Disabling the master switch or setting rules.truncation.enabled = false stops with the truncated outcome instead of requesting a continuation. Disabled or exhausted truncation does not fall through to empty-response repair, even when the truncated response is empty. An unresolved truncated task result remains cut short rather than reopening through report repair. A valid structured report can still satisfy the task's report contract. Cancellation, queued user instructions, and outer turn limits take priority over automatic steering.

FieldTypeDefaultMinDescription
default_modelStringunset-Default model identifier (e.g. anthropic/claude-sonnet-4-6)
allowed_modelsstring[][]-Glob patterns for permitted qualified model specs; empty permits all models
excluded_modelsstring[][]-Glob patterns for excluded qualified model specs; exclusions take precedence
connect_timeout_secsu64101HTTP connect timeout (seconds)
stream_timeout_secsu6430010Longest the server may send nothing before the request is abandoned (seconds)
FieldTypeDefaultEnvMinDescription
max_log_bytes_mbu64200-1Max total log size (MB)
max_log_filesu3210-1Max number of log files to keep
max_eager_load_mbu641024CAUDRA_MAX_EAGER_LOAD_MB64Largest session Caudra will hydrate when opening one (MB), counted in uncompressed payload bytes rather than disk or memory. A session past this refuses to load; trim it or raise this
log_levelstringinfo--Minimum severity written to the log file: trace, debug, info, warn, or error. RUST_LOG overrides it
input_history_sizeusize100-10Number of input history entries to retain
ephemeralboolfalse--Store session data in a temporary directory removed when Caudra exits
FieldTypeDefaultDescription
group_bystringdirectoryEvaluate policies per working directory (directory) or across every session (none)
sweep_interval_hoursu6424Hours between background sweeps. A sweep reclaims freed space, and applies trim and forget when they are set. 0 disables the sweep; caudra storage commands still work
trimtable{}Sessions outside this policy lose file revert, tool output files, archives, and large rich outputs but stay resumable. Empty means never trim automatically
forgettable{}Sessions outside this policy are deleted. Empty means never delete automatically

trim and forget are keep policies in restic forget terms: keep_last, keep_hourly, keep_daily, keep_weekly, keep_monthly, keep_yearly take a count, and keep_within plus keep_within_hourly through keep_within_yearly take a duration such as "90d" or "2y5m7d3h". A session is kept when any rule matches. An empty forget policy disables automatic deletion. See Sessions for what each tier keeps and how the sweep runs.

FieldTypeDefaultMinDescription
enabledbooltrue-Record each tool call's file changes so file revert can undo them, locally and remotely. false turns recording and file revert off and keeps records already made. --no-snapshots overrides this for one run
max_bytes_mbu645121Most file data one change record may cover, and the size each workspace's change store is trimmed to. A record over it is refused and its call runs unrecorded. Values above the store's limit are lowered to it, and locally that limit is the default
max_filesu64500001Most files one change record may cover, counted after ignore rules. A record over it is refused and its call runs unrecorded. Values above the store's limit are lowered to it, and locally that limit is the default
max_file_bytes_mbu641001Largest file a change record stores. A larger file is left unrecorded, and a file revert across a call that changed it stops with a conflict. Values above the store's limit are lowered to it, and locally that limit is the default

A change record that would cover more than max_files files or max_bytes_mb of file data is refused, and its call runs without a record. A file over max_file_bytes_mb is left unrecorded. Values above the store's limits are lowered to them, and zero is rejected. See Sessions for what a record covers.

FieldTypeDefaultEnvDescription
enabledboolfalseCAUDRA_ENABLE_TELEMETRYMaster switch
metrics_exporterstringnoneOTEL_METRICS_EXPORTERWhere metrics go: otlp, console, none, or a comma-separated mix
logs_exporterstringnoneOTEL_LOGS_EXPORTERWhere events go: otlp, console, none, or a comma-separated mix
protocolstringunsetOTEL_EXPORTER_OTLP_PROTOCOLOTLP protocol: grpc, http/protobuf, or http/json. Required when an exporter is otlp
endpointstringunsetOTEL_EXPORTER_OTLP_ENDPOINTCollector endpoint. HTTP appends /v1/metrics and /v1/logs
headerstable{}OTEL_EXPORTER_OTLP_HEADERSExtra headers sent with every export
timeout_msinteger10000OTEL_EXPORTER_OTLP_TIMEOUTPer-export request timeout (ms)
compressionstringnoneOTEL_EXPORTER_OTLP_COMPRESSIONPayload compression: gzip or none
metrics_protocolstringunsetOTEL_EXPORTER_OTLP_METRICS_PROTOCOLMetrics-only protocol override
metrics_endpointstringunsetOTEL_EXPORTER_OTLP_METRICS_ENDPOINTMetrics-only endpoint, used verbatim with no path appended
metrics_headerstable{}OTEL_EXPORTER_OTLP_METRICS_HEADERSMetrics-only headers, merged over headers
metrics_timeout_msintegerunsetOTEL_EXPORTER_OTLP_METRICS_TIMEOUTMetrics-only request timeout (ms)
logs_protocolstringunsetOTEL_EXPORTER_OTLP_LOGS_PROTOCOLLogs-only protocol override
logs_endpointstringunsetOTEL_EXPORTER_OTLP_LOGS_ENDPOINTLogs-only endpoint, used verbatim with no path appended
logs_headerstable{}OTEL_EXPORTER_OTLP_LOGS_HEADERSLogs-only headers, merged over headers
logs_timeout_msintegerunsetOTEL_EXPORTER_OTLP_LOGS_TIMEOUTLogs-only request timeout (ms)
metrics_interval_msinteger60000OTEL_METRIC_EXPORT_INTERVALHow often metrics are exported (ms)
metrics_export_timeout_msinteger30000OTEL_METRIC_EXPORT_TIMEOUTDeadline for one metrics export, retries included (ms)
logs_interval_msinteger5000OTEL_LOGS_EXPORT_INTERVAL, OTEL_BLRP_SCHEDULE_DELAYHow often queued events are flushed (ms)
logs_max_queue_sizeinteger2048OTEL_BLRP_MAX_QUEUE_SIZEEvent queue capacity. Events are dropped and counted when it is full
logs_max_export_batch_sizeinteger512OTEL_BLRP_MAX_EXPORT_BATCH_SIZEMaximum events per export request
logs_export_timeout_msinteger30000OTEL_BLRP_EXPORT_TIMEOUTDeadline for one events export, retries included (ms)
metrics_temporalitystringdeltaOTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCEMetric temporality: delta or cumulative
service_namestringcaudraOTEL_SERVICE_NAMEservice.name on the exported resource
resource_attributestable{}OTEL_RESOURCE_ATTRIBUTESExtra resource attributes, your place for team or environment labels
metrics_include_session_idbooltrueOTEL_METRICS_INCLUDE_SESSION_IDAttach session.id to metrics. Turn off to keep metric cardinality low
metrics_include_versionboolfalseOTEL_METRICS_INCLUDE_VERSIONAttach app.version to metrics
log_user_promptsboolfalseOTEL_LOG_USER_PROMPTSInclude prompt text in caudra.user_prompt events. Off by default
log_tool_detailsboolfalseOTEL_LOG_TOOL_DETAILSInclude tool input in caudra.tool_result events. Off by default
content_max_lengthinteger10240CAUDRA_OTEL_CONTENT_MAX_LENGTHCharacter cap on any logged prompt or tool input

Every field also has an environment variable, shown in the Env column, and the variable wins. See Telemetry for the full picture.

FieldTypeDefaultDescription
backendstringautoWhat creates and removes worktrees for /worktree: auto uses Herdr inside a Herdr pane and git elsewhere, git always runs git
directorystring<data dir>/worktreesWhere git-created worktrees go, as <directory>/<repository>/<branch>. A leading ~/ is your home directory

Inside a Herdr pane, auto asks Herdr to create and remove worktrees, so each one opens as a grouped Herdr workspace. directory applies only to worktrees git creates. See Worktrees for what /worktree does with each backend.

Configure the optional typed decision engine in the [decisions] table. The engine is experimental and needs decision_engine = true under [experimental]. Without that switch Caudra still validates this table and starts no engine. It then sends no decision requests, reads no engine credentials, and leaves decision logs and shell duration history untouched. No base URL, passive feature, or decision logging is enabled by default. Explicit workflow decide() calls need a base URL but do not need a passive feature enabled. Shell duration history can work without a base URL.

Connection settings and thresholds are global-only. Projects may set individual features to "off", set log = false, or keep or shorten inherited log retention. Other project overrides are errors, even when they repeat a global value. Disabling globally required Auto screening or its active content screening restores prompting for eligible Auto calls.

FieldTypeDefaultDescription
base_urlstringunsetDecision API base URL, such as https://api.typesafe.ai. Caudra appends /v1/systemone and keeps any path prefix. TYPESAFE_BASE_URL replaces a configured value. HTTPS required except for numeric loopback HTTP or explicit allow_http consent. No credentials, query, fragment, whitespace, or control characters.
modelstringjev-latestDecision model identifier, nonblank and without control characters.
api_key_envstringTYPESAFE_API_KEYEnvironment variable containing the optional credential, never the credential itself. Project environment values are excluded.
allow_remotebooleanfalseExplicit global consent to send decision context to a non-loopback endpoint.
allow_httpbooleanfalseGlobal-only opt-in for non-loopback HTTP. Also requires allow_remote = true. Use only with transport protection you control, such as a trusted encrypted tunnel.
timeout_msinteger800Positive decision-request deadline in milliseconds, separate from shell execution timeouts.
logbooleanfalseRetain bounded decision records in the local caudra.db.
log_retention_daysinteger90Positive retention period for decision records.
featurestable{}Per-feature modes below.
thresholdstable{}Probability thresholds, all finite and within 0–1 inclusive.

Caudra sends each request to base_url with /v1/systemone appended. A path prefix stays in place, so a server mounted under /typesafe uses base_url = "http://127.0.0.1:8080/typesafe" and receives requests at /typesafe/v1/systemone. Leave /v1/systemone out of base_url. The hosted API also needs remote consent:

[decisions]
base_url = "https://api.typesafe.ai"
allow_remote = true

TYPESAFE_BASE_URL replaces the whole configured base URL, path prefix included, and passes the same URL and transport opt-in checks. It applies only when base_url is set, so the variable alone never activates the engine. Project .env files cannot set it.

Caudra retries HTTP 408, 429, and 5xx responses at most twice. Each retry waits for the delay the server requests in retry-after-ms or Retry-After, or else for an exponential backoff that starts near half a second. No retry waits past timeout_ms, so under the default 800 ms deadline most retries need a short server-requested delay. Connection failures, 401, 422, and other client errors fail at once.

Requests ignore ambient proxies and do not follow redirects. localhost is a DNS name, not numeric loopback for this policy. Private and CGNAT addresses receive no automatic HTTP exemption. These settings do not change Workcell transport policy.

Redaction is best effort. Decision context can include commands, task text, tool output, and candidate descriptions. Review what you send and any exports before sharing them. See decision advice and logging.

off disables the feature. shadow collects predictions without applying them. advise adds caution or suggestions. enforce applies only the feature-specific behavior listed below, never permission grants or relaxed executor restrictions. Unsupported modes are configuration errors. Passive features are suppressed in YOLO.

FeatureDefaultSupported modesBehavior beyond shadow
permission_adviceoffoff, shadow, adviseAdd warnings to an existing permission prompt without delaying the answer.
auto_screeningoffoff, shadow, enforceEscalate an eligible Auto call to a prompt on a flag or engine failure. Only enforce lets Auto run scripts and other lines that cannot be checked command by command. No answer channel means denial.
shell_effectoffoff, shadow, adviseWarn about possible project writes during Plan review only when shell_writes is configured. Never establish read-only authority.
content_screeningoffoff, shadow, adviseAdd caution to flagged web/MCP output and tighten upload/credential Auto screening for the session. Content remains available.
shell_durationoffoff, shadow, advise, enforceAdvise with local shell estimates. Enforce may fill an omitted timeout and select delivery at admission. Explicit timeouts stay unchanged. See shell duration.
tool_searchoffoff, shadow, enforceRerank the existing lexical tool shortlist. This neither loads arbitrary names nor grants execution permission.
skill_suggestionsoffoff, shadow, adviseSuggest a shortlisted skill. The agent still chooses whether to load it.
goal_prescreenoffoff, shadow, enforceSkip an unlikely-to-pass goal evaluation within the continuation budget and continue work. Only the normal evaluator can certify completion.
subagent_routingoffoff, shadow, enforceChoose a model job for a new unpinned subagent from its task label, mode, profile, and a redacted prompt excerpt. Explicit jobs, profile pins, and continuations keep their routing.

Flag thresholds trigger at or above the configured value. Goal prescreening uses an at-or-below comparison. Content screening requires both signals in a sampled chunk. After content is flagged, Auto uses 75% of auto_flag for upload and credential flags.

FieldTypeDefaultDescription
permission_flagfloat0.85Probability for a permission warning.
auto_flagfloat0.85Probability for escalating an eligible Auto call.
content_injectionfloat0.9Probability that sampled content attempts instruction injection.
content_addressed_to_agentfloat0.9Probability that sampled content addresses the agent.
shell_endlessfloat0.9Probability that a shell command runs until stopped.
shell_durationfloat0.9Probability mass a duration bound needs before an engine estimate is used.
routing_confidencefloat0.9Confidence required for tool search and skill suggestions. Tool-search choice probability must also meet it. Subagent routing picks the Fast model when this much difficulty probability is at or below routine work, and the Best model when this much is on open-ended work.
goal_skip_belowfloat0.05Skip an evaluator at or below this completion probability, within the continuation budget.
shell_writesfloatunsetOptional project-write warning threshold. Omission leaves the warning disabled. No built-in enforcement threshold.

shell_duration applies only to eligible local native shell calls, not remote workspaces or managed sandboxes. Measured exact-command history takes priority over command-family history, and both take priority over a model estimate. Timeouts, cancellations, and failures are recorded separately from completed latency samples. History is separate from the opt-in decision log, so log = false does not disable duration observations.

A model estimate scores a command on four levels: exits at once, runs for seconds, runs for minutes, or runs until stopped. It counts as running until stopped when the endless answer or the probability of that level reaches shell_endless. Otherwise the first of these bounds whose probability reaches shell_duration decides: at least minutes, at once, then at most seconds. With no bound reached, the call runs without an estimate.

Measured runs are labeled by fixed boundaries. A run within 1 second exited at once, a run under 120 seconds took seconds, and a longer run took minutes. These boundaries stay the same whatever agent.shell_async_threshold_secs is. When neither the command nor its family has enough history, the request lists up to four related families as earlier_runs, drawn from runs in the same project and working directory. The command's own family comes first, then families with the same program, each with how long its runs took.

In advise, estimates and warnings leave execution unchanged. In enforce, an omitted timeoutSec may receive a default based on 1.5 times estimated p90, bounded by the tool schema's default and maximum. An explicit timeout is never changed. An endless prediction gives caution only and does not remove the execution deadline.

With agent.shell_execution = "auto", Enforce estimates can select synchronous or asynchronous delivery at admission, bounded by the effective timeout and agent.shell_async_threshold_secs. Explicit sync/async settings still win. Elapsed runtime never promotes a synchronous call to asynchronous delivery. An admission receipt is not completion or success.

Only the permission question set currently supports a user-global file override: ~/.config/caudra/decisions/permission.json. It must be a regular JSON file no larger than 64 KiB, retain all required question IDs as noul, and pass question validation. It is read when a base URL is set and permission advice or Auto screening is enabled. Projects cannot supply this override. Other feature question sets have no file override.

FieldTypeDefaultMinMaxDescription
turns_per_houru32201600Most turns automations may start in one session per rolling hour, shared by all of its automations
max_unattended_turnsu32unset110000Stop automation-started turns after this many since the last human input. Human input resets the count, and unset means no cap
allow_private_networkboolfalse--Let http() in automations reach loopback and private network hosts. Without it, automations reach public hosts only

Automations are experimental and need automations = true under [experimental]. Only the global caudra.toml may hold this table. Caudra rejects a project .caudra/caudra.toml that contains it, even an empty one, so a repository cannot raise these limits or let automations reach a private network.

The plugins table turns bundled features and plugins on or off and passes options to them. All bundled features are on by default. Set enabled = false to turn one off.

Each feature checks its own options at startup. A typo, a wrong type, or an unknown plugin name gives you a clear error right away.

enabled = false turns off the tools that key produced, under the names they are registered with today, so plugins.bash turns off shell and plugins.edit turns off file_edit and file_apply_patch. To name a tool directly, use agent.disabled_tools, described in Disabling tools.

The edit plugin's extra tools are options too: plugins.edit = { multiedit = false, insert_lines = true }.

This table is for bundled plugins only, and it works without Lua. Your own plugins go in ~/.config/caudra/lua/ and need lua_plugins turned on. See Plugins.

[plugins.bash]
timeout_secs = 180
[plugins.websearch]
enabled = false

file_index executes as a native Workcell tool, and this table keeps the plugins.index key it was configured under. The file-size limit accepts 1 through 16 MiB to bound parser memory and work.

FieldTypeDefaultMinMaxDescription
max_file_size_mbinteger2116Refuse to index files larger than this many MiB.

skill executes as a native Caudra tool. This table keeps its existing configuration key.

FieldTypeDefaultDescription
plugin_devbooleanfalseOffer the builtin caudra-plugin-dev skill for writing caudra plugins. Needs experimental.lua_plugins.
workflow_devbooleantrueOffer the builtin caudra-workflow-dev skill for writing and running workflows. Needs experimental.workflows.
automation_devbooleantrueOffer the builtin caudra-automation-dev skill for writing automations. Needs experimental.automations.
docsbooleantrueOffer the builtin caudra-docs skill: this build's user documentation, loaded one page or section at a time.

task executes as a native Caudra tool. This table keeps its existing configuration key.

FieldTypeDefaultMinDescription
max_concurrentinteger81Max concurrently running subagents.

If a value is below its minimum or above its maximum, Caudra shows a ConfigError with the field name, the value, and the bound it crossed.

Caudra follows platform directory conventions. On Linux and macOS that is XDG. On Windows, config, data, state, and logs all live under Roaming AppData (Windows has no separate state dir in this layout).

PurposeLinux / macOSWindows
Config~/.config/caudra/%APPDATA%\caudra\
Data~/.local/share/caudra/%APPDATA%\caudra\
State~/.local/state/caudra/%APPDATA%\caudra\
Logs~/.local/logs/caudra/%APPDATA%\caudra\
Cache~/.cache/caudra/%LOCALAPPDATA%\caudra\
Scratch$TMPDIR/caudra/%TEMP%\caudra\

Config holds caudra.toml, permissions.toml, mcp.toml, providers.toml, workcell.toml, sandboxes.toml, init.lua, .env and commands/. State holds sessions, auth tokens, memories, plans, model-job bindings, sandbox lifecycle records and transfer recovery journals. The install script puts the binary under %LOCALAPPDATA%\caudra on Windows; that is separate from these runtime dirs.

Scratch holds work that belongs outside your project, such as a file the model writes while thinking or a temporary a command leaves behind. Each project gets its own subdirectory, named by the project directory plus a three-word phrase derived from its path, as in caudra-heroic-easy-grouse. Two checkouts sharing a name get different phrases, so they cannot overwrite each other. The phrase is derived rather than drawn at random, so a project returns to the same directory on every run. Caudra creates it at startup and points TMPDIR, TMP, and TEMP at it, so every command Caudra runs puts its own temporary files there instead of the shared temp root. The model is told the path, and writing anywhere under the scratch root needs no approval. Paths beside the root still ask.

The choice of subdirectory is fixed when Caudra starts. /cd moves the project without moving it, which is why approval covers the whole root rather than one project's share of it. Directories are owner-only, and Caudra refuses to use one that turns out to be a symlink. Nothing sweeps them, so they live as long as your system keeps its temp root.

State that belongs to one project sits under …/state/caudra/projects/<project-id>/, where the id is the project directory name plus a hash of its path. Memory notes and plan-mode documents both live there, so removing that directory clears everything Caudra kept for the project.

Development builds compiled with debug assertions use caudra-debug for every platform directory. This keeps global config, sessions, auth, logs, and caches separate from release builds. Per-project .caudra/ directories remain shared.

Set CAUDRA_NAMESPACE to choose the directory name yourself instead of letting the build profile pick it. The value is a single directory name, so CAUDRA_NAMESPACE=caudra-review reads and writes ~/.config/caudra-review/, ~/.local/state/caudra-review/, and the rest. Use it to give a run its own config and session store, or to point a debug build at your release directories. A value that cannot be a directory name, such as one holding a path separator or .., stops Caudra with an error rather than falling back. An empty value counts as unset. Per-project .caudra/ directories are unaffected.

Each TOML config file takes a top-level version, and every format is at version 1. Where the key is optional, a file without it counts as version 1. A build that finds a newer version than it reads refuses the file instead of guessing what it means. For a file with an optional key, the error says the file needs a newer Caudra.

FileversionNewer than this build reads
caudra.tomlOptionalCaudra stops with an error
permissions.tomlOptionalFails closed. Tool calls are denied until the file is fixed
mcp.tomlOptionalServers from that file do not start, and Caudra shows the error
providers.tomlOptionalCaudra stops with an error
plugin.tomlOptionalEvery permission of that plugin is denied
workcell.tomlRequiredRejected with an error
sandboxes.tomlRequiredRejected with an error

Caudra writes version = 1 whenever it saves providers.toml. init.lua, which runs only with Lua plugins turned on, has no version because it is a script. To share one init.lua across releases, branch on caudra.version().

On top of the project instruction files Caudra loads from the git root down to the cwd (AGENTS.md, CLAUDE.md, and friends; see Context), you can add:

  • AGENTS.local.md in any of those project directories for per-directory preferences (gitignored)
  • ~/.config/caudra/AGENTS.md for preferences that apply to all projects

All of these are added to the system prompt at the start of every session.

The memory tool and /memory command store small Markdown notes under the state directory, scoped per project:

…/state/caudra/projects/<project-id>/memories/

(Linux/macOS: ~/.local/state/caudra/…; Windows: %APPDATA%\caudra\…). Use them for non-obvious gotchas and decisions that should survive across sessions. They are separate from skills and from AGENTS.md.

Related pages: Skills, CLI, Providers.

Website privacy and analytics