Configuration
Where Luxe's files live, what a project can set, and every key in config.json.
Luxe works with no configuration. Everything here is optional, and most of it can be set from inside
Luxe: Configuration (on the start screen, or /config) signs you in and opens these files in
your editor, /settings changes the settings you use most, /theme sets the theme,
and /model the model.
Files
Your own files live in ~/.config/luxe/ (%APPDATA%\luxe on Windows). A project can have its own
in .luxe/ at its root.
| File | Holds | In a project |
|---|---|---|
config.json | Appearance, behavior, and the settings on this page | .luxe/config.json, over yours |
keybindings.json | Your keys; see Commands and keys | .luxe/keybindings.json, over yours |
models.json | Model and provider settings; see Custom providers | |
auth.json | Credentials; see Models and providers | |
permissions.json | What the agent may do; see Security | .luxe/permissions.json, which can only tighten yours |
hooks.json | Commands run at points in a turn; see Hooks | .luxe/hooks.json, only with --trust-project |
mcp.json | MCP servers; see MCP | .luxe/mcp.json or .mcp.json |
lsp-servers.json | Language servers; see Tools | |
debug-adapters.json | Debug adapters; see Tools | |
agents.md | Instructions for every project; see Project context | AGENTS.md |
themes/ | Your own themes; see Appearance | |
skills/ | Your own skills; see Skills | .luxe/skills/ or .agents/skills/ |
LUXE_CONFIG_DIR moves the whole directory, and every file in it.
What a project cannot change
A project’s .luxe/config.json overrides yours key by key, with a few exceptions. These run
programs, reach the network, or decide what a repository is trusted with, so Luxe reads them from
your own config only:
launchersandmentions, which run programsupdate, andgithub.refresh_secslsp.project_serversagent.on_ask, which a project can set todenybut not toallowagent.cache_warming, which a project can turn down but not up, since it spends your money
Project gate.commands also run programs. Luxe ignores them and warns unless you start with
--trust-project. With trust, a nonempty project list replaces your global list. Otherwise, the
loop uses your global commands. Move the list to your own config if you don’t want to trust the
project.
Editing
luxe init asks the first run’s questions again (a theme, a provider, the tools, and the start
screen) and writes the answers to config.json, changing only those keys. It also writes a
config.schema.json beside it so your editor can complete and check every key. --defaults writes
a file that chooses nothing, without asking, and so does a run with no terminal; with a
config.json already there, either one needs --force, which removes the old file first. Luxe ignores a key it does
not know, so an old config always loads on a newer Luxe; check the spelling if a setting seems to
do nothing.
/reload (ctrl+shift+r) applies changes to config.json and keybindings.json without
restarting.
Settings
/settings, or Settings in Configuration, shows the settings you are most likely to change
as controls, on five pages: Appearance, Conversation, Dock & statusline, Tools, and Agent. Each
change writes one key to your config.json and leaves the rest of the file as it was.
| To | Key |
|---|---|
| Choose a setting | ↑ / ↓ |
| Turn it on or off, or step to the next choice | space, enter or → |
| Step back a choice | ← |
| Remove it from your file, so the default applies | r |
Open config.json in your editor | e |
| Search every page | / |
| Change page | tab, or 1 to 5 |
Each value says where it comes from: default, global (your config.json), or project (this
project’s .luxe/config.json, which wins over yours, so it is changed there). Most settings take
effect at once; the rest say they take effect the next time Luxe starts. That includes the Tools
page, because the tools the agent is offered are fixed for a run. In a window too small for the
panel, it says so instead, and only esc works until the window fits.
Behavior
Notifications
{ "notifications": true, "bell": false }notifications sends a desktop notification while the terminal is in the background, when a turn
finishes or fails, a tool call waits for your approval, the agent asks you a question, or a Guided
Review finishes writing its guide. To pick some of those, list them:
{ "notifications": ["permission", "question"] }| Name | When |
|---|---|
turn | A turn finished or failed |
permission | A tool call is waiting for your approval |
question | The agent asked you something |
review | A Guided Review finished writing its guide |
bell rings the terminal bell at each of those moments. Both are off by default. Many terminals
turn a bell into a request for the window manager’s attention, which can pull focus from what you
are doing.
The notification goes through your terminal, as an escape sequence it turns into a desktop
notification, so it works over ssh and needs nothing installed. Ghostty, iTerm2, kitty, WezTerm,
Warp and foot show them; Luxe recognizes those and sends nothing to a terminal it does not know. If
yours shows them and Luxe does not recognize it, name the sequence: "notification_method": "osc9"
(the common one) or "osc777". Inside tmux, add set -g allow-passthrough on to your tmux
configuration. Your terminal may also have to be allowed to send notifications in your system’s
settings.
herdr
Inside a herdr pane, Luxe tells herdr whether it is working, idle, or waiting
on you, and why: Approve bash, or the question it asked. herdr shows that in its sidebar, raises
its own notification when Luxe finishes or needs you (set in herdr’s [ui.toast]), and reports it
to herdr agent wait. After a herdr restart, the pane reopens the same session with
luxe --resume. Luxe sends no escape-sequence notifications inside herdr, because herdr keeps
them for itself.
Recipes has a Luxe palette for herdr’s theme.
This is local to your machine and on by default. Outside herdr nothing is sent.
LUXE_HERDR=0 in the environment stops the reports, and so does the config:
{ "herdr": false }Update notice
Once a day, Luxe checks whether a newer release exists and says so on the start screen, with the command to update. Luxe never updates itself. The check sends nothing about you or your machine; the comparison happens locally.
{ "update": { "check": false } }LUXE_UPDATE_CHECK=0 turns it off as well.
Launchers
A launcher gives a key to a program that takes over the terminal and gives it back, such as gh-dash or lazygit:
{
"launchers": [
{ "key": "alt+g", "command": "gh-dash" },
{ "key": "ctrl+alt+l", "command": "lazygit" }
]
}Luxe keeps running underneath and redraws when the program exits. Text the program writes to the
file named by $LUXE_HANDOFF is put in the composer, so a gh-dash command can send
#123 look at this to Luxe. A launcher’s key wins over any other binding.
Reference
Every key in config.json, with its default.
| Key | Default | Does |
|---|---|---|
theme | your Omarchy theme, else luxe | The theme; see Appearance |
colors | Single color overrides; see Appearance | |
glyphs | auto | Which icons to draw; see Appearance |
images | auto | How images are drawn; see Appearance |
mouse | true | Capture the mouse; see The interface |
dashboard | true | Open on the start screen. false skips it; { "style": "minimal" } shows the prompt alone. |
banner_animation | true | The shine across the start screen’s logotype |
show_key_hints | true | The key hint beside messages waiting for a turn |
notifications | false | Desktop notifications: true, or a list of moments; see Notifications |
notification_method | auto | auto, osc9 or osc777 |
bell | false | Terminal bell when a turn ends or something waits on you |
herdr | true | Report the agent’s state to herdr; see herdr |
statusline.visibility | auto | auto, shown or hidden; see Appearance |
statusline.style | slab | slab or flat |
statusline.left | ["project", "branch", "pr", "todo", "changes"] | Modules on the left |
statusline.right | ["context", "cost", "tokens", "thinking", "model"] | Modules on the right |
statusline.thinking_colors | false | Color the thinking level |
dock.mode | auto | auto, shown or hidden; see The interface |
dock.position | left | left or right |
conversation.alignment | full | full, left or center; see Appearance |
conversation.prose_max_width | 120 | Text width under left or center |
conversation.wide_block_max_width | 140 | Code and table width under left or center |
conversation.growth | bottom | bottom or top |
conversation.thinking | shown | shown, collapsed or hidden |
conversation.tool_runs | fold | fold or cards |
conversation.tool_details | errors | errors, all or collapsed |
conversation.stream_reveal | smooth | smooth or off |
conversation.activity_bar | bars | bars, dots or off |
conversation.scroll_lines | 3 | Lines per wheel notch, 1 to 20 |
conversation.image_max_rows | 24 | Tallest image, in rows |
diff.layout | auto | auto, split or unified; see Appearance |
diff.word_wrap | false | Wrap long lines in Guided Review |
review.exclude | [] | Files every review leaves out; see Guided Review |
review.context_files | [] | Extra files a review reads for what the change was for, beside PLAN.md and AGENTS.md |
tools.disabled | [] | Tools to turn off; see Tools |
tools.format_on_save | true | Format each file the agent changes; see Tools |
tools.clone_repositories | true | Clone a GitHub repository web_fetch is given; see Tools |
lsp.project_servers | auto | auto, always or never; see Tools |
compaction.auto | true | Summarize when the window fills; see Sessions and context |
compaction.at | 0.9 | How full before summarizing |
compaction.keep_recent | 20000 | Tokens kept word for word |
compaction.reserve | 20000 | Tokens held back for the reply |
compaction.prune | true | Replace old tool output first |
compaction.summarizer | the session’s model | The model that writes the summary |
agent.default_mode | build | The mode a session starts in: build or plan; see Plan, then build |
plan.files | ["PLAN.md"] | Files or globs plan mode may write; the first plain file gets the plan, or a file matching the first glob |
plan.model | the session’s model | Plan mode’s model, as provider/id; switching to it re-reads the conversation at full price |
plan.thinking | the session’s | Plan mode’s thinking level |
reviewer.model | the session’s model | The model /review and the loop’s gate ask; see A second opinion |
reviewer.thinking | the session’s | The reviewer’s thinking level |
reviewer.tools | read-only tools | Tools a review may call; whatever you list, a review changes nothing |
agent.remember_model | true | Start on the model you last chose |
agent.max_tool_iterations | none | Most rounds of tool calls in one turn |
agent.on_ask | allow | What a permission prompt becomes with nobody to answer; see Autonomous runs |
agent.cache_warming | streaming | off, streaming or idle; see Keeping the cache warm |
gate.commands | [] | Commands a phase must pass; see Autonomous runs |
gate.timeout_secs | 600 | Longest one gate command may run |
gate.review | on when reviewer.model is set | Have a reviewer read each phase after the commands pass |
worktree.always | false | Give every session a worktree; see Git and GitHub |
github.refresh_secs | 60 | Seconds between pull request checks; see Git and GitHub |
github.sections | What /github lists | |
update.check | true | Look for a newer release |
launchers | [] | Keys that open other programs; see Launchers |
mentions | [] | Your own @ sources; see Mention sources |