Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Configuration

Ralph uses a TOML configuration file for persistent settings. This document covers file locations, available options, and configuration precedence.

Configuration File Location

Ralph stores its configuration in platform-specific directories:

PlatformConfig DirectoryConfig File
Linux~/.config/ralph/~/.config/ralph/config.toml
macOS~/Library/Application Support/ralph/~/Library/Application Support/ralph/config.toml
Windows%APPDATA%\ralph\%APPDATA%\ralph\config.toml

Environment Variable Overrides

You can override the config directory with an environment variable:

VariablePurpose
RALPH_CONFIG_DIROverride config directory (where config.toml is stored)

Example:

# Use a custom config directory
export RALPH_CONFIG_DIR=/path/to/custom/config
ralph ask 'your prompt'

Configuration Precedence

Settings are resolved in this order (highest priority first):

  1. CLI flags (e.g., --theme "Solarized (dark)")
  2. Environment variables (e.g., RALPH_THEME=Solarized (dark))
  3. Config file (config.toml in config directory)
  4. Default values

This means CLI flags always win, allowing you to override config file settings for specific invocations.

Configuration File Format

The config file uses TOML format. All sections and fields are optional - only include what you want to customize.

Complete Example

# Ralph Configuration File
# Location: ~/.config/ralph/config.toml (Linux)
#           ~/Library/Application Support/ralph/config.toml (macOS)
#           %APPDATA%\ralph\config.toml (Windows)

[theme]
# Syntax highlighting theme for code blocks and diffs
# Can be a built-in theme name or path to a .tmTheme file
name = "base16-ocean.dark"

# When true, don't apply theme background colors
# Useful if you want your terminal's background to show through
no_background = false

Minimal Example

# Just set the theme, everything else uses defaults
[theme]
name = "Solarized (dark)"

Configuration Sections

[theme] - Syntax Highlighting

Controls how code blocks and diffs are displayed in the terminal.

FieldTypeDefaultDescription
namestring"base16-ocean.dark"Theme name or path to .tmTheme file
no_backgroundboolfalseDisable theme background colors

Per-role themes: [theme.assistant] and [theme.agent]

Each role has its own markdown theme. assistant styles the replies of ralph ask and ralph chat. agent styles worker messages that ralph chat shows from /inbox, including the worker header box.

[theme.assistant]
code = "Monokai Extended"   # code-block theme; overrides [theme] name
heading1 = "cyan"

[theme.agent]
code = "Solarized (dark)"   # default: the assistant code theme
heading1 = "#ff6ac1"
inline_code = "dark_cyan"
border = "magenta"
KeyAssistant defaultAgent defaultStyles
code[theme] nameassistant code themeSyntax theme for fenced code blocks
heading1, heading2, heading3cyan, blue, magentagreen, dark_green, dark_yellowHeadings (always bold)
bold, italicterminal defaultterminal defaultEmphasis color
inline_codeyellowdark_cyanInline code (on a dark gray background)
bulletdark_greydark_greenList bullets
quote, tabletermimad defaulttermimad defaultQuote mark, table borders
link, urlblue, cyanblue, cyanLink label (underlined), link URL
memory_refmagentamagenta#N memory references
borderdark_bluedark_blueWorker header box border
done, blocked, waitingdark_green, dark_red, dark_yellowsameWorker status (failed uses blocked, check uses waiting)

A color is a name (black, red, green, yellow, blue, magenta, cyan, white, grey, their dark_ forms, dark_grey, reset) or #rrggbb. ralph chat warns at start for an unknown key or a bad color and keeps the default for it. Plain output stays plain when stdout is not a TTY or NO_COLOR is set.

Status line colors: [theme.status]

ralph chat paints its status line from this table. Every key is optional and takes the same color values as the role themes. Keys that are missing keep the defaults below, so an empty or missing table draws the same bar as before. ralph chat warns at start for an unknown key or a bad color and keeps the default for it.

