Klaub reads two optional TOML files and merges them, the project's over the user's:
- the user's
config.tomlin Klaub's config directory (klaub doctorprints the path), then .klaub.tomlat the root of the worktree.
Tables merge key by key. A scalar or an array in the project file replaces the user's value. An unknown key, a wrong type or a value out of range is an error that names the file, the line and the column. Nothing is ever written to either file by Klaub.
Every key has a default, so an empty file (or none) is valid. The schema lives in src/domain/config.rs; this page is the tour.
| Key | Default | Meaning |
|---|---|---|
base |
"HEAD" |
The revision a review compares against. klaub review --base overrides it. |
default_scope |
"worktree" |
worktree, staged, unstaged or branch. klaub review --scope overrides it. |
sort |
"priority" |
How the queue is ordered: priority, module or execution. |
include_untracked |
true |
Whether untracked, non-ignored files are part of the change. .klaub/ never is. |
max_file_bytes |
2097152 |
Larger files are listed with metadata and not parsed. |
| Key | Default | Meaning |
|---|---|---|
ui.theme |
"dark" |
dark (Tokyo Night colours), light, catppuccin_mocha, catppuccin_latte, dracula, gruvbox_dark, nord, rose_pine or high_contrast. The colour themes use 24-bit colour when the terminal reports it (COLORTERM=truecolor) and the 256-colour palette otherwise. high_contrast uses no colour at all. : then "Switch colour theme" cycles through them for the current session; set ui.theme to keep the one you like. |
ui.language |
"auto" |
The language of the reader and the command line: auto, en, pt or es. auto follows KLAUB_LANG, then LC_ALL, LC_MESSAGES and LANG, and falls back to English. A value other than auto wins over the environment. The JSON output, exports and the text pasted into the agent stay in English; see Languages. |
ui.density |
"comfortable" |
How much air the lists leave around each row: comfortable adds a blank line between rows in the queue, the tree and the impact view, compact packs them as tightly as they stay readable. |
ui.show_hints |
true |
The key hints in the status line. |
ui.mouse |
false |
The wheel scrolls, a click on a tab switches to it, a click on a row selects it and a second click opens it. Off by default because capturing the mouse stops the terminal's own text selection until you hold the modifier it offers (usually Shift, or Option in iTerm2). The mouse only does what a key already does. |
ui.hold_to_peek |
false |
Hold B (the peek_previous key) while reading code to see the previous version, and let go to come back. It needs a terminal that reports key releases (the kitty keyboard protocol: kitty, Ghostty, WezTerm, recent iTerm2 and foot). Where that is missing, which includes tmux, the key says so and v still toggles. While it is on, the terminal sends keys as escape codes except inside text fields, which keep ordinary input so compose and AltGr characters still type. |
integration.submit_mode |
"manual" |
The only mode. Klaub never presses Enter in the agent. |
integration.ask_agent_confirms |
false |
The t shortcut, which puts what is on screen in the agent's input for you to ask about it, does it with one key. true asks first, showing the destination and the text. |
integration.tmux_prefix |
"C-b" |
The prefix of the session chords. Moving between the agent and the reviewer needs no prefix: Shift+← goes to the agent and Shift+→ to the reviewer. The rest are Prefix+R, Prefix+A, Prefix+d, Prefix+Q and Prefix+?. |
Moves a reader action to another single character. An action that is moved gives up all of its default characters, so the help never lists a key that stopped working.
[keys]
toggle_reviewed = "e"
explain = "E"The ids are:
queue, structure, files, code, decisions, flow, ask_agent, next_unreviewed, previous_unreviewed, next_critical, toggle_reviewed, toggle_bookmark, next_bookmark, explain, toggle_version, peek_previous, next_change, previous_change, toggle_code_scope, search, filter_high, filter_unreviewed, filter_introduced, filter_no_tests, filter_new, cycle_scope, cycle_module, clear_filters, history_back, history_forward, deeper_tree, shallower_tree, refresh, help.
The keys that only mean something inside some modes move the same way. A moved key answers to its new character in the modes it works in, and its old character stops acting there:
| Id | Default | Works in |
|---|---|---|
down, up |
j, k |
every list and the code |
scroll_left, scroll_right |
h, l |
Code |
open_file |
o |
Code |
inspect_contract |
i |
Code |
toggle_inspector |
K |
Code |
approve, reject |
a, d |
Decisions |
comment |
c |
Decisions |
send_decisions |
f |
Decisions |
ask_decisions |
g |
Decisions |
ask_flow |
g |
Flow |
edit_flow |
e |
Flow |
reload_flow |
L |
Flow |
[keys]
down = "z"
up = "Z"
open_file = "O"A mode-specific key may take a letter that another mode uses, but not one that is live in the same mode, and not one a global action already has. The footer and the help show the keys in use.
Some keys are deliberately not rebindable, because a terminal cannot be assumed to deliver anything else reliably: the arrow, page and function keys, Esc, Enter, Tab, the palette (:), quitting (q), Space and the confirmation keys (y/n inside a question). A binding on one of those is refused. So is a value that is not exactly one printable character, an id that does not exist, and two keys that would be live on one character. The reader will not open with an invalid [keys] table; it says which entry is wrong.
| Key | Default | Meaning |
|---|---|---|
languages |
python, javascript, typescript, rust, go, java | Languages that get semantic analysis. Others are shown as plain files. |
max_call_depth |
8 |
How far the reverse call graph is followed. |
match_strong_threshold |
0.85 |
A symbol match at or above this is strong. |
match_probable_threshold |
0.65 |
At or above this it is probable; below it the match is left unresolved. |
brief_file is a local Markdown file imported as the brief. It is read only when set (or passed with klaub review --brief), and a copy is kept in the review.
| Key | Default | Meaning |
|---|---|---|
enabled |
true |
Look for tests associated with changed symbols. |
run_mode |
"manual" |
The only mode. Nothing runs without you. |
report_paths |
[] |
JUnit XML and Coverage.py XML reports to read. |
python_patterns, js_patterns, rust_patterns, go_patterns, java_patterns |
per language | Where test files live. Java's default is **/src/test/**/*.java, **/*Test.java, **/*Tests.java and **/*IT.java. |
command |
unset | The test command, as an array (["pytest", "-q"]). Never inferred from the repository, never run through a shell. |
timeout_secs |
600 |
Time limit for a run. |
[architecture]
modules = ["src/api", "src/domain", "src/infra"]
[[architecture.forbidden_dependencies]]
from = "src/domain"
to = "src/infra"Without modules, packages and directories are used and the rules say they are guesses.
The weights of the explainable score. Every key is an integer and the review shows each term. The names are contract_change, entrypoint_external, entrypoint_internal, fan_in, cross_module, global_scope, criticality, complexity, complexity_growth, risk_per_finding, risk_critical, risk_cap, no_tests, architecture_violation, format_only, test_file, generated and moved, plus the thresholds fan_in_threshold and complexity_threshold.
disabled is a list of rule ids that are off, the way to silence a rule everywhere.
| Key | Default | Meaning |
|---|---|---|
enabled |
true |
Look for .klaub/decisions/<snapshot-id>.json. |
directory |
".klaub/decisions" |
Relative to the worktree. |
max_file_bytes |
1048576 |
Larger decisions files are rejected. |
| Key | Default | Meaning |
|---|---|---|
coverage.count_unit |
"symbol" |
What the review progress counts: symbol or file. |
coverage.warn_on_unreviewed_p0_p1 |
true |
The non-blocking warning when finishing. |
flows.enabled |
true |
Look for .klaub/flows/<snapshot-id>.json. |
flows.directory |
".klaub/flows" |
Relative to the worktree. |
flows.max_file_bytes |
1048576 |
Larger flow files are rejected. |
flows.missing_prompt |
"confirm" |
confirm: the Flow window can put a request for the agent in its input, only after you confirm. never: it cannot. |