Configuration
Every key of ~/.config/komrad/config.toml with its built-in default. Write only the keys you are changing; an unknown key is an error.
Top level#
Config is the user's customization.
| Key | Default | Description |
|---|---|---|
default_harness | "claude" | Which agent CLI a new agent runs when neither the agent nor its workflow names one. It has to be a harness this binary implements, so it is one of the names under [harness] below. |
[harness.claude]#
| Key | Default | Description |
|---|---|---|
flags | "" | Flags appended to every agent's command line for this CLI, ahead of the flags that agent carries itself. |
[harness.codex]#
| Key | Default | Description |
|---|---|---|
flags | "" | Flags appended to every Codex agent's command line, ahead of the flags that agent carries itself. |
trust_launch_dirs | false | Whether to record each agent's directory as trusted in Codex's own config before launching it. Codex asks whether a directory is trusted the first time it runs there and waits for an answer, which it reads only from that file, so an agent in a fresh worktree otherwise starts blocked and shows here as waiting. Turning this on edits that file on your behalf. |
[usage]#
How much agents may run and how large their conversations may grow.
| Key | Default | Description |
|---|---|---|
max_agents | 50 | How many unarchived agents this engine may run at once, past which a create is refused. |
[usage.implementer]#
What an implementer, the agent that lands work on a branch of its own, may use.
| Key | Default | Description |
|---|---|---|
auto_compaction | 250000 | The conversation size in tokens an agent is held under, summarizing its history a little before it gets there. Lower costs less per turn and forgets more. 0 leaves the agent CLI's own default, and a value the CLI will not take is moved to the nearest one it will. |
max_children | 3 | How many children, such as its reviewer, one implementer may hold at once. Children share their parent's checkout, so this is deliberately far lower than max_agents. |
[usage.reviewer]#
What a reviewer, the child that reads another agent's work, may use.
| Key | Default | Description |
|---|---|---|
auto_compaction | 250000 | The conversation size in tokens an agent is held under, summarizing its history a little before it gets there. Lower costs less per turn and forgets more. 0 leaves the agent CLI's own default, and a value the CLI will not take is moved to the nearest one it will. |
[usage.orchestrator]#
What a workflow's orchestrator may use.
| Key | Default | Description |
|---|---|---|
auto_compaction | 150000 | The conversation size in tokens an agent is held under, summarizing its history a little before it gets there. Lower costs less per turn and forgets more. 0 leaves the agent CLI's own default, and a value the CLI will not take is moved to the nearest one it will. |
max_children | 0 | How many agents one orchestrator may have spawned and running at once, not counting their children. 0 sets no limit of its own, leaving max_agents as the cap. |
[layout]#
Where the panel's sidebar, the stage beside it, and the info pane under the stage sit, and how much of the popup each takes.
| Key | Default | Description |
|---|---|---|
sidebar_side | "left" | Which side of the popup the panel's sidebar sits on, "left" or "right". |
sidebar_width | 30 | How many columns wide the panel's sidebar opens at. Dragging the divider afterwards moves it, and the panel follows. |
info_side | "below" | Which side of the stage the info pane opens on, "below" or "above". That pane is where the server log and an editor are drawn. |
info_height | 0.4 | How tall the info pane opens, either a share of the stage's height below one or a whole number of rows. |
details_height | 9 | How many lines the details under the list draw, either a share of the sidebar's height below one or a whole number of lines. The marks the hovered row is carrying are spelled out in that same room, ahead of the fields. The chrome around them is added on top, and the two together never take more than half the sidebar's height. Once the details hold the keys they grow past this to show the whole record, as far as the sidebar allows. |
[keybindings]#
Panel keybindings, scoped to the screen each binding acts in.
[keybindings.agents]#
The agents list, the panel's main screen.
| Key | Default | Description |
|---|---|---|
archive | ["z"] | Archive the hovered agent, which stops it and moves it to the archive screen rather than destroying it. |
back | ["esc"] | Step out of a workflow scope, or quit at the root. |
review | ["d"] | Review what the hovered agent has changed in its worktree, with the diff and the review threads drawn beside each other across the window. The key does nothing for an agent whose workflow does not make worktrees, since there is no base branch to measure one against, and the legend leaves it off there. |
pause | ["p"] | Pause the hovered agent where it stands, or unpause one you have already paused. Komrad waits for the agent to come to rest before it claims the worktree, and refuses rather than claiming it when the agent will not stop or its pane cannot be read. |
release_silently | ["P"] | Unpause the hovered agent without typing anything at it, which is the way out of a pause whose agent will not take the words komrad normally sends it. |
hide | ["h"] | Hide the hovered agent from this list. |
new | ["c"] | Start a new agent. |
child | ["C"] | Attach a child agent to the hovered agent, which runs in that agent's own checkout with no worktree of its own and is archived along with it. |
open | ["enter"] | Attach to the hovered agent, or to the workflow's own orchestrator when the cursor is on a workflow. Either one is started first if it is not running. |
quit | ["ctrl+c"] | Quit the panel. |
rename | ["r"] | Rename the hovered agent. |
retry | ["R"] | Retry the launch of an agent that failed to create, opening a form where the flags can be corrected before confirming. |
search | ["s"] | Search every conversation the panel holds for what you type, the archived ones included. |
[keybindings.archive]#
The archive screen, and the key that opens it from the agents list.
| Key | Default | Description |
|---|---|---|
back | ["esc"] | Leave the archive for the agents list. |
delete | ["d"] | Destroy the agent under the cursor for good, with its transcript. This is the one thing in the panel nothing undoes, so it asks first. |
empty | ["D"] | Destroy every archived agent for good, however many there are. The panel hands the work to a background job, since tearing down that many agents takes a while. It asks first. |
open | ["Z"] | Open the archive from the agents list. |
quit | ["ctrl+c"] | Quit the panel. |
restore | ["r"] | Put the agent under the cursor back in the panel. |
restore_open | ["R"] | Put the agent under the cursor back in the panel and open it, which relaunches its conversation in a pane and takes you to it. An agent that never got as far as starting is only restored. |
[keybindings.details]#
The details under whichever list is on screen: the key that hands them the cursor, and the key that copies the field it lands on.
[keybindings.filter]#
The filter over whichever list is on screen, shared by every screen that draws one. The key that opens it is "/" and is not configured.
| Key | Default | Description |
|---|---|---|
next_match | ["n"] | Move the cursor to the next row matching the search, wrapping at the end of the list. |
prev_match | ["N"] | Move the cursor to the previous row matching the search. |
[keybindings.help]#
The key that draws the legend under a list, shared by every screen for the same reason navigation is.
| Key | Default | Description |
|---|---|---|
toggle | ["?"] | Toggle for the keybindings |
[keybindings.git]#
The git menu on the agents list, and the actions inside it.
| Key | Default | Description |
|---|---|---|
open | ["b"] | Open the git menu on the hovered agent. |
open_pull_request | ["o"] | Open the hovered agent's current pull request in your browser: the newest one opened from its branch that is not finished, else the newest finished one. The entry says so rather than acting on an agent with none. |
rebase | ["r"] | Bring the hovered agent's worktree up to date on the latest base, which asks first and says what it would do to the branch and to the files. |
[keybindings.logs]#
The key that pages the service's log, shared by every screen since the log is about the service rather than about anything a screen lists.
[keybindings.marks]#
The marks a person puts on rows to jump between them, as vim's own marks work.
| Key | Default | Description |
|---|---|---|
set | ["m"] | Set a mark on the row under the cursor, agent or workflow, then the letter to set, or the letter it already holds to take the mark off it. |
jump | ["'"] | Jump the cursor to a marked row, then the letter to jump to, or the jump key again to go back to where the last jump left from. |
[keybindings.nav]#
Navigation, shared by every menu so movement is the same everywhere.
| Key | Default | Description |
|---|---|---|
bottom | ["G"] | Jump to the last row. |
down | ["j"] | Move the cursor down. |
page_down | ["ctrl+d"] | Move the cursor down a chunk of rows, stopping on the last one. |
page_up | ["ctrl+u"] | Move the cursor up a chunk of rows, stopping on the first one. |
top | ["g"] | Jump to the first row, pressed twice the way vim's gg is. |
up | ["k"] | Move the cursor up. |
[keybindings.review]#
The review screen, which draws an agent's diff in the stage and its review threads in the sidebar.
| Key | Default | Description |
|---|---|---|
back | ["esc"] | Leave the review for the agents list. |
base | ["<"] | Walk back a round through the review, from the whole change to the newest round and on into the older ones, stopping on the oldest. |
base_forward | [">"] | Walk the other way through the rounds, towards the newest work and on to the whole change. |
compose | ["c"] | Write a message on the line under the cursor, replying in the thread already there or opening a new one. |
edit_file | ["e"] | Open the file under the cursor in your editor, beside the diff, on the line the cursor is on. This is the agent's own worktree rather than a copy of it, so what you write is what the agent finds there, and the key is refused while the agent is working rather than letting you both write at once. It is refused on a round the agent has written past, since those lines have moved on. |
focus_thread | ["ctrl+f"] | Move the keys onto the thread in the sidebar, so up and down read the conversation rather than the diff, and press it again to hand them back. A thread longer than the sidebar is otherwise only readable from its end. |
next_file | ["]"] | Jump to the next file in the diff. |
next_match | ["n"] | Jump to the next line matching the pattern the filter key searched for. |
next_thread | ["t"] | Jump to the next line carrying a review thread. |
next_open_thread | ["u"] | Move the cursor to the next comment nobody has settled. It stops on the last one. |
pan_left | ["h", "left"] | Pan the diff left, for a line wider than the pane. |
pan_reset | ["0"] | Pan back to the start of the line. |
pan_right | ["l", "right"] | Pan the diff right. |
prev_file | ["["] | Jump to the previous file in the diff. |
prev_match | ["N"] | Jump to the previous line matching the pattern. |
prev_open_thread | ["U"] | Move the cursor to the previous comment nobody has settled. It stops on the first one. |
prev_thread | ["T"] | Jump to the previous line carrying a review thread. |
quit | ["ctrl+c"] | Quit the panel. |
reload | ["R"] | Catch up with the agent, once the band says it has written since you opened the diff. What you are reading never moves on its own, since that would take the code out from under a comment being written, so catching up is always yours to ask for. |
resolve | ["r"] | Settle the thread under the cursor, which marks it resolved without deleting it. |
expand | ["E"] | Draw the whole of the file the cursor is in rather than the changed lines and the three around them, or go back to those. The lines this adds behave like any other: the cursor rests on them and a comment can be written on one. A file stays open while you are reading this change and is drawn tight again when you leave. |
toggle_viewed | ["v"] | Fold away the file the cursor is in once you have read it, or open it again. A file the agent writes to afterwards comes back on its own. |
[keybindings.column]#
The keys the mouse wheel presses over the panel, shared by every screen.
| Key | Default | Description |
|---|---|---|
scroll_down | ["ctrl+n"] | Scroll down. |
scroll_up | ["ctrl+p"] | Scroll up. |
[keybindings.schedules]#
The schedules screen, and the key that opens it from the agents list.
| Key | Default | Description |
|---|---|---|
archive | ["z"] | Archive the schedule under the cursor, which stops it firing. The agents it launched are kept, and nothing brings the schedule back. |
back | ["esc"] | Leave the schedules screen for the agents list. |
edit | ["e"] | Edit the schedule under the cursor. |
new | ["c"] | Write a new schedule. |
open | ["S"] | Open the schedules screen from the agents list. |
quit | ["ctrl+c"] | Quit the panel. |
toggle | ["space"] | Pause or resume the schedule under the cursor. |
[keybindings.sidebar]#
The keys that move the sidebar's edge, shared by every screen.
[keybindings.selection]#
Choosing several agents at once, shared by the two screens that draw a tree.
[keybindings.tabs]#
The row of tabs a screen draws over its list, and the key that hands it the cursor.
| Key | Default | Description |
|---|---|---|
focus | ["f"] | Hand the keys to the row of tabs over the list; escape hands them back. |
[keybindings.terminal]#
The key that opens a shell in the hovered agent's directory, shared by every screen that lists agents.
| Key | Default | Description |
|---|---|---|
open | ["T"] | Open a shell in the hovered agent's directory, focus the one already there, or move it here. |
[keybindings.workflows]#
The bindings that create and change workflows, from the agents list.
| Key | Default | Description |
|---|---|---|
adopt | ["a"] | Put an agent on a branch that already exists, in the workflow under the cursor. |
archive | ["z"] | Archive the workflow under the cursor, which archives the agents inside it. |
edit | ["e"] | Edit the workflow under the cursor. |
new | ["w"] | Create a workflow. Works from anywhere in the list. |
rename | ["r"] | Rename the workflow under the cursor. |
[keybindings.worktrees]#
The worktrees screen, which lists every directory komrad cut for an agent.
| Key | Default | Description |
|---|---|---|
back | ["esc"] | Leave the worktrees screen for the agents list. |
clear | ["D"] | Delete everything on the screen that can go: every directory whose agent is archived, through the agent delete and its hooks, and every directory no agent answers for. A directory with a live agent in it is never deleted. |
delete | ["d"] | Delete the directory under the cursor. One with an archived agent goes through the agent delete, which runs the workflow's hooks and the cleanup; one with a live agent offers to archive it first; one nothing answers for is removed on its own. It asks first. |
jump_to_agent | ["J"] | Jump to the agent in the directory under the cursor, on the agents list or in the archive. |
open | ["t"] | Open the worktrees screen from the agents list or the archive, landing on the hovered agent's own directory. |
quit | ["ctrl+c"] | Quit the panel. |
[hooks]#
Where komrad finds the scripts a workflow hangs on a moment in its agents' lives.
| Key | Default | Description |
|---|---|---|
dir | "" | Directory for hooks: one executable file per hook, named after the hook. A hook is a script or program komrad runs at a moment a workflow names it against, in the agent's own directory, with agent info in KOMRAD_AGENT as JSON and the moment in KOMRAD_TRIGGER. Default is ~/.config/komrad/hooks. |
[worktrees]#
Where a workflow's generated worktree provisioner creates its worktrees.
| Key | Default | Description |
|---|---|---|
dir | "" | Directory generated worktrees are created under, one subdirectory per agent. Left empty this is ~/.local/state/komrad/worktrees. |
[github_app]#
The GitHub App an engine fetches and pushes as.
| Key | Default | Description |
|---|---|---|
app_id | "" | The App's own id, from its settings page. Left empty the engine has no GitHub identity and git is left to whatever credentials the account already has, which on a machine nobody logs into is none. |
installation_id | "" | The installation the token is minted for, which is what scopes it to the repositories the App was installed on rather than to everything it could reach. GitHub writes it as a number, and it is in the URL of the installation's own settings page. |
private_key_path | "" | The PEM the App was created with. On a deployed engine this is fetched into a tmpfs at boot rather than written to disk, so the key does not outlive the machine. |
[context]#
The standing text every agent is started with, whatever workflow it is in.
| Key | Default | Description |
|---|---|---|
file | "" | The file holding global context, read at each launch. Left empty this is ~/.config/komrad/context.md, but will not trigger a failure if left blank. |
[mail]#
How mail between agents is delivered.
| Key | Default | Description |
|---|---|---|
delivery_deadline | "3h" | How long mail stays deliverable, as a Go duration such as "3h" or "45m". Mail past it is neither delivered nor readable, and the row is kept as a record that it never arrived. A duration komrad cannot read, or one that is not positive, is refused. |
max_exchange | 40 | How much mail two agents may write each other before a send between them is refused. It counts the pair in both directions over every thread, so opening a new subject is not a way around it. When a send is refused komrad marks a row for attention and tells the recipient its mail was stopped, so an exchange that is cut off does not leave the other side waiting on a reply that will never arrive. A negative limit is refused. |
[log]#
The log the background service writes, which the panel's log key pages.
| Key | Default | Description |
|---|---|---|
level | "info" | How much is written, one of debug, info, warn, or error. |
viewer | "tail -n +1 -F \"$KOMRAD_LOG\" | grep --line-buffered \"$KOMRAD_AGENT_ID\" | less -R +F" | The default log viewer. Switch with fzf, rg, etc. |
process_viewer | "less -R -X \"$KOMRAD_LOG\"" | The viewer for a provisioner's or deprovisioner's own output, plain text rather than the structured log's JSON lines. |
[debug]#
Puts komrad into debug mode which records additional information used to help diagnose issues.
| Key | Default | Description |
|---|---|---|
frames | false | Whether the pane capture behind each reading of an agent is kept under the cache directory. |
frame_history | 500 | How many frames are kept for one agent before the oldest is dropped. A number at or below zero takes the default. |
[connection]#
Which komrad this is: the database, the address, the tmux socket, the cache.
| Key | Default | Description |
|---|---|---|
database_url | "postgres://komrad_engine_default:komrad@localhost:5460/komrad?sslmode=disable" | The Postgres komrad keeps every agent, workflow, schedule and transcript in, reached as
this engine's own login, which is what keeps its rows apart from every other engine's.
|
owner_database_url | "" | The login that owns the schema, used only by |
readonly_database_url | "" | The least-privilege login the MCP query tools connect as. Left empty this is database_url with the engine's reader login, which is its own login with _reader on the end and the same password. |
addr | "127.0.0.1:8787" | Where the background service listens, and where the panel, the CLI and the MCP endpoint all reach it. Change it to run two komrads on one machine. It has to be a loopback host, since the api has no auth and its writes spawn agents. |
tmux_socket | "komrad" | The tmux socket komrad runs its own server on. Nothing in your normal tmux sees
that server, which is why |
cache_dir | "" | Where komrad keeps what it generates: the service log, the built-in scripts it writes out on every start, and the temp files a harness passes a prompt through. Left empty this is ~/Library/Caches/komrad on a Mac and ~/.cache/komrad on Linux. Everything under it is komrad's to delete and rewrite, so nothing of yours belongs here. |
ssh | "" | The ssh destination the engine runs on, like user@host, when it is not this machine. Left empty the engine is local and an agent's terminal is shown by moving its own pane into the panel, which only works while the panel and the agents share a tmux server. |
engine_tmux_socket | "" | The tmux socket the engine's own server runs on, which is only consulted when ssh names a destination. Left empty it is tmux_socket, which is right when both machines run a default komrad and wrong when this machine is also running an engine of its own. |
panel_key | "" | The key, after your tmux prefix, that opens and hides the panel, and the picker between this machine and its engines once engine files exist. Left empty it is whatever @komrad_key says, and failing that g. An engine file may not set it. |
exec | [] | How to run a command on the engine, as an argv, when ssh is not how you reach it. "{{command}}" is replaced with what komrad wants run there, and "{{command_json}}" with the same text escaped for embedding in JSON. It needs to allocate a terminal, since what it carries is an interactive one. |
forward | [] | How to forward a port from this machine to the engine, as an argv, when ssh is not how you reach it. "{{local_port}}" and "{{remote_port}}" are replaced with the two ends. It should stay in the foreground for as long as the forward is wanted. |
engine_user | "" | The account on the engine that owns its tmux server, where the transport does not already arrive as it. Left empty nothing is stepped into. |