Configuration
Nexrall Code configures itself through a .nexrall/ directory and a few well-known files, layered by scope so team settings, personal settings, and machine-local overrides coexist. This page maps the directory and the settings.json hierarchy.
The .nexrall/ directory
A project can carry a .nexrall/ directory at its root; a global copy lives at ~/.nexrall/. Files are discovered and merged at session start.
| Path | What it holds |
|---|---|
.nexrall/nexrall.md (or nexrall.md, NEXRALL.md) | Project-specific instructions, auto-included in every session. |
.nexrall/instructions.md / .nexrall/config.md | Alternate project-instruction filenames (first match wins). |
~/.nexrall/nexrall.md | Global instructions that apply to every project. |
.nexrall/settings.json | Project settings (permissions, model, etc.), shared with the team. |
~/.nexrall/settings.json | Your personal settings, across all projects. |
.nexrall/permissions.json | Permission rules (see Permissions). |
.nexrall/mcp.json | MCP server connections (see MCP). |
.nexrall/agents/ | Custom sub-agents (see Sub-agents & skills). |
.nexrall/commands/ | Custom slash commands. |
.nexrall/skills/ | Reusable skill playbooks. |
.nexrall/rules/ | Rule files loaded on demand — always-on, or scoped to matching paths (see Rules below). |
.nexrall/plugins/ | Installed plugins (see Plugins). |
.nexrall/checkpoints/ | File checkpoints for /rewind. |
.nexrall/memory.md | Persistent memory written via memory_write. |
.nexrall/cli-sessions/ | Saved CLI sessions. |
Project instructions: nexrall.md
The most-used piece of configuration. Run /init (or ask the agent in a session) to generate a nexrall.md at the project root — a short brief (tech stack, conventions, what to avoid) that's prepended to every session in that directory, so you don't repeat context each time.
Nexrall reads these candidate filenames for the project brief, in order (first match wins):
nexrall.mdNEXRALL.md.nexrall/instructions.md.nexrall/config.md
A global ~/.nexrall/nexrall.md applies to every project; persistent memory (project-scoped, keyed by working directory) is merged in alongside it.
Subdirectory instructions
A nexrall.md (or NEXRALL.md) in a subdirectory is picked up once the agent works with files under it — the same brief shape, scoped to the subtree. Conventions for one package can live in packages/cli/nexrall.md instead of bloating the root brief, and sibling subtrees stay untouched until they're worked in.
- Loaded on touch, then kept. A tool call touching a file under a directory loads that directory's brief from the next request onward; once loaded, it stays for the session. Creating one mid-session (the agent writing conventions as it works) behaves the same way.
- Order and budget. Several briefs apply parent-first (directories closer to the root first, then alphabetical). Each file is capped at 4000 characters, the whole block at 12000, and truncation is marked
[truncated]— a cloned-repo file cannot crowd out your root brief. - Scope.
.gitignored directories andnode_modulesare skipped, and the extra root candidates above (.nexrall/instructions.md,.nexrall/config.md) stay project-level only./reloadre-reads the nested files along with everything else. Each discovery fires theInstructionsLoadedhook withload_reasonnested_traversal, so plugins can audit what loaded and why.
Rules
.nexrall/rules/**/*.md holds rules that load as the agent works instead of living in the brief — organized per topic rather than as one growing file:
- Unconditional rules (no
paths:frontmatter) load at session start and stay for the session. - Scoped rules declare a
paths:list (aliasglobs:) and activate only when a tool call touches a matching path — including a file the agent creates — then ride the following request. A rule scoped topackages/api/**never activates while you work elsewhere.
---
paths:
- "packages/api/**"
- "**/*.graphql"
---
API conventions: validate every input, never add a dependency without
asking, and update the schema snapshot in the same change.Globs are anchored to project-relative paths and support **/ (zero or more directories), *, ?, {a,b} alternation and [abc] classes ([!abc] negates); an invalid pattern simply never matches. The scope rules and budget match subdirectory instructions: .gitignored directories and node_modules are skipped, each file is capped at 4000 characters, the loaded block at 12000, and truncation is marked [truncated]. Each load fires the InstructionsLoaded hook with load_reason session_start or path_glob_match. /reload re-reads everything from disk.
Settings hierarchy
Settings merge across tiers, and the tiers are layered so the most specific wins. The effective value of a setting is resolved in this order:
| Tier | Location | Scope |
|---|---|---|
| Managed (read-only policy) | managed-settings.json (macOS /Library/Application Support/Nexrall/, Windows %PROGRAMDATA%\Nexrall\, Linux /etc/nexrall/) | Highest — enforced organization-wide |
| User | ~/.nexrall/settings.json | You, across all projects |
| Project | <workDir>/.nexrall/settings.json | This repository |
For permission rules specifically, the precedence is inverted where it matters: deny always wins, then allow, then ask — a deny at any tier blocks the action regardless of an allow lower down.
settings.json shape
{
"permissions": {
"allow": ["Bash(npm run lint)", "Bash(npm run test *)"],
"ask": ["Bash(curl *)"],
"deny": ["Read(.env)", "Read(secrets/**)"]
},
"env": {
"NEXRALL_ALLOW_DESTRUCTIVE": "0"
}
}The permissions block is the main one (see Permissions for rule syntax). A hooks key and an env key can also live here — env exposes environment variables to the agent session.
UI settings
Everything you can change from inside a session with /config (or the command it hands off to — /livediff, /mouse, /notify, /vim, /output-style, /theme, /keybindings) lands here too, so it survives a restart and can be committed with the repo. The keys:
| Key | Values | Default | What it does |
|---|---|---|---|
liveDiff | true / false | true | Preview the lines each edit changes, as the agent works. |
mouse | true / false | true | Wheel scrolling in fullscreen mode. |
notifications | "auto" | "bell" | "osc" | "off" | "auto" | Terminal notifications for background jobs, long turns, and prompts waiting on you. |
editorMode | "vim" | (unset) | Vim-style editing in the input box — see Vim mode. |
outputStyle | "concise" | "explanatory" | "learning" | a custom style name | (unset) | How the agent answers. |
theme | "dark" | "light" | "auto" | "ansi" | "high-contrast" | "colorblind" | "none" | "custom" | a theme-file name | "dark" | Colours. auto follows the terminal (COLORFGBG); custom reads a themeColors block; a named theme reads ~/.nexrall/themes/<name>.json (or .nexrall/themes/ in the repo, or a plugin's themes/ — see Theme files). |
keybindings | { "<action>": "<key>" } | (unset) | Rebind a shortcut — command_palette, background_shell, task_panel, agent_panel, open_editor, history_search, expand_output, fix_failure, clear_screen, model_picker, effort_picker, prev_prompt, next_prompt. Enter, Esc, Tab and the arrows are fixed. |
axScreenReader | true / false | false | Screen-reader mode — flat labelled output, no spinner repaints, numbered menus. --ax-screen-reader and NEXRALL_AX_SCREEN_READER=1 override it; see Screen-reader mode. |
autoRecap | true / false | true | The one-line recap printed when a session is resumed (nex --resume / --continue) — last prompt, turns, tools, changed files, from the local event log. NEXRALL_AUTO_RECAP=0 forces it off; /recap prints it on demand. |
promptSuggestions | true / false | true | After each turn, a short background request proposes your next prompt as ghost text on the empty input row (Tab or → places it). Each shown suggestion is billed like a small turn; NEXRALL_PROMPT_SUGGESTIONS=0 forces it off, /suggestions off toggles it, and after 20 ignored in a row suggestions slow down until you use one. |
autoMode | object | {} | Auto-mode classifier config: classifier (default true), classifierModel, environment, allow, soft_deny/hard_deny (with $defaults), classifyAllShell, maxClassifications, maxBudgetUsd. Read from user/managed/--settings ONLY — project settings that set it are ignored. See Permissions → Auto-mode classifier. |
maxEffortLevel | low / medium / high / xhigh / max | (unset) | A CAP on the thinking-effort level, on every model (extra and ultra are accepted aliases of xhigh/max). The STRICTEST tier wins — a project file can only tighten it, never loosen what user/managed settings set. Applied at startup (incl. -e/--effort), /effort + the Alt+T picker and model switches; a value the ladder does not know is ignored with a one-line startup warning. |
requiredMinimumVersion / requiredMaximumVersion | string | (unset) | Managed settings only — an approved CLI version range for the organization. A client outside it exits at startup with a message naming both bounds; nex update, nex doctor, --help and --version keep working so users can recover. nex doctor shows a "Managed version" row whenever the range is set. |
worktree | object | {} | Worktree isolation options. worktree.baseRef is "fresh" (default) or "head": fresh starts a new --worktree/agent-isolation tree from the remote default branch (origin/HEAD, falling back to origin/main / origin/master, then local HEAD when there is no remote), so unpushed commits stay out of the isolated tree; head restores the old behaviour of branching from local HEAD. An unknown value behaves as fresh. |
worktreeHooks | object | {} | Shell commands for a non-git VCS (SVN, Perforce…): create / enter / exit. When create is defined it takes priority over the built-in git backend; it runs at worktree creation and must create the directory it finds in $NEXRALL_WORKTREE_PATH (exit 0 required). Each phase runs in the main checkout with a 60 s timeout and NEXRALL_WORKTREE_NAME / NEXRALL_WORKTREE_PATH / NEXRALL_MAIN_CHECKOUT set; the exit hook owns removing its own directory. See Environment variables. |
/config writes to your user settings by default; add --project to any of these (/vim on --project, /config liveDiff=off --project) to save it in the repository instead, for the whole team.
{
"editorMode": "vim",
"liveDiff": false,
"notifications": "osc",
"keybindings": { "command_palette": "ctrl+p" }
}Theme files
Besides the built-in themes (/theme lists them), you can define named themes as JSON files — one theme per file, the file name is the theme name:
{
"base": "dark",
"colors": {
"red": "ansi256:203",
"cyan": "#22d3ee",
"dim": "#8b93a1"
}
}basepicks the preset to build on:dark(default),light,ansi,high-contrast,colorblindornone.colorsoverrides individual slots; values are#rrggbb,ansi256:<0-255>,none, or chalk names joined with.(e.g.bold.red) — the same shape asthemeColors.- Optional
label/detailset the picker text.
Then /theme midnight switches to it (and saves "theme": "midnight"), or put "theme": "midnight" in a settings file directly. Files are read from three places, later winning a name clash:
| Where | For |
|---|---|
<plugin>/themes/<name>.json | plugins shipping a theme (disabled plugins contribute nothing) |
~/.nexrall/themes/<name>.json | your themes everywhere (NEXRALL_THEMES_DIR overrides the directory) |
<repo>/.nexrall/themes/<name>.json | a team theme, committed with the repo |
A file that fails to parse (bad JSON, unknown key, bad colour, a name that collides with a built-in) is reported and skipped — /theme prints the problem with its file name rather than half-applying it. Naming a theme that is not installed behaves like a missing setting: the session says so and falls back to dark.
Next steps
- Permissions — the
allow/ask/denyrule syntax in detail. - Environment variables — the
NEXRALL_*variables. - Sub-agents & skills —
.nexrall/agents/and.nexrall/skills/.