[theme.status]
mode_idle_fg = "black"    # IDLE block text
mode_idle_bg = "green"    # IDLE block background
mode_nap_fg = "black"     # NAP block text
mode_nap_bg = "magenta"   # NAP block background
mode_inbox_fg = "black"   # INBOX block text
mode_inbox_bg = "yellow"  # INBOX block background
mode_work_fg = "white"    # WORK block text
mode_work_bg = "blue"     # WORK block background
store_fg = "reset"        # store path text
workers_fg = "reset"      # workers text
watches_fg = "reset"      # watches text
memory_fg = "reset"       # memory size text
base_bg = "#303030"       # bar background: filler, store, workers, watches, memory

The default base_bg is ANSI color 236, written #303030 above. reset is the terminal’s own text color. Powerline glyphs take their colors from the neighbouring blocks, so they have no keys.

Code theme precedence for the assistant: --theme > RALPH_THEME > [theme.assistant] code > [theme] name > default.

The old [theme] agent = "<theme>" string still works as [theme.agent] code = "<theme>"; ralph chat prints a deprecation warning for it.

Built-in Themes

Run ralph themes to see all available themes:

Available syntax highlighting themes:

  InspiredGitHub
  Solarized (dark)
  Solarized (light)
  base16-eighties.dark
  base16-mocha.dark
  base16-ocean.dark (default)
  base16-ocean.light

Using a Custom Theme

You can use any TextMate-compatible .tmTheme file:

[theme]
name = "/path/to/my-custom-theme.tmTheme"

Theme Environment Variable

The RALPH_THEME environment variable can be used instead of the config file:

# Set theme via environment variable
export RALPH_THEME="Solarized (dark)"
ralph ask 'your prompt'

# Or for a single command
RALPH_THEME="Monokai Extended" ralph ask 'your prompt'

Disabling Background Colors

If your terminal has a specific background color you want to preserve:

[theme]
name = "base16-ocean.dark"
no_background = true

Or via environment variable:

export RALPH_NO_BACKGROUND=1

Or via CLI flag:

ralph ask --no-background 'your prompt'

[ask] - Single-Shot Prompts

FieldTypeDefaultDescription
permission_modestring"bypassPermissions"Tool permission mode for ralph ask

Precedence: ask --permission-mode, then RALPH_ASK_PERMISSION_MODE, then this key, then bypassPermissions. [chat] permission_mode does not apply to ask. See ralph ask.

[chat] - Persistent Chat

FieldTypeDefaultDescription
mcp_serverslist of strings["mcptools"]Servers from ~/.claude.json to load in chat turns
skillslist of paths[]Skill directories exposed to chat
recent_history_tokensinteger8192Token budget for the newest chat messages shown verbatim in the memory view; 0 turns it off
worker_check_secsinteger60Seconds between worker checks while chat is open; 0 turns the check off
worker_quiet_secsinteger300Seconds a running Cursor worker may send no ACP traffic before one inbox alert; must be above 0, else a warning and 300. The 300 s default is an unverified guess, to be measured by GUZ-651. Runs on the worker check, so worker_check_secs = 0 turns it off too
reset_turnsinteger30Turns one claude process serves before chat drops it and respawns from the store; must be above 0, else a warning and 30
reset_tokensinteger140000Context tokens of the last assistant message at which chat drops the process and respawns from the store; must be above 0, else a warning and 140000
watch_timeout_secsinteger3600Seconds before a watch is killed and reports that it timed out; applies to every watch without its own timeout_secs; 0 is an error
wrap_widthintegerunsetColumn cap for chat replies and the prompt area; 0 or unset wraps at the terminal width
cell_output_limitinteger200Lines of cell output sent to Claude: first half and last half kept; 0 sends all
cell_output_bytesinteger65536Bytes of cell output sent to Claude: head and tail kept; 0 sends all
worker_basestringunsetBase branch that close_worker checks for unmerged commits
worktree_dirstring.worktreesDirectory that holds worker worktrees; a leading ~ expands to home, relative paths resolve against the repo root
permission_modestring"auto"claude --permission-mode for chat turns and claude workers
inbox_alert_soundbooltruePlay a sound when a worker report arrives and the chat is not focused
inbox_alert_notificationboolfalseAlso send a system notification (<id> <status>)
inbox_alert_unknown_focus"alert" or "silent""alert"What to do when focus cannot be detected (outside tmux, no attached client, tmux query failed)
status_powerlineboolfalseUse powerline glyphs (\ue0b0, \ue0b2) between status line segments; needs a patched font. Off draws plain colour blocks
editorlist of stringsunsetCtrl-G editor argv, draft path appended, e.g. ["nvim", "-c", "normal! Go", "-c", "startinsert"]; unset uses $VISUAL, $EDITOR, then vi; empty or wrong type warns and falls back
edit_mode"emacs" or "vi""emacs"Key bindings of the chat prompt; another value prints a warning and uses "emacs". See ralph chat
empty_submit"inbox", "inbox-first" or "phrase""inbox"What Enter on an empty prompt does. inbox: open the inbox when reports are unread, else nothing. inbox-first: open the inbox when reports are unread, else send empty_prompt. phrase: always send empty_prompt, even with unread reports; use /inbox to read them. An unknown value warns and uses inbox
empty_promptstringunsetPhrase sent by inbox-first and phrase, e.g. "continue". Unset, empty or whitespace-only warns and the mode behaves like inbox

