Configuration
orangu uses an INI configuration file.
Interactive setup
(--init)
Run orangu --init (short form -i) to
generate the configuration interactively instead of editing the file by
hand:
orangu --initThe wizard:
- Asks for the LLM URL (the server
endpoint). - Queries the server’s
/v1/modelsendpoint and pre-fills the first advertised model as the Model value; if no model can be detected, you enter one manually. - Walks every
[orangu]and server option, showing its default in[brackets]. Press Enter to keep the default. Boolean options acceptYes/Y/No/N(case-insensitive). - Reports which optional external
tools it detects (
git lg,delta,bat,gh, andglab). Each is shown asNowhen the tool is absent,Yes (Used)when it is installed and configured to be used, orYes (Not used)when it is installed but not yet wired up — for exampledeltainstalled but not set as your Git diff pager. See Optional external tools for how each one is activated. - Installs bundled skills into
~/.orangu/skills/when they are not already present. At the moment this includesdebugging. - Shows the resulting configuration and asks for confirmation before writing.
The server is orangu-server. Only values that differ
from their default are written, so the generated file stays minimal. It
is written to ~/.orangu/orangu.conf, creating
~/.orangu/ if needed and overwriting any existing file.
Bundled skills are written to
~/.orangu/skills/<skill>/SKILL.md and are left
untouched when the file already exists.
Agent Skills
orangu supports Agent Skills: directories containing a
SKILL.md file with YAML frontmatter and markdown
instructions. Skills are discovered from four locations:
~/.orangu/skills/~/.agents/skills/<workspace>/.orangu/skills/<workspace>/.agents/skills/
Project skills override user skills with the same name. The
/skills command lists the discovered skills. A skill can be
invoked explicitly with /skill-name; for example, the
bundled debugging skill is typically available after
--init:
/debugging reproduce the failing request path and identify the root cause
See the Skills chapter for how to write instruction-only skills, skills with helper files, and skills that compile helper code.
Startup connectivity
The terminal UI renders immediately on launch — it never waits on a
network check first. The header’s Server/Model
rows show a white dot while connectivity is still being resolved in the
background, turning green or red within a moment.
If the default server ([orangu] server = ...) doesn’t
respond, orangu automatically tries the other configured server sections
in turn and switches to the first one that does, printing “Switched to
server: <name>” to the output window. If none of them
respond either, it stays on the default (which then shows red, as
usual). This happens once, at startup; /server still
switches on demand exactly as before.
Per-session server and model
Each workspace tab keeps its own active server, model, and endpoint.
A /server or /model command in one tab does
not affect any other tab, and switching tabs restores the server and
model that were active there.
These choices are persisted automatically. When you run
/server or /model, the selected values are
written to the session’s settings file:
~/.orangu/sessions/<UUID>/settings
The next time that session is resumed — whether in a new run or after a tab switch away and back — orangu restores the server and model from there. No manual config files are needed.
[orangu]
The main section selects the default server and client-wide limits.
The server key names the server section that holds the host
information:
[orangu]
server = main-server
model = ggml-org/gemma-4-E4B-it-GGUF
timeout = 1800
max_tool_rounds = 10
review_max_tokens = 512
code_max_tokens = 0
theme = classic| Key | Required | Description |
|---|---|---|
server |
Yes, if multiple servers exist | Name of the default server section |
model |
No | General default model name. Used unless
the selected server defines its own model, which takes
precedence |
timeout |
No | Request timeout in seconds. The default is
1800 |
max_tool_rounds |
No | Maximum tool-calling turns before the client aborts the prompt |
review_max_tokens |
No | Response-token cap for each
/auto_review request. Defaults to 512;
0 disables the cap. Raise it (e.g. 2048) when
the review model thinks before answering |
code_max_tokens |
No | Response-token cap for normal chat and
tool responses. Defaults to 0 (no cap) |
compile_workers |
No | Parallel job count /build
passes to toolchains that support one (e.g. make -j,
meson compile -j, cargo --jobs). Defaults to
0, meaning unused: no job flag is passed and each toolchain
falls back to its own default |
quotes |
No | Quote set shown while the model is
thinking. Defaults to none. Options: none,
star_trek, star_wars,
marco_pierre_white, gordon_ramsay,
calvin_and_hobbes, sun_tzu_mandarin,
sun_tzu_english, attila_the_hun,
all |
width |
No | Virtual terminal width in characters.
Controls the layout canvas for /show_file output. Defaults
to 512 |
banner |
No | Horizontal placement of the banner.
Defaults to left. Options: left,
center, right |
theme |
No | Global default UI theme. Defaults to
classic. Built-ins are classic,
modern_dark, modern_light,
oranguday, tokyonight, and
rosepine-moon; random draws one of the
available themes at each launch. User themes are loaded from
~/.orangu/themes/*.theme |
drop_down |
No | Enable the autocomplete dropdown for slash
commands. Defaults to on. Options: on,
true, 1, off, false,
0 |
word_wrap |
No | Wrap long lines in the main TUI,
/show_file, /review, and
/auto_review windows. Defaults to off; set it
to on to wrap at the visible width. Options:
on, true, 1, off,
false, 0 |
mouse |
No | Enable mouse capture in the terminal. When
true (the default), the TUI handles mouse scroll and
double-click. Hold Shift while clicking/dragging to do
native text selection and copy. Set to false to disable all
mouse handling |
workspaces |
No | Placement of the workspace tabs. Defaults
to top. Options: top, bottom,
left, right. See the Workspaces chapter |
feedback |
No | Show a green or red dot in the output
window after each command to indicate success or failure, blink an
orangu ● progress title and ring the terminal bell when a
/auto_review finishes. Defaults to off.
Options: on, true, 1,
off, false, 0 |
auto_rebase |
No | Automatically rebase the branch before
/pull_request if it is behind the base. Defaults to
off. Options: on, true,
1, off, false,
0 |
auto_squash |
No | Automatically squash commits before
/pull_request if more than one commit is ahead of the base.
Defaults to off. Options: on,
true, 1, off, false,
0 |
terminal |
No | Launch command used to open
$EDITOR for terminal editors in a new window for
/open_file (for example xterm -e or
kitty). When unset, a terminal emulator is
auto-detected |
platform |
No | Code-hosting platform driven for
/pull, /pull_request, /merge, and
/comment. Defaults to github (uses the
gh CLI). Options: github, gitlab
(uses the glab CLI) |
system_prompt |
No | Override the base system prompt sent to the model. When empty (the default) orangu uses its built-in coding-assistant prompt. The discovered Agent Skills index is appended to whichever prompt is in effect |
review_confidence_threshold |
No | Minimum confidence score (0–100) for
/auto_review findings; findings below this threshold are
silently dropped. Defaults to 80. Set to 0 to
disable filtering |
compression |
No | Enable the built-in compression layer:
context deduplication, file-read stubbing, and shell-output compression.
Defaults to on. Options: on,
true, 1, off, false,
0. See the Compression chapter |
auto_downsample_lines |
No | Line count above which an unbounded file
read is returned as signatures instead of the whole file, with a note
saying so. Defaults to 300; 0 reads every file
in full. Only applies while compression is on, and never to
a read that asked for a mode or a line range |
diff_file_cap |
No | Maximum number of files kept when a
git diff is compressed. Defaults to 20. See
the Compression chapter |
world_state_max_bytes |
No | Ceiling on the
world_state_changes fragment prepended to a turn when the
working tree has changed, in bytes. Defaults to 8192;
0 disables the cap. See Workspace change budget |
semantic_budget_tokens |
No | Token budget for the code chunks
/search injects into a turn. Hits are added in rank order
until the next one would exceed it, so the cap bounds what semantic
search costs in context rather than the number of results. Defaults to
16384; the top hit is always kept |
Workspace change budget
Every interactive turn taken after the working tree changed carries a
world_state_changes fragment describing the change. That
fragment is prefilled by the server, so its size is
response latency, not just context: on a small local model a few hundred
bytes cost milliseconds and a few hundred kilobytes cost minutes.
world_state_max_bytes is the hard ceiling on it. Raise
it if you want the model to see more of a large working diff without
asking; lower it if the first turn after each edit feels slow. Two lower
limits apply before it — untracked files above 4 KiB are announced
rather than inlined, and smaller ones are cut to 80 lines — so the
ceiling is rarely the binding constraint in an ordinary workspace. The
Compression chapter describes the whole path.
Response-token caps
review_max_tokens and code_max_tokens bound
how long a model response may get. Each is sent to the server as the
max_tokens field of the chat completion request, so the
server stops generating when the cap is reached — the request does not
fail, the response is simply cut off at that point. A value of
0 disables the cap entirely: no max_tokens
field is sent and the server’s own default applies. Like
timeout and max_tool_rounds, both keys are
client-wide and apply to every configured server.
The two caps cover the two kinds of request the client makes:
review_max_tokensapplies to every/auto_reviewrequest — the per-file category reviews and the final whole-change pass. The default of512fits the requested format (a verdict plus at most five one-line findings) comfortably, and exists so a review can never generate unbounded output: a runaway or endlessly deliberating model is cut off rather than stalling the run.code_max_tokensapplies to the normal conversation — prompts typed at the input window, including tool-calling turns. It defaults to0(no cap) because coding answers are open-ended: explanations, diffs, and file contents can legitimately be long. Set it only when a model tends to ramble or you want a hard latency bound per response. Note that0does not mean unbounded — it means the server chooses, andorangu-serveranswers with8192(see the HTTP chapter).
A cut-off answer says so. Whichever cap is reached,
the server reports finish_reason: "length" and
orangu prints
[answer cut off at the server's response-length cap …]
under the timings. This matters most on a tool-calling turn: a file’s
contents travel inside the tool call, and a call cut off
mid-argument never closes, so it is not recognised as a call at all —
nothing runs, nothing is written, and the half-finished file arrives as
ordinary text. If you see that notice where you expected a file, raise
code_max_tokens.
Reasoning (“thinking”) models need a larger review
cap. A model’s hidden thinking tokens count against
max_tokens, so with the default 512 a model
that deliberates at length can be cut off before it emits its verdict.
Such a truncated review is handled safely — a response with no verdict
and no findings is recorded under Overall as a failed
category review and the file keeps its white (unreviewed) box, so a
truncation can never silently approve a file — but the review is wasted.
When reviewing with thinking enabled, raise the cap so the answer
survives the thinking:
[orangu]
review_max_tokens = 2048Conversely, for the fastest reviews disable thinking on the server
(orangu-server --reasoning-budget 0 together with
--chat-template-kwargs '{"enable_thinking": false}') and
keep the default 512 — the cap then almost never binds and
only guards against runaways.
Themes
The global default theme is configured in [orangu]:
[orangu]
theme = classicBuilt-in themes are shipped inside the binary: classic,
modern_dark, modern_light,
oranguday, tokyonight, and
rosepine-moon. modern is accepted as a short
name for modern_dark.
random is not a palette of its own: it draws one of the
available themes — the shipped ones plus anything in
~/.orangu/themes — when it is applied, and holds it for the
rest of the run, so the UI never reshuffles mid-session. The
configuration or session value stays random, so the next
launch draws again.
A theme selects both a palette and a chrome — the screen furniture around the content:
chrome |
Frame |
|---|---|
classic (the default) |
The boxed ORANGU banner pinned to the top
of the screen, placed by the banner key; the output window
directly below it at full width; and full-width separators above and
below the input window |
modern |
The banner only on the empty landing screen; an inset output window; code blocks drawn in a box; and a rounded input box |
Both frames share the rest: the input window carries a bare
> prompt, and closes with the same status line, which
shows the branch on the left, a centered Graph: /
Pending: group, and the model name flush right.
classic and the modern_* themes differ only
in this: they are the same UI in the two frames, so
theme = modern_dark is the way to keep the Ratatui-native
look while theme = classic reproduces the original one.
Custom themes live in:
~/.orangu/themes/<name>.theme
A theme file is key = value lines. Colours are
#RRGGBB, or default to leave the terminal’s
own colour in place; styles accept fg:/bg:
colours plus bold, italic,
underlined and reversed. The
chrome key takes classic or
modern.
Every key is optional, and classic is the
base. Whatever a file leaves out keeps its classic value, so a
theme that only wants a different link colour is one line long:
highlight = fg:#66b2ffThat also means a palette-only theme never changes the layout by accident, and that adding a key in a later release never invalidates the theme files already on disk. A key that isn’t recognized is an error rather than a silent no-op, so a typo can’t quietly fall back to the classic value.
You can switch the current session with
/theme <name>. That writes a session override to:
~/.orangu/sessions/<UUID>/theme
Naming the theme orangu.conf already asks for drops the
session override instead of pinning a copy of it, so the session goes
back to following the global [orangu].theme. The command
completes built-in themes and user theme files. The startup option
-t/--theme <name-or-path> applies a
theme only for that process and takes precedence over the global and
session settings.
The session’s licence
The licence generated files are written under is a session setting
too, but it is not configured here: it is read from the
workspace — its manifest’s license field, then its
LICENSE/COPYING file, then MIT as the default
— and overridden for the session with
/license <spdx> [<holder>]. That writes:
~/.orangu/sessions/<UUID>/settings
as license and license_holder, beside the
session’s server and model, and is restored on
resume or when you switch back to that workspace tab.
/license auto clears it and /license none
turns headers off. See the Core tools chapter.
Server sections
Each server is a named section. The section name is what
[orangu].server points to, and it carries the host
information for that server:
[main-server]
endpoint = http://localhost:8100/v1
model = ggml-org/gemma-4-E4B-it-GGUF| Key | Required | Description |
|---|---|---|
endpoint |
Yes | orangu-server URL (its
OpenAI-compatible API) |
model |
No | Model identifier used in chat completion
requests. Overrides the general [orangu].model when
set |
api_key |
No | API key sent as
Authorization: Bearer <key> on every request to the
server. Required when orangu-server runs with
--api-key |
role |
No | A specific role this server fulfills.
Valid roles are: all (default), code,
review, explorer, and embeddings.
If a specific subsystem needs a server and one is tagged with its role,
it will use that server instead of the default. embeddings
designates the server that embeds code for semantic
/search; an all server also serves it, and
search auto-enables when that endpoint responds at startup. Ignored
behind a confirmed orangu-coordinator — it alone decides which model
backs each role, so a single server section is enough there |
model_verbosity |
No | How chatty this server’s model should be.
Defaults to normal. Options: terse,
normal, verbose. It is a per-server key:
writing it in [orangu] has no effect |
- At least one of
[orangu].modelor a server’s ownmodelmust be set, so every server resolves to a non-empty model - The endpoint may be configured either with or without
/v1 - The client normalizes the endpoint internally before calling
/v1/chat/completions - Set
api_keywhen the server requires authentication, for exampleorangu-server --api-key <key>. The key is sent as a bearer token on every request, including the/v1/modelsprobe - Each server section must use a unique
endpoint;http://xandhttp://x/v1are treated as the same host - Use
/serverto switch between the configured servers at runtime; Tab completion lists every server section - Set
feedback = onin[orangu]to show a green or red dot in the output window after each command completes, and to blink anorangu ●title and ring the terminal bell while/when a/auto_reviewruns and finishes
Sample file
The distributed sample lives at:
doc/etc/orangu.conf
It ships with orangu-server sections and a 30-minute
timeout suitable for local tool-calling workloads.
MCP servers
Use a [mcp.<name>] section, or set
mcp = true in a section, for an already-running Streamable
HTTP MCP service. The endpoint normally ends in /mcp.
[mcp.weather]
endpoint = http://localhost:9000/mcp
timeout = 30
approval_mode = writes| Key | Required | Description |
|---|---|---|
endpoint |
Yes | Streamable HTTP URL of the running
service, normally ending in /mcp |
mcp |
Only for the shortcut form | Set to on in a section that
is not named mcp.<name> to read that section as an
MCP service too. Options: on, true,
1, off, false,
0 |
timeout |
No | Seconds allowed for initialization, tool
discovery, and tool calls alike. Defaults to 30, and
supplies the default for the two keys below |
startup_timeout |
No | Seconds for connection and tool discovery
alone. Defaults to timeout. Must be greater than zero |
tool_timeout |
No | Seconds for a single tool call. Defaults
to timeout. Must be greater than zero |
enabled |
No | Whether the service is used at all.
Defaults to on. Options: on,
true, 1, off, false,
0 |
required |
No | Make a failed connection abort workspace
startup instead of disabling the service with a warning. Defaults to
off. Options: on, true,
1, off, false,
0 |
enabled_tools |
No | Comma-separated allowlist of tool names. Empty (the default) offers every discovered tool |
disabled_tools |
No | Comma-separated denylist of tool names.
The denylist wins over enabled_tools |
approval_mode |
No | How tool calls are confirmed. Defaults to
auto. Options: auto, prompt,
writes, deny |
The section name after mcp. is the service name used in
the mcp__<server>__<tool> prefix, and it
accepts ASCII letters, digits, _ and -.
Configuring the same name twice — once as
[mcp.<name>] and once through the
mcp = on shortcut — is a startup error.
approval_mode controls MCP execution: auto
runs tools directly, prompt asks for each call,
writes asks unless the MCP tool declares
readOnlyHint, and deny disables the service.
In the interactive terminal, answer an approval with y or
n; noninteractive and review runs deny calls that require
confirmation.
orangu connects to configured MCP services; it does not launch or
manage MCP processes. A failed service is disabled with a warning while
the rest of the session continues. MCP support is tools-only: resources,
prompts, sampling, elicitation, and tasks are deferred. Use
/mcp refresh to rediscover tools after a service changes
them; an interrupted connection is retried once.