Nexrall CLI
The Nexrall CLI brings the coding agent to your terminal — scriptable, headless, and suited to CI pipelines and automation. It runs the same agent engine as Nexrall Code for VS Code and Nexrall Work.
Install
npm install -g nexrall-codeThe binary is called nex. Then run it from any project directory:
nexInteractive use
Running nex with no arguments starts an interactive session in your current directory — describe what you want, and the agent reads the project, edits files, and runs commands just like in VS Code.
Running nex "some prompt" starts the same interactive session but with your first message already sent, so you can watch it work and keep chatting afterward.
Startup flags
| Flag | What it does |
|---|---|
-m, --model <name> | Explicit model id — e.g. claude-opus-5-5, gpt-6-sol, deepseek-flash. Without it, the session adopts your account's default model (see Models). |
-d, --dir <path> | Working directory (default: current directory). |
-r, --resume [id] | Resume the last session, or a specific saved session id. A one-line recap of where it left off prints on arrival (disable with the autoRecap setting). |
-y, --yolo | Auto-approve every tool call — no permission prompts. |
--ax-screen-reader | Screen-reader mode: flat labelled output, no spinner repaints, numbered menus. See Screen-reader mode. |
--no-banner | Skip the ASCII banner (useful in scripts/pipes; automatic when input is piped). |
--output-format <fmt> | One-shot machine-readable output: text | json | stream-json — see Headless / CI use. |
Those are the everyday flags — the complete flag and command list is in the CLI reference; Interactive mode has the full key map.
Piped input
If you pipe data into nex, it's read up front and handed to the agent as part of the turn — useful for feeding it a diff, a log, or any command's output directly:
git diff | nex "review this change for bugs"
cat error.log | nex "what's causing this crash?"Files & images
Type @ in a message to pick a file or folder from a list — what you choose is attached to that message. /image <filepath> attaches an image or PDF, and Ctrl+V pastes an image straight from the clipboard, so a screenshot can go into the conversation without saving it to disk first.
The first Ctrl+C with text in the box doesn't exit — it clears the draft and stashes it, saying so on the hint line (Draft cleared · ↑ restores it). Press ↑ on the empty prompt and the text comes back, ahead of history recall. Ctrl+C on an already-empty prompt exits.
Vim mode
Turn it on with /vim (or "editorMode": "vim" in settings.json) and the input box becomes a small vi. It's the subset that matters on a one-line prompt — motions, counts, operators, and repeat:
| Keys | What they do |
|---|---|
Esc, then i a I A o O | NORMAL mode, and back to INSERT. The prompt shows [N] while in NORMAL. |
h l 0 ^ $ w b e | Motions, with counts (3w). j/k move between the lines of a multi-line draft. |
x X dd D C dw cw yy p P u | Edits, counts included (2dd, d2w). Words are whitespace-delimited, so a path is one word. |
v / V | Visual mode, charwise / linewise — the span is highlighted. Then d x c y p P, and o to swap ends. |
. | Repeat the last change, with its inserted text (. , 2.). |
Everything else keeps working: Enter still sends, arrows and Ctrl-chords still do their usual thing, and history/Ctrl+R are unaffected — a keystroke only counts as vim when the modal handler consumes it.
Screen-reader mode
A terminal screen reader (VoiceOver, NVDA, Orca) reads whatever the terminal writes, in order. The normal UI is hostile to that: box-drawing frames, a spinner that repaints ten times a second, lines rewritten in place, and things that only make sense if you can see the layout. Screen-reader mode replaces all of it with flat, labelled, line-at-a-time output:
nex --ax-screen-reader # this run
NEXRALL_AX_SCREEN_READER=1 nex # this shell/CI job{ "axScreenReader": true }Precedence: flag > NEXRALL_AX_SCREEN_READER > the axScreenReader setting.NEXRALL_AX_SCREEN_READER=0 forces the mode off even when the setting is on (handy when a profile enables it and one script needs the normal UI). The first line printed tells you which one won:
[Screen Reader Mode: on via flag]What changes once it's on:
| Surface | Normal | Screen-reader mode |
|---|---|---|
| Banner | Two-column bordered card with the ASCII logo | One fact per line, no frame, no logo |
| Your messages | Echoed with the > prompt | you: <line> |
| Replies | Styled markdown | claude: on its own line, then flat text |
| Reasoning | ✻ Thought … | thinking: Thought … (no animation) |
| Tool calls | ⚡ + coloured name | tool: <name> <arg> / tool error: <what failed> |
| Status line | Spinning frame, elapsed seconds, token counter | The label alone, and only when it changes — no repaints |
| Choice menus | Box navigated with arrow keys | Numbered list + Select with numbers (1-N) or press Ctrl+C to cancel |
| Yes/no prompts | Two-option menu | Type y / n (yes / no also work) |
| Code blocks | Fenced with ┌─ / └─ | Indented plain text |
| Tables | Box-character grid | One Header: value, Header: value line per row |
| Horizontal rules, bullets, checkboxes | ─, •, ✓ | blank line, -, [x] |
| Input box rules | Two ─ rows bounding the prompt | Two blank rows (the layout height is unchanged) |
| Startup | Banner lands immediately | Banner waits NEXRALL_AX_STARTUP_QUIET_MS (default 3000 ms, cap 10 min) so the confirmation line is heard first; any key skips the rest of the wait |
| Bell | Per /notify | Rings when a reply finishes, when a prompt is waiting on you, and when a tool that ran over 5 s finishes |
A number answers a menu, the option's own letter still works, and an answer that isn't a valid option asks again with the valid range instead of guessing — which matters most for permission prompts, where the wrong guess approves a file edit.
Not implemented on purpose (so the docs don't promise them): OSC 133 shell integration markers, per-character echo of the input line, announced deletions, and NEXRALL_AX_PREPARK_MS (CC's cursor park — our output is written by Ink's frame writer, so there is no point where we hold the cursor before a line write; the knob is absent rather than a silent no-op). Headless output is unchanged by this mode.
Slash commands
The table below is the set you'll reach for most. /help inside a session lists every command your installed version has, and Slash commands documents the complete set:
| Command | What it does |
|---|---|
/model [name] | Show or switch the model (e.g. claude-opus-5-5, gpt-6-sol). |
/mode [ask|edit|plan|auto] | Show or switch the agent mode. |
/effort [low|medium|high|extra] | Show or switch the thinking-effort level. |
/resume [id] | Resume the last session, or a specific saved session. |
/recap | Where this session left off: last prompt, turns, tools, changed files (rebuilt from the local event log). |
/cd <dir> | Move this session to a different working directory (trust-gated; ~ and relative paths work; the session is re-stamped so --continue lists it in the new folder). |
/suggestions [on|off] | Prompt suggestions: ghost next-prompt after each turn — Tab (or →) places it, typing dismisses it; a small background request per suggestion. |
/sessions | List saved sessions. |
/save | Save the current session immediately. |
/clear | Clear the conversation and start a fresh session. |
/rewind [id] | List file checkpoints, or roll back to one — reverts both the files and the conversation to that point. |
/compact | Manually summarize the conversation to free up context (this also happens automatically as a session grows). |
/init | Generate a nexrall.md (project-specific instructions) by analyzing your project. |
/add <filepath> | Add a specific file's contents to the conversation context. |
/balance | Show your current wallet balance. |
/stats | Usage across sessions from this machine's local event logs — activity by day, tokens, models — plus this session's run. /cost remains the per-session breakdown. Costs are whatever the server reported per request; days or requests without one are named as such, never estimated. |
/yolo | Auto-approve all permissions for the rest of the session. |
/commands | List custom skills and commands (from .nexrall/commands/*.md, skills and plugins). |
/code-review [target] [deep] [--max-findings <n>|all] [--comment] [--json] | Review the working tree, a git ref, a PR/MR number or a path with a fresh-context, read-only reviewer sub-agent: findings with file:line, severity, why and a fix sketch. --comment posts them as ONE comment on the PR/MR; --json emits the machine-readable report. From the first-party code-review plugin; the built-in /review stays the local risk listing that never calls a model. |
/doctor | Check the setup — Node, sign-in, network, terminal, MCP servers, storage — with a fix beside every problem. The same checks as nex doctor. |
/config [key[=value]] | See and change settings (live diff, mouse, notifications, output style, vim mode) in one place — --project saves to this repo. |
/output-style [name] | Change how the agent answers: concise, explanatory, learning, or your own style file. |
/goal <condition|clear> | Keep working until a condition is met — a judge checks after every turn. |
/loop <interval> <prompt> | Re-run a prompt on an interval while the session is idle (min 1m, expires after 7 days); /loop list, /loop stop <id|all>. |
/share [off|drive on|drive off] | Watch this running session live from the web app — your account only, nothing stored on the server. Prints the watch link; /share drive on also lets the watcher type and answer prompts; /share off stops. See Watch a session from the browser. |
/channel [open [auto|ask]|close|accept [n]|discard [n]|auto|ask] | The door between this session and the outside: CI jobs and webhooks push a message into it, and the pusher can read the turn's answer back (nex channel push --wait). Pushes wait for your /channel accept unless you open with auto. See Push messages into a running session. |
/schedule [add <interval> <task>|pause|resume|run|rm|runs] | Cloud schedules — recurring tasks that run on Nexrall's servers (alias /routines). Unlike /loop, they keep firing with this laptop closed — see Cloud schedules. |
/batch <instruction> | Split a mechanical change across parallel agents, each in its own git worktree. |
/subtask <task> | Fork this conversation into a background agent: it starts from everything said so far, works while you keep typing, and reports back into the session when it is done — see Forked sub-agents. |
/btw <question> | Ask a side question — answered without touching the conversation. |
/add-dir <path> | Let the agent work in another directory for the rest of the session. |
/hooks | List the hooks that will run (project, --settings, plugins). |
/reload | Re-read skills, plugins and the project brief (nexrall.md) without restarting. |
/import [--user] [--apply] | Bring your Claude Code setup (.claude/, CLAUDE.md) across — dry run unless --apply; never overwrites. |
/vim [on|off] | Vim-style editing in the input box: Esc for NORMAL, v/V for visual mode, . to repeat — see Vim mode. |
/trust | Show what in this folder can configure the agent. Trust is per-session and never saved — you confirm again next launch, so a newly added .nexrall/mcp.json can never run un-announced. Only the NEXRALL_TRUST_WORKSPACE env var (set by the invoker, never committable) skips the prompt. |
/mcp [name] | List MCP servers and their state, or inspect one. /mcp auth <name> signs in to a remote server that needs OAuth; enable/disable (or on/off) and connect/disconnect act on one server. /mcp resources lists resources (files, docs, records) the connected servers expose — the agent can read them too; /mcp prompts lists the servers' prompt templates, which you run as /<server>:<prompt> args… from the same / menu. |
/plugins | List installed plugins. |
/update | Update nex to the latest version. |
/help | Show this list. |
/exit, /quit | Exit (auto-saves the session first). |
Project instructions: nexrall.md
Run /init (or ask for it in a session) to generate a nexrall.md file at your project root — a short, project-specific brief (tech stack, conventions, what to avoid) that's automatically included in every session started in that directory, so you don't have to repeat context every time.
Checkpoints & rewind
Every file-modifying turn is checkpointed automatically. /rewind lists them and lets you roll back to any point — both the files on disk and the conversation history revert together, so you can safely try an approach, decide it was wrong, and get back to exactly where you were.
If a rewound turn ran shell commands, those side effects are not automatically undone (the CLI can't know how to reverse an arbitrary command) — /rewind tells you when this applies and, if it touched a git repo, gives you a recovery hash from a snapshot taken right before the command ran.
Sessions & the event stream
Sessions are saved automatically and managed from outside the chat:
| Command | What it does |
|---|---|
nex sessions | List saved sessions (id, title, last used, directory). |
nex sessions --events <id> | Print the session's event stream: one line per thing that happened — prompt, tool call and outcome, file change, checkpoint, compaction, end. --json prints the raw records; --last <n> widens the window. |
nex sessions --export <id> [--out <file>] | Hand a session to another machine or client as a portable bundle (conversation + event stream). |
nex sessions --import <file> | Bring such a bundle in; continue it with nex --resume <id>. |
nex sessions --delete <id> / --clear-all | Remove sessions (a session's event stream goes with it). |
An <id> may be the full id or any unique prefix — the list shows the first 8 characters, and that short form works everywhere (--resume, --export, --events, --delete). An ambiguous prefix is refused rather than guessed.
The event stream is the record other clients read (VS Code, the web app), so it also covers background housekeeping: an automatic context compaction is written as context.compacted, and the summary line says which kind it was — compacted 42 → 17 messages (auto). Set NEXRALL_EVENTS=off to keep a run from being recorded.
Usage export & telemetry
Two ways to get usage out of the CLI: a pull-based report you can run at any time, and a live push to your own OpenTelemetry collector.
nex usage export
Reads the local event stream (the same record /stats shows) and prints cost, tokens and tool activity — per session, with model and tool rollups:
| Command | What it does |
|---|---|
nex usage export | Every session, as JSON (the default — scriptable). |
nex usage export --format jsonl / --format csv | JSONL (a meta line + one line per session) or CSV (one row per session, spreadsheet-friendly). |
--since 7d / --until 2026-10-01 | Limit the window — 7d, 48h, 90m, 2w or a date. Rows outside it are trimmed; files whose last write is older than --since are skipped outright. |
--session <id> | One session only. |
--limit <n> / --all | How many log files to read, newest first (default 500). When the cap bites, the report says "truncated": true — it never quietly exports a subset. |
--out <file> | Write the report to a file instead of stdout. |
Two honesty rules carry over from /cost: a finished turn whose cost was not reported is counted as costMissing — never as $0 — and a turn without its own model is attributed to the session's last message.started, then unknown. Exit codes: 0 success (an empty report is still success), 1 session not found, 2 bad flags.
nex usage export --since 7d --format csv --out report.csvLive telemetry (OTLP)
Point the CLI at your own OpenTelemetry collector to watch a session as it works. Telemetry is off unless you ask for it:
export NEXRALL_ENABLE_TELEMETRY=1
export OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.example.com # or http://localhost:4318
nexWhat is exported:
- Logs — one OTLP record per session event, body
nexrall.<event-type>(tool outcomes, turn ends; failures atWARN). - Metrics (delta) —
nexrall.session.count,nexrall.token.usage{model},nexrall.cost.usage{model},nexrall.tool.calls{tool,outcome}.
The standard OTEL_* names work — OTEL_EXPORTER_OTLP_* (endpoints, headers, protocol), OTEL_LOGS_EXPORTER / OTEL_METRICS_EXPORTER (including console), OTEL_LOGS_EXPORT_INTERVAL / OTEL_METRIC_EXPORT_INTERVAL — and NEXRALL_OTEL_ENDPOINT / NEXRALL_OTEL_* win where both are set. Transport is OTLP over HTTP/JSON; grpc is refused with a note at startup rather than silently dropped. A failed POST is re-queued for the next export window.
Privacy: prompt text and tool details are stripped by default. Opt in with NEXRALL_OTEL_LOG_PROMPTS=1 and/or NEXRALL_OTEL_LOG_TOOL_DETAILS=1 (the Claude Code names OTEL_LOG_USER_PROMPTS / OTEL_LOG_TOOL_DETAILS work too). Exporter notes go to stderr only, so headless JSON output stays pure.
Watch a session from the browser
/share mirrors the running session's event stream to Nexrall's relay, so a watcher in the web app follows it live — it prints the link (https://app.nexrall.com/live/<session-id>), and /share off stops. The same relay and viewer follow cloud coding sessions, and a headless run can publish itself with the --share <id> flag. It is deliberately account-scoped: only your account can open the stream, the relay stores nothing, and it needs a signed-in account (nex auth). It follows the event stream above, so NEXRALL_EVENTS=off turns sharing off with it. The connection is lossy by design: frames published while it is down are dropped rather than buffered, and when it heals the publisher re-pushes the tail while a late-joining viewer pulls what it missed — together with a fresh hello, so the metadata and the drive switch it sees are current, not whatever they were when the link was printed.
By default a watcher can watch, never type. /share drive on lends the viewer the keyboard: the account's web app can send lines and answer mirrored permission prompts while a turned-off switch refuses every frame with a note in the viewer. The terminal stays the authority for every gate:
- Only prompts the web can render in full (exact preview text included) are answerable, and only with Yes/No — the "always / don't ask again" choice never leaves the terminal. Destructive typed-
yesconfirmations are shown for visibility but answered locally. - A remote answer races the local choice box — first answer wins, the loser is withdrawn, and stale answers are refused.
- A typed line behaves exactly like a locally typed one: refused while a prompt owns the input, queued while a turn runs (if it is prose; commands are never queued), and echoed into the local transcript.
The switch lives on the share, not the session: /share off (or leaving the session) turns drive off with it, and every reconnect re-announces the current state so a stale tab cannot type into a session it no longer follows.
Push messages into a running session (channels)
/share is the outbound door — you watch the session. /channel is the inbound one: CI jobs, webhooks and scripts push a message into a live session. /channel open mints a push token and prints the per-session endpoint; the terminal decides what a push may do:
/channel open # ask policy (default): pushes wait for you
Channel open — anything that can POST can reach this session:
https://api.nexrall.com/api/cli-sessions/<id>/push
header x-channel-token: nxch_… (shown once — only its hash is stored)
/channel accept # deliver the oldest waiting push as a turnFrom anywhere that can POST — a CI job, a webhook receiver, a script:
curl -X POST https://api.nexrall.com/api/cli-sessions/<id>/push \
-H "x-channel-token: nxch_…" -H 'content-type: application/json' \
-d '{"text": "main is red: 3 failing tests", "source": "ci"}'The answer comes back. A push is owed the closing text of the turn that consumed it — read it with the same token, or let the CLI wait for you:
nex channel push --url https://api.nexrall.com/api/cli-sessions/<id>/push \
--token nxch_… --source ci --wait "main is red: 3 failing tests"
# …prints the turn's answer when it lands.
# exit 0 answered · 3 the person there discarded it · 4 still pending (timeout)curl https://api.nexrall.com/api/cli-sessions/<id>/push/<nonce> \
-H "x-channel-token: nxch_…"
# {"ok": true, "status": "accepted", "reply": "…", "completedAt": …}Rules that matter:
- Off by default,
askby default. Pushes park in a bounded queue (10 held)./channel accept [n]delivers one as a turn,/channel discard [n]refuses it,/channel autodelivers on arrival (and drains what is already queued, oldest first),/channel askgates again. - The token never leaves the terminal. The relay stores only its sha256;
/channel closerevokes the door, leaving the session closes it, and the mapping expires after 12 h as a backstop. - A push is text, delivered like a typed line — it reaches the model wrapped as
<channel source="ci" ts="…">…</channel>, never as a slash command or a!shell, and it can never answer a permission prompt by itself. A push that arrives mid-turn folds into the running turn as a follow-up. - The door follows the session:
/clearand/forkkeep it open with the same token. Unknown or expired endpoints 404 uniformly, and per-token rate limits (20 burst, then 0.2/s) keep a runaway source from burying the one message you need. - Every push gets an answer, or a named silence. The reply is the turn's closing text (produced after its last tool call), clamped rather than dropped (
replyTruncated); a turn that produced no text is an explicitnoText, an interrupted one carriesinterrupted. Results are readable only with the channel token — the same trust boundary as push — and a web watcher holding the same account cannot fabricate one.
Headless / CI use
For scripts and CI pipelines, pass a prompt directly and get structured output:
nex --dir ./my-project --model claude-opus-5-5 --output-format json --no-banner \
"Fix the failing test in src/utils"--output-format supports:
json— a single JSON object at the end:{ result, tool_calls, usage }.stream-json— one JSON object per line as the agent works (tool calls, tool results, text, final result) — useful for piping into another process that wants to react as it happens. The first line is a{"type":"system","subtype":"init"}event carrying thesession_id,cwd,modeland the tool set for the run, so a consumer can learn the context before the first token. Add--include-partial-messagesto also stream model deltas ({"type":"stream_event",…}), and--replay-user-messages(with--input-format stream-json) to have each stdin message echoed back as a{"type":"user",…}event the moment it becomes a turn. Add--include-hook-eventsto watch hooks fire as they happen (see Hooks — observing hook runs).
Passing --output-format on its own implies auto-approve, since there's no one to prompt for permission in a non-interactive run. To keep control, add --permission-mode — then anything the mode would have asked about is denied instead of approved. Or hand the decision to an MCP tool with --permission-prompt-tool (below).
Scripting flags
| Flag | What it does |
|---|---|
--permission-mode <mode> | ask, edit, auto, plan — or the Claude Code names default, acceptEdits, bypassPermissions. In a headless run, whatever would prompt is denied. |
--allowedTools <rules...> / --disallowedTools <rules...> | Allow or deny tools for this run, e.g. --allowedTools "Bash(npm test:*)" Edit. Deny always wins. Put the prompt before these flags. |
--append-system-prompt <text> | Extra instructions added to the project brief. |
--add-dir <dirs...> | Extra directories the agent may work in. Must exist. |
--max-budget-usd <n> | Stop once the run has spent this much. Exit code 2; the result carries cost_usd and "stopped":"budget". |
The json/stream-json result line also carries total_cost_usd whenever the server reported any cost (absent — never an invented 0 — when it did not), and each streamed usage event carries the server's per-call cost when reported. | --json-schema <schema> | JSON Schema (inline or a file) the final answer must satisfy. The result gains structured_output; if it does not validate, schema_error is set and the exit code is 3. Supports type, enum, const, properties, required, additionalProperties:false, items, length/range limits, anyOf/oneOf; any other keyword (such as $ref or pattern) is reported as unsupported rather than ignored. | | --input-format stream-json | Read Claude Code-style NDJSON {"type":"user","message":{…}} lines on stdin. Each line is its own turn, run in order, and later turns see the earlier ones. | | --mcp-config <files-or-json...> | Load MCP servers for this run. Add --strict-mcp-config to use only those. | | --bg | Run the prompt in the background and return a job id (see Background jobs). | | --exec <command> | With --bg: run this raw shell command instead of an agent prompt. | | --no-session-persistence | Don't save the run to disk (it can't be resumed). | | --max-turns <n> | Stop after n model round-trips. Exit code 4. | | --append-system-prompt-file <file> | Like --append-system-prompt, read from a file. | | --tools <list> | Restrict the run to exactly these tools. | | --session-id <id> | Use a specific session id for a new session. | | -n, --name <name> | Name the session; resume it later by that name. | | --fork-session | With --resume/--continue, branch into a new session instead of continuing. | | --fallback-model <alias> | Switch to this model if the main one is overloaded. | | --settings <file-or-json> | Extra settings (permission rules) for this run. | | --permission-prompt-tool <tool> | MCP tool (mcp__server__tool, or server__tool) that answers permission prompts where nex would otherwise deny for lack of a human. The tool receives {tool_name, input, cwd, permission_mode, session_id} and answers {"behavior":"allow"} or {"behavior":"deny","message":"…"} — and may replace the call with {"behavior":"allow","updatedInput":{…}} (what it approves is what runs, re-checked against plan mode and worktree locks). Never consulted when a deny rule or a plan lock refuses: those fail before prompting. A missing tool, a crash or an unparseable answer is a denial, never an approval. | | --debug-file <path> | Write debug logs to a file. | | nex auth status [--json] | Show whether you are signed in, and how. | | --system-prompt <text> / --system-prompt-file <file> | Replace the project brief (nexrall.md + memory + global instructions) for this run instead of appending to it. Giving both is an error. | | --verbose | Print progress detail (model, session, each tool call and its outcome) to stderr while a one-shot run works — stdout stays machine-readable. | | --include-partial-messages | Stream model deltas as they arrive (stream_event lines). Needs --output-format stream-json. | | --include-hook-events | Stream hook lifecycle events (hook_started / hook_progress / hook_response lines) as hooks fire. Needs --output-format stream-json. Without it, only SessionStart (and Setup) hook runs are streamed. | | --replay-user-messages | Echo each stdin message back on stdout as it is consumed. Needs --input-format stream-json and --output-format stream-json. | | --bare / --safe-mode | Start without discovery: no nexrall.md/memory, skills, plugins, hooks or MCP config files are read. Auth, model choice, permissions and built-in tools still work — use it for fast, predictable scripted runs or to rule out a broken config. | | --agents <json-or-file> | Define extra sub-agents for this run: a JSON object { "name": { "description", "prompt", "tools", "model" } } or @file.json. They join the catalogue the model can dispatch to with task. A definition that cannot be used is an error, not a silent drop. | | --agent <name> | Run the session as that agent: its prompt leads the brief, its tools become the allowlist (intersected with --tools if both are given) and its model is used unless --model overrides it. The name may come from .nexrall/agents/, a plugin, --agents, or a builtin. Not compatible with --bare. |
--max-budget-usd, --json-schema and --no-session-persistence need --output-format. Invalid values are an error, never silently ignored.
Background jobs
nex --bg "fix the failing tests" starts a headless run (stream-json output) and returns a job id at once.
nex --bg --exec "npm run build" starts a raw shell command instead — no agent, no model, no permission prompts (the command is the one you typed, like ! in the prompt). It lives in the SAME registry: nex jobs marks it !, nex logs/attach show the command's raw output (attach does not pretty-print a shell job), nex kill stops it, nex respawn re-runs it, and the exit code is recorded exactly as for an agent job. --exec without --bg, with a prompt as well, or nested inside another job is refused.
| Command | What it does |
|---|---|
nex jobs | List jobs: running, done, failed (with exit code), killed (by nex kill) or lost (process vanished without an exit code). |
nex logs <id> [-f] | Print a job's output; -f follows until it ends and exits with the job's exit code. |
nex attach <id> | Watch live in readable form (text, tool calls, result) instead of raw JSON. Ctrl+C detaches, the job keeps running. logs stays raw, for scripts. |
nex kill <id> | Stop a running job. |
nex stop <id> | Same as kill (the name Claude Code uses). |
nex rm <id> | Delete a finished job's records, log included. A running job is refused — stop it first, or its log would disappear while the process keeps writing. |
An id can be any unique prefix. Output lives in ~/.nexrall/cli-bg/. --bg cannot be nested inside a job.
One view of everything in the background
Background work lives in four stores (jobs, live sessions, sub-agent transcripts, shared tasks). nex agents merges them into one table so you do not have to remember which command lists what:
| Command | What it does |
|---|---|
nex agents | One table of everything still going: running/lost jobs, live sessions, recent sub-agent transcripts, open shared tasks. Includes work from other sessions on this machine, not just this shell. |
nex agents --all | Also the settled rows: done/failed/killed jobs, completed tasks, transcripts older than a day. |
nex agents --cwd <dir> | Rows at or under <dir> (jobs and sessions); tasks come from that exact directory's board. |
nex agents --json | The same rows as JSON — fields are only ever added, never renamed; kind is job | session | agent | task, and the per-kind state vocabulary is fixed (documented below). |
nex respawn <id> | Start a new job with the same command, args and directory as a previous one. Refused for jobs recorded by an older nex that did not save the full command — a guess could run wider than you asked (a lost --permission-mode or -w). |
nex respawn --all | Respawn every currently running job (e.g. after a machine restart). |
The table drops its WHERE column first, then AGE, when the terminal is narrow — the id, state and description are the columns that stay, because those are what logs / attach / stop / respawn need. For scripts, --json never changes shape:
// nex agents --json
[
{ "kind": "job", "id": "a1b2c3d4", "state": "running", "name": "fix the failing tests",
"cwd": "/repo", "startedAt": 1730000000000, "pid": 123, "prompt": "fix the failing tests" },
{ "kind": "session", "id": "aaaa1111bbbb2222", "state": "idle", "name": "brave-harbor",
"cwd": "/repo", "startedAt": 1730000000000, "updatedAt": 1730000009000, "pid": 456, "clientType": "cli" },
{ "kind": "agent", "id": "agent_7_0a0b0c0d", "state": "done", "name": "Map the auth call sites",
"startedAt": 1730000000000, "updatedAt": 1730000009000, "agentType": "explorer", "messages": 12, "bytes": 34567 },
{ "kind": "task", "id": "eeee5555ffff6666", "state": "in_progress", "name": "CLI gap-fix S7: agent view",
"cwd": "/repo", "startedAt": 1730000000000, "updatedAt": 1730000009000, "claimedBy": "brave-harbor" }
]Optional fields are omitted (not null) when the store does not carry them — e.g. exitCode appears only once the job ended, agentType only when the sub-agent ran with an explicit type, claimedBy only while a session holds the task. A job in state lost crashed without writing an exit code; it is deliberately shown without --all, because it is not history yet.
The shared task board from the shell
Sessions create and claim shared tasks through their tools; nex tasks is the same board for people and scripts — seed work before launching sessions, see who holds what, and tick off or release stuck claims without being inside a session:
| Command | What it does |
|---|---|
nex tasks | The board: pending and in-progress tasks, who holds each one. |
nex tasks add "write the release notes" | Create a task sessions can see and claim; --blocked-by <ids> makes it wait on other tasks. |
nex tasks claim <id> | Take a task — races a session's claim exactly as two sessions would race each other. |
nex tasks done <id> / release <id> | Close it, or hand a claimed task back to the board. |
nex tasks rm <id> | Remove it from the board entirely. |
An id may be any unique prefix, and --json is available on every verb for scripts. The full table (and its exit codes) is in the CLI reference.
Managing MCP servers
| Command | What it does |
|---|---|
nex mcp add <name> <command> [args...] | Register a stdio MCP server. Add --always-load to keep its tools in context past the tool cap. Details |
nex mcp add-json <name> <json> | Register a server from a JSON definition. |
nex mcp list / nex mcp get <name> | Show configured servers. Secret values (env, headers) are never printed. |
nex mcp login <name> | Sign in to a remote (http/sse) server that requires OAuth. Opens the browser, then really connects to confirm the token works. Refused for a stdio server or one that already pins an Authorization header. Details |
nex mcp logout <name> | Forget the stored token for that server. |
nex mcp remove <name> | Remove a server. |
nex mcp serve [--cwd <dir>] | The other direction: run Nexrall's read-only tools (read_file, list_directory, glob, search_files) as an MCP server on stdio, for another agent to call. Prints nothing on stdout — stdout is the protocol. Details |
Authentication
Run nex auth (or its alias nex login). In a terminal it asks which method to use:
| Method | When to use it |
|---|---|
| Browser (recommended) | Works for every kind of account — Google, Apple, company SSO, or email + password. The CLI opens app.nexrall.com/auth/vscode?cli=1, you sign in there, and paste the 5-minute code it shows back into the terminal. nex auth --browser picks this method directly; --code <code> finishes a hand-off without opening a browser (headless boxes). |
| Email + password | Typed in the terminal. Only works for accounts that have a password — one created with Google, Apple or SSO does not, and must use the browser method. |
| Token | nex auth --token <token>, for CI and headless setup. The token is verified against the API before it is saved. |
For CI or any non-interactive context, prefer setting NEXRALL_TOKEN as an environment variable — it always takes precedence over any locally saved interactive session:
export NEXRALL_TOKEN=<token>Because it wins over the saved login, nex logout cannot remove it: unset the variable as well, or the CLI stays signed in with that token.
nex logout (or /logout inside a session) revokes the refresh token server-side before deleting the local config, so the 60-day token cannot be replayed from a backup or a synced dotfile.
Billing & teams
Every turn is metered from a wallet — Nexrall is pay-as-you-go, with no plans or subscriptions. /balance shows what you have left.
If your account has a team, your usage is billed to whichever target your account is set to (your personal wallet, or the team's shared budget) — the same setting the web app and the VS Code extension use, so the CLI cannot disagree with them. A CI or headless run can override it for a single request to bill a personal wallet instead, which is the usual choice for automation. See Teams & shared budgets.
Cloud schedules
nex schedule (alias nex routines) runs a recurring task on Nexrall's servers instead of on your laptop: "triage the repo every day" keeps firing after the terminal closes, the session ends and the machine sleeps. Inside a session the same thing is /schedule (or /routines).
| Command | What it does |
|---|---|
nex schedule / nex schedule list [--json] | Your schedules: state, interval, next run, last status. |
nex schedule add --every <interval> <task> | Create one. Units are s, m, h, d (15m–7d). --start-url <url> and --domains <list> pin where the cloud agent may go; --disabled creates it paused. |
nex schedule pause <id> / nex schedule resume <id> | Stop it firing, or start it again (resume re-arms the next run). |
nex schedule run <id> | Run it now without waiting for the interval. This arms the row — the cloud runner picks it up within ~60s; check nex schedule runs <id> for the outcome. A paused schedule is refused (resume it first) rather than silently un-paused. |
nex schedule rm <id> | Delete it — asks first, -y for scripts. It stops firing; its run history stays on the server. |
nex schedule runs <id> [--json] | What happened on each run: status, steps, summary. Newest first. |
nex schedule add --every 1d --start-url https://github.com/Maxrall-Inc extract the open issuesA schedule's runs are full cloud browser-agent runs, billed like any other usage (see Billing & teams). The server owns validation — interval bounds and the task length come back as plain sentences if you get them wrong, and a schedule that has never run shows - for its last status rather than guessing. Interval bounds (15 minutes – 7 days) are the platform's: a faster loop belongs in /loop or a --bg job on a machine you leave on.
Not to be confused with the two LOCAL mechanisms: /loop jobs and cron tools live inside the session (they die when it ends), and --bg jobs live on this machine (see Background jobs). Cloud schedules are the only ones that survive the laptop being closed.
Cloud coding sessions
nex cloud runs a coding task on Nexrall's infrastructure instead of your laptop: the repo is cloned into an isolated Pod, the agent works headless on the task, and the result comes back as a pushed branch and a pull request. Your machine can close the moment the command returns.
nex cloud run "fix the failing tests on this branch" --repo acme/apiThe command prints the session id and a live link; from there:
| Command | What it does |
|---|---|
nex cloud run "<task>" --repo <owner/name> | Start a session. --base <branch> picks the base (default main); --open opens the live viewer when you want to watch. |
nex cloud / nex cloud list [--json] | Your sessions, newest first — id, status, repo, and the result once there is one (the PR, the branch, or the error). |
nex cloud logs <id> [-f] [--tail <n>] | The pod's log; -f follows until the run ends and exits non-zero when it failed. A finished session's log survives — the final tail is captured when its pod is deleted. |
nex cloud stop <id> | Stop a live session — its pod is deleted within ~10s. |
nex cloud watch <id> | Open the live viewer; --print just prints the URL for a script. |
Rules that shaped it:
- Watch live, like
/share. The run publishes its own event stream to the relay undercloud-<id>, so the viewer atapp.nexrall.com/live/cloud-<id>shows the same tool calls, diffs and text a shared local session streams. Like/share, it is account-scoped and needsnex auth— every cloud verb fails without one. - The GitHub token. A public repo clones without one; any repo needs one for the push and pull request. Pass it as
--pat <token>or, better, inNEXRALL_CLOUD_PAT— argv is visible in shell history and process lists. A fine-grained token scoped to the one repo (contents: read/write, pull requests: write) is enough; the server keeps it only for the session's lifetime, and the Pod fetches it per use and never writes it to disk. - The deliverable is git. The branch is
nexrall/cloud-<id>and the PR is opened against the base branch when the run ends; a run that produced no commits reports exactly that, never a fabricated success. Without a push credential, the commits stay in the Pod and the session records why. - Billing is the usual wallet. Model spend is charged like any other usage — the wallet or team your account is set to.
- Early access, with server-enforced caps. Until your account is enabled, every verb refuses with a sentence saying so. For enabled accounts: one running session at a time, up to 3 queued, 10 sessions per rolling 24 hours, and a 90-minute wall clock per session.
Safety in headless mode
Destructive-but-legitimate operations (dropping a database table, force-pushing, terraform destroy, and similar) are blocked by default in headless mode, even with auto-approve on — a script or CI job has no one to confirm with. To allow them explicitly in a trusted CI context, set:
NEXRALL_ALLOW_DESTRUCTIVE=1Troubleshooting
nex doctor checks everything a session depends on — Node version, sign-in, network, terminal capabilities, MCP servers, storage — and prints a fix beside each problem it finds. It exits non-zero when something is wrong, so it can double as a CI preflight; in a session, /doctor runs the same checks.
nex doctor
nex doctor --dir ./my-projectRelated mid-session views: /context (what is filling the context window), /hooks (which hooks will run), /mcp (each server's state and tool count).
Plugins
nex plugin install code-review # an official plugin, by short name
nex plugin install owner/repo # from GitHub
nex plugin install owner/repo#branch/subdir
nex plugin install https://github.com/owner/repo
nex plugin install ./local/path
nex plugin search <name> # search the registry
nex plugin info <name>
nex plugin list # what's installed
nex plugin remove <name> # --keep-data keeps ~/.nexrall/plugin-data/<name>
nex plugin update [name]
nex plugin prune --dry-run # auto-installed deps nothing needs any more
nex plugin prune -y # remove them (alias: autoremove)install also installs the dependencies a plugin's manifest declares, and prune never removes a plugin you installed yourself or one that an installed plugin still needs. The official plugins — code-review, test-gen, doc-writer, security-audit, refactor-guide, commit-pro — install by short name, and nex plugin source binds a repo to a short alias a whole team can commit.
See Plugins for the full plugin system — commands, agents, and hooks.
Updating
nex update # update to the latest version
nex update --check # check without installingor /update inside a session.
Reference
The CLI is one surface of the developer-tools coding agent — for the full technical surface, see:
- CLI reference — every command, subcommand and flag on one page.
- Slash commands — the complete in-session command list, with custom commands and MCP prompts.
- Interactive mode — keyboard shortcuts and input modes.
- Configuration — the
.nexrall/directory andsettings.json. - Environment variables — the
NEXRALL_*variables (including the safety toggles used above). - Permission modes & rules — modes and
allow/ask/denyrules. - Tools reference.
- MCP · Sub-agents & skills · Hooks.