--skill and RALPH_CHAT_SKILLS replace skills. For permission_mode the precedence is chat --permission-mode, then RALPH_CHAT_PERMISSION_MODE, then this key, then auto; chat passes the resolved mode to every claude worker it spawns, so chat and workers always match. --recent-history-tokens <TOKENS> overrides recent_history_tokens; see recent history. Without worker_base, close_worker uses origin/HEAD, then main. For worktree_dir the precedence is chat --worktree-dir, then RALPH_WORKTREE_DIR, then this key, then .worktrees. A worker that already has a worktree keeps it: spawn and close look up worker/<ID> in git worktree list first, so changing the key does not lose running workers. A directory inside the repo is added to .git/info/exclude. A config that fails to read or parse skips worktree_dir, and the spawn or close result ends with a warning. For wrap_width the precedence is chat --wrap-width <N>, then RALPH_WRAP_WIDTH, then this key; a value that is not a whole number stops chat start with an error. The width used is the smaller of this cap and the terminal width, read at each render, so a narrower terminal still wins. The cap is read once at chat start: a change to this key or RALPH_WRAP_WIDTH needs a chat restart; a terminal resize does not. It applies to rendered prose (chat turns and drained worker reports) and to the reedline prompt area: the status line, the draft, and the footer. Code blocks are not wrapped. For cell_output_limit and cell_output_bytes the precedence is RALPH_CELL_OUTPUT_LIMIT / RALPH_CELL_OUTPUT_BYTES, then the key, then the default; a value that is not a whole number stops chat start with an error. The caps shape only what Claude receives; the terminal shows all output in result fences. See executable cells. worker_check_secs has no flag or env var; the check is described in ralph chat. chat --no-inbox-sound and --no-inbox-notification turn off the matching alert for one run; focus rules are in ralph chat. See ralph chat.

[cursor] - Cursor Workers

FieldTypeDefaultDescription
permissions"ask" or "yolo""ask""yolo" answers every Cursor session/request_permission with the allow-once option at once; "ask" waits for the person, except for the worker report tool
modelstringunset (cursor’s own default)Model id for Cursor workers that spawn_worker starts without a model. Applied with session/set_config_option, not agent --model. Cursor’s ACP fixes the variant for that model

yolo picks only the allow-once option, never allow-always, and writes nothing to ~/.cursor/cli-config.json. A request with no allow-once option still waits for the person. Cursor’s own rules (deny lists, sandbox) still apply. Risk: shell commands and MCP tools run without asking. A wrong value or type, or a config that fails to read, warns and uses "ask". The key is read when a Cursor worker starts.

A model passed to spawn_worker wins over this key. A value that is empty or has whitespace warns in the spawn result and uses cursor’s default. A config that fails to load warns and uses cursor’s default. The key is read at each spawn. The child is agent acp. After session/new, and again after session/load when chat resumes the worker, ralph sets the session model option from the value Cursor advertises there (worker::select_cursor_model). An exact advertised value is sent as-is. A short name selects the advertised value for that name. Cursor’s ACP fixes one variant per model name, so effort and fast mode cannot be chosen: there is no [cursor] reasoning_effort or [cursor] fast. If a name is listed more than once, the cheapest listed value is sent (fast=false, then no fast, then fast=true, then the lowest effort). Any other string is sent unchanged, and the agent’s rejection is the spawn error. agent --model does not change the ACP session model. The set rewrites the user’s Cursor default. Before the set, ralph writes cursor-model-default.json next to config.toml in the ralph config directory, holding only the model keys. It then restores model, selectedModel, modelParameters, hasChangedDefaultModel, modelSelectionHistory and maxMode in ~/.cursor/cli-config.json, and selectedModelVariantId in ~/.cursor/acp-config.json, and deletes the snapshot. A crash between the set and the restore leaves those files on the worker model. The next ralph chat start sees the snapshot and puts the saved keys back. With no snapshot, that start cannot tell the switched files from a change the user made. The resolved model is stored on the session record and applied again on resume; a record with no model leaves the agent’s current model alone.

[claude] - Claude Workers

FieldTypeDefaultDescription
modelstringunset (claude’s own default)Model name or alias passed as --model to Claude workers that spawn_worker starts without a model

A model passed to spawn_worker wins over this key. A value that is empty or has whitespace warns in the spawn result and uses claude’s default. A config that fails to load warns and uses claude’s default. The key is read at each spawn.

[opencode] - opencode Workers

FieldTypeDefaultDescription
modelstring"openai/gpt-6.1-sol"provider/model for opencode workers that spawn_worker starts without a model

A model passed to spawn_worker wins over this key. A value that is not provider/model warns in the spawn result and uses the built-in default. A config that fails to load uses the built-in default. The key is read at each spawn.

[mermaid] - Diagram Rendering

In a terminal, a fenced mermaid code block renders as a Unicode text diagram for flowchart/graph, sequenceDiagram, erDiagram, classDiagram, stateDiagram, and stateDiagram-v2. Rendering runs in a child process (ralph __mermaid) that ralph kills on timeout or memory overrun. Any refusal, kill, error, or output wider than the terminal shows the highlighted source with no error text. Piped output keeps the raw source.

mermaid-text can drop a transition label on an edge into a composite state.

KeyDefaultMeaning
timeout_ms500Kill the render child after this many milliseconds
max_rss_mb256Kill the child above this resident size (macOS and Linux only; elsewhere only the timeout applies)
max_input_bytes1048576Refuse a block with more source bytes
max_flowchart_edges50Refuse a flowchart/graph, stateDiagram, or stateDiagram-v2 with more arrow tokens
max_class_relations400Refuse a classDiagram with more relation tokens (provisional: dense graphs among few classes can exceed the timeout well below 400; the timeout still bounds them)

Fixed limits: flowchart, stateDiagram, and stateDiagram-v2 source up to 16 KB; sequenceDiagram up to 20 participants, 64 KB, and 2000 statements; erDiagram up to 64 KB and 2000 statements. A config that fails to load prints a warning and uses these defaults.

[changes] - /diff pager and turn snapshots

/diff in chat runs git diff. See ralph chat. Chat also snapshots the repo around each turn. See ralph chat.

KeyDefaultMeaning
pager"git"git, delta, or hunk. An unknown string warns once at chat start and uses git; the config still loads
diff_args[]git diff arguments placed before the ones typed after /diff
enabledtrueSnapshot the chat’s repo at the start and end of each turn. false turns it off

delta and hunk are one-off git -c core.pager=... (hunk passes core.pager=hunk pager as one argument). ralph sets no environment variables and does not change core.pager in git config. With pager = "git", git uses the user’s pager.

[wire.prices] - ralph wire ls price overrides

ralph wire ls prices calls from a built-in dated table. A [wire.prices."<model prefix>"] table overrides it for that exact model id, or the same id plus an 8-digit date (-20261021). Longest prefix wins. Any [...] suffix on the recorded model is ignored. An override applies at every prompt size. A negative price fails config load, so ralph wire ls fails. A config that fails to parse fails the same way. See ralph wire.

[wire.prices."claude-haiku-5-5"]
input = 0.1
output = 0.5
KeyDefaultMeaning
inputrequiredUSD per million uncached input tokens
cache_readinput x provider multiplierUSD per million cache-read tokens
cache_write_5minput x provider multiplierUSD per million 5-minute cache-write tokens
cache_write_1hinput x provider multiplierUSD per million 1-hour cache-write tokens
outputinput x provider multiplierUSD per million output tokens

Unknown keys are an error. Speed and geography factors from the recorded usage still apply on top.

Chat Store

ralph ask stores nothing. ralph chat keeps its store at ~/.ralph/chat. For another path the precedence is chat --store <DIR>, then RALPH_CHAT_STORE, then ~/.ralph/chat; a relative path resolves against the cwd at startup. Parallel chats need separate stores. See ralph chat.

Verbose Tools Configuration

The --verbose-tools flag controls how much detail is shown for LLM tool invocations during ralph ask.

Usage

# Enable verbose output for all tools
ralph ask --verbose-tools 'your prompt'

# Enable verbose for specific tools (comma-separated, case-insensitive)
ralph ask --verbose-tools=read,grep,bash 'your prompt'

# Single tool
ralph ask --verbose-tools=glob 'your prompt'

Supported Tools

ToolVerbose Output Shows
readFull file content with syntax highlighting and line numbers
editFull diff with syntax highlighting
writeFull diff showing new/changed content
globAll matched files grouped by directory
grepFull regex pattern and matched content
bashFull command and output with shell syntax highlighting
todowriteFull todo list with status indicators
notebookeditFull cell diff for Jupyter notebooks

Non-Verbose Mode (Default)

Without --verbose-tools, tool output is shown in a compact format:

  • File paths shown without content
  • Large outputs truncated
  • Pattern matches summarized

Environment Variables Reference

VariablePurposeExample
RALPH_CONFIG_DIROverride config directory/custom/config
RALPH_THEMESet syntax highlighting themeSolarized (dark)
RALPH_NO_BACKGROUNDDisable theme backgrounds1
RALPH_ASK_PERMISSION_MODEPermission mode for ralph askacceptEdits
RALPH_CHAT_PERMISSION_MODEPermission mode for chat turns and claude workersauto
RALPH_WORKTREE_DIRDirectory for worker worktrees; ~ expands, relative paths resolve against the repo root.worktrees
RALPH_CHAT_STOREChat store directory; relative paths resolve against the cwd~/chats/a
RALPH_CHAT_SKILLS:-separated skill directories for chat~/skills/a:~/skills/b
RALPH_WRAP_WIDTHColumn cap for chat replies and the prompt area; 0 = terminal width80

Troubleshooting

Finding Your Config Location

If you’re unsure where ralph is looking for configuration:

# Check what paths ralph uses
ralph --version
# Then check the platform-specific path for your OS

Config File Not Loading

  1. Verify the file exists at the correct path
  2. Check file permissions (must be readable)
  3. Validate TOML syntax - even small errors prevent loading:
    # Test TOML validity
    cat ~/.config/ralph/config.toml | python3 -c "import sys, tomllib; tomllib.loads(sys.stdin.read())"
    

Theme Not Applying

  1. Verify the theme name matches exactly (run ralph themes for the list)
  2. For custom themes, ensure the file path is absolute and the file exists
  3. Check if a CLI flag or environment variable is overriding your config