TUI¶
The Nur-gold terminal UI for interactive sessions.
The editor opens before skill indexing, account refresh, and model discovery
finish. You can type immediately. Built-in controls such as /login, /help,
/effort, /theme, /context, /new, and /cd work while skills index.
Model requests and skill commands retain their text and attachments in the queue
until their dependencies are ready. /compact waits only for account preparation.
The activity line shows the remaining work. /quit and Ctrl+C remain available.
The NUR banner keeps its gradient shimmer while idle, along with the input
border, separators, and status-line animations.
Queued requests belong to their original session and workspace. /new, /cd,
resume, fork and undo discard obsolete queued requests, including attachments.
Escape cancels pending judgments and clears questions and approvals, so delayed
responses cannot reopen a cancelled turn.
/skills refresh rebuilds global metadata on a worker while retaining the
previous complete snapshot. Finished Markdown retains its parsed content across
width changes. See the v0.41.0 refresh.
Session inspector and compact activity¶
Press F6 to open a shared inspector with Changes, Tools, Agents, and Context tabs. It docks beside the conversation at 90 columns or wider; in a narrow terminal it covers the transcript while leaving the composer usable. Use Alt+1–4 or click a tab, and scroll with the wheel or Alt+PgUp/PgDn. F6 closes it; Esc closes it when no detail preview is open.
Changes lists file-edit tool calls from this session, including their success
or failure status; it is not a live Git working-tree diff. Click a change or tool
to open its existing full-detail preview. Agent rows open the agent trace.
Context shows the provider, model, cumulative session token usage, queued
messages, and draft attachment count. /context still provides detailed
context inspection.
Completed successful tools occupy a compact summary row; consecutive ones share one frame. Running operations and errors retain their details. Click the chevron to expand or click to peek for the full result. Every transcript piece sits in a theme-coloured frame (see Card frames), and the pinned prompt uses two rows. The composer stays visually still while idle.
Transcript rendering indexes cached cell heights, builds styled rows and interaction metadata only for the visible viewport, and caches link detection. Full-history text remains available for selection. Idle redraws are limited to one per second; input and incoming agent events still trigger immediate redraws. Scroll offsets use full-width counters so long histories do not wrap at 65,535 rows.
Built with Ratatui
The entire interface — cards, borders, animations, drag-select, and the scrollbar — is built on Ratatui (github.com/ratatui/ratatui) with crossterm for input/rendering. Enormous thanks to the Ratatui folks. 💙
Opening the TUI¶
nur # fresh session
nur "fix the bug" # start with a prompt
nur -c # continue last session
nur -r <session-id> # resume specific session
Opening banner¶
The splash is intentionally lean:
- NUR art
<active provider> loaded · v<cli>model · cwd · session- Purple ecosystem line (sandbox · subagents · tools + pack status)
- Permission mode
Mouse/keyboard interaction tips that used to live under the art are behind
/tips so the banner stays short. The active provider name comes from
config.provider (see Authentication).
Keyboard shortcuts¶
Navigation¶
| Key | Action |
|---|---|
↑ ↓ · mouse wheel · drag scrollbar |
Scroll transcript (wheel and keys glide; the thumb stays under the pointer while dragging, a click on the open track pages toward it) |
Rail in any list dialogue (/model, /login, /plugins, /theme, sessions) |
Click or drag the right-hand rail to jump through the list; the selection follows the window |
| Drag on chat text | Select + auto-copy (keeps range while you scroll; works on expanded thought/tool bodies) |
Click ↓ N · End |
Jump to latest message |
| Click the exact click to peek text | Opens stable dialogue (frozen position; Esc · outside · ✕ only) |
Click ▸ |
Expand / collapse in place |
| Ctrl+C (peek open, no selection) | Copy full thought / tool body |
| Right-click or double-click a prompt | Prompt menu: fork · edit · revert · copy (works on the sticky header too) |
Ctrl+P / Ctrl+N · Alt+↑/↓ |
Previous / next prompt from history |
Peek dialogue
Click a card (or a finished turn's timing strip) to pin a peek box with its
full content. Close it with the ✕, Esc, or a click anywhere outside
the box.
Input¶
| Key | Action |
|---|---|
| Ctrl+A | Select-all input (or whole transcript if input empty) |
| Ctrl+C | Copy selection (transcript or input); else interrupt / double-tap quit |
| Ctrl+V | Paste text or stage an image in the composer |
| F4 / Shift+F4 | Preview/cycle draft images / remove the selected draft image |
| F6 | Toggle the session inspector (Changes / Tools / Agents / Context) |
| Alt+1–4 | Select an inspector tab while it is open |
| Alt+PgUp / Alt+PgDn | Scroll the inspector; the mouse wheel also works |
| Ctrl+X | Cut input selection (or whole input) |
Enter |
Send message |
Shift+Enter |
Newline in input |
The composer caches its measured soft-wrap layout for each draft and terminal width, then reuses that map for height, paint, cursor movement, and mouse hit testing. This keeps long or paste-heavy drafts responsive during redraws.
Control¶
| Key | Action |
|---|---|
Shift+Tab |
Cycle permission mode (manual → plan → auto → manual) |
Ctrl+R |
Reverse-search prompt history (Ctrl+R again steps older · Esc cancels) |
Esc |
Close peek, then cancel current turn |
Approval¶
When the agent requests permission to run a write/shell tool:
| Key | Action |
|---|---|
y |
Approve this one time |
a |
Always approve what the footer names, for this session: the tool, or for bash the programs the command runs (git, npm, …), so approving git never approves rm. A command that hides what it runs ($(…), a redirect into a file, sudo, bash -c, env, xargs, …) is approved as that exact command only |
n · Esc |
Deny |
Enter deliberately does not approve — the modal can open while you are
mid-sentence in the composer, and finishing that sentence should not run a tool.
Keys held with Ctrl or Alt are ignored here for the same reason: Ctrl+A is
"select all" everywhere else, and must never be read as "always approve".
Question modal¶
When the agent needs your answer to proceed, it calls the question tool and
the TUI shows the options:
| Key | Action |
|---|---|
1-8 |
Pick immediately, or toggle that option in multi-select |
↑ · ↓ (k · j) |
Move the cursor |
Space |
Toggle (multi-select questions only) |
Enter |
Confirm the cursor (single-select) or the checked set (multi-select) |
Esc |
Dismiss without answering |
Page Up / Page Down, Home / End |
Navigate options |
o / Tab, or paste |
Open a custom typed answer |
In the custom-answer field, use Left/Right, Home/End, Backspace and Delete to
edit at the caret. Ctrl+U clears the field; Enter submits a nonblank answer.
Escape returns to the options while preserving your draft. Press o or Tab to
resume it. Pasted line breaks become spaces, and Unicode text is measured in
terminal cells so the caret stays visible on narrow terminals.
Unlike approval, Enter does confirm here - picking is reversible
conversation, not a side effect. An empty multi-select confirm is ignored so
Enter never submits nothing. Dismissed questions come back as guidance text
(proceed, defer, or declare BLOCKED:), never as an invented answer. Goal
turns, subagents, and headless runs never open this modal; a Jev gate resolves
the question silently first when context or a safe default suffices.
Slash commands¶
Type / in the input to see available commands. The palette spans from the
input's left edge to the right edge of the window, so widening the terminal
reveals more of each command's tip rather than adding empty margin.
Permission and mode¶
| Command | Purpose |
|---|---|
/mode |
Show current permission mode |
/plan |
Switch to plan mode (explore + shell freely; no code edits or repo commits) |
/manual |
Switch to manual mode (approval required for writes) |
/auto |
Switch to auto mode (auto-approve all) |
See Permission modes below for exactly what each mode allows.
Session and state¶
| Command | Purpose |
|---|---|
/sessions · /resume |
Open the sessions window; press c to switch to takeover |
/takeover · /hijack |
Open the takeover window: import a Claude/Codex/Cursor/Grok session and resume it; press Tab to scope to here, c to switch back |
/todos |
Show current todos |
/swarm |
Inline subagent grid — one live pane per subagent |
/clear |
Clear the screen only — the model keeps full context and the session history is untouched (/compact shrinks context, /new starts fresh) |
/new |
Start a new session |
/steer <text> |
Inject a message into the running turn without cancelling it (tools, subagents and bg jobs keep going). While busy, a plain Enter queues a choice card instead of steering |
/undo |
Revert the last file edit made this session (write_file edit_file multi_edit) |
/receipt |
Session receipt: what actually ran (models, tools, privacy tiers) plus hash-chain verification and an OTLP span export |
/commands |
Commands + keyboard shortcuts |
/quit |
Quit (alias of /exit) |
The swarm card¶
/swarm drops a live card into the transcript that tiles every subagent the
agent tool spawns: state glyph, id and type, the task, the tool in flight, an
activity trace, elapsed time, tool count, and tokens.
Layout is a zone grid — percent tracks snapped to character cells — so panes tile the card exactly at any width, and the card resizes with the window rather than wrapping:
| Terminal width | Behaviour |
|---|---|
| Wide | Up to 8 panes across a multi-column grid |
| Medium | Fewer columns; panes it dropped are disclosed as +N more |
| Narrow (< 28 cols) | Frames are dropped for a one-line-per-agent list |
Subagents fan out concurrently: several agent calls in one model response
run in parallel (up to 4 at a time), so the card usually shows more than one
live pane. Approval for the whole batch is collected up front, one prompt at a
time, so concurrent children never race you for the approval dialogue.
The card re-arms itself on each new turn and freezes when the turn ends.
/swarm detail adds a status row, /swarm off freezes it, /swarm clear
forgets finished runs, /swarm hide removes the card.
The sidegraph panel¶
/sidegraph opens a right-sidebar live node-graph of the current query, drawn on a
2D character canvas: a double-bordered root prompt at the top, then fixed-width
boxed steps down a centred trunk — reasoning (◇, violet), tool calls with their
formatted arguments and ✓ return { … } blocks, answering, steers, queued
follow-ups, and the settled turn. Text word-wraps inside each box; durations ride
in the bottom border.
Completed tool calls are grouped into one track per tool, to the right of the trunk. Each track's arrowhead under the root rail and the links between its own nodes carry its category colour (search, edit, exec, agents and knowledge each take a theme role, so every theme keeps them distinct), while the trunk's links stay faint.
Because nodes are placed by coordinate rather than concatenated as strings, a box cannot render wider than its own borders, and content is clipped only at paint time — which is what gives panning something real to reveal.
Two structures are drawn as actual graph topology, and only these, because they are the only ones nur has:
- Parallel fan-out — the
agenttool's live subagent runs hang side by side beneath it on an elbow rail and rejoin the trunk below (up to 4, then… +N more). A fan-out is far wider than the panel; that is what horizontal panning is for. - Steer re-entry — a mid-turn steer sends control back into the preceding
reasoning node, drawn as a back-edge up the right gutter (
↻ re-entry).
| Width | Behaviour |
|---|---|
| ≥ ~66 cols | Transcript split into [main |
| < ~66 cols | Panel hidden automatically, state kept; note once: "sidegraph · hidden — window too narrow · reappears on resize" |
- Bare
/sidegraphtoggles the panel (open -> close).off/freezefreezes refresh,on/liveresumes,hide/closecloses. - Resize: drag the panel's left border. Clamped so the transcript keeps ≥ 35 cols.
- Pan: click and drag anywhere inside the panel to move the canvas under the cursor, both axes. Horizontal range exists only when the graph is genuinely wider than the panel (fan-outs, back-edges). Once you pan, the canvas stays put as new nodes stream in — you keep control. Double-click empty space to snap back to the root / latest prompt.
- Zoom:
Ctrl+mouse-wheel over the panel zooms between three levels —detailed(full boxes),compact(title rows), andminimap(glyph dots) — so a long graph shrinks vertically without touching the transcript, window, or model./sidegraph zoom/zoom-out/resetdo the same from the palette. - Peek a box: double-click or right-click any node box to open its
click-to-peek modal (same content as the transcript's "click to peek"). Subagent
fan-out (kid) boxes open a swarm peek with a sticky task header (static
border) above the live tool output (border + colour follow the current tool);
Ctrl+Cthere copies only the tool output, never the sticky task. The same kid peek opens by double-clicking a pane in the inline/swarmcard. - Title shows
◈ sidegraph (N)with the step count,● live+ spinner while running,◼ frozenwhen frozen. - Mouse wheel scrolls vertically and agrees with drag direction; the view follows the newest node unless you scrolled up.
- New turn re-roots the graph and resets both scroll axes; same-turn refreshes keep scroll sticky.
- Performance: the painted canvas + hit-boxes are cached against a cheap structural fingerprint and only rebuilt when something visible actually changes — a long session never repaints the whole graph at spinner cadence. The node list is bounded (most-recent 240) so history can't grow it without limit.
- The model is derived from transcript cells on each turn event, so it can never drift from what actually ran; the renderer re-reads the swarm registry each frame for live subagent fan-out.
Redraw / ghost-cell recovery¶
Windows ConPTY and image-protocol peeks can leave glyphs behind when the layout
changes. Nur forces a full terminal.clear() (not only a ratatui Clear) when:
- the window resizes or focus returns
/sidegraphopens or closes (horizontal split)- a click-to-peek closes (image pixels sit outside the cell buffer)
/themeoffers 41 themes, including 18 chromatic studies, with type-to-filter search, paste, and Ctrl+U to clear. It previews live as you move. Enter saves; Esc or the close button restores the previous palette. The preview and list use separate regions so visible rows and mouse targets stay aligned.- Theme, provider, model, plugin, and session pickers fit their content and available terminal height. A proportional rail shows when more choices are off screen. Use arrows or the wheel for one choice, Page Up/Down for a page, and Home/End for the first/last choice. Click a row to select; click the selected row again to activate it.
- Theme, provider, model, and plugin searches accept typing or paste; Ctrl+U clears the filter. Plugin descriptions and operation status have reserved space below the choices. Pasting into a dialog stays in that dialog.
- Sign-in forms support wheel and Page Up/Down scrolling on short terminals; their close buttons follow the same back/cancel path as Escape.
- The command palette supports mouse row selection, Page Up/Down, Home/End, and a visible close button. Tool and subagent peeks support keyboard scrolling and keep typing/Enter from changing or submitting a hidden draft.
- Dialog drawing, keys, and mouse share one focus order, so background update notices cannot cover a dialog that is receiving input.
/theme transparenttoggles see-through mode (panels stop painting backgrounds; pairs with a translucent terminal profile; persisted as[theme] transparent)/theme motiontoggles reduced motion (the banner shimmer, aurora rules and modal edges hold one frame, the idle loop stops repainting, spinners tick at ~10fps; persisted as[theme] motion). The defaultautoalready reduces motion inside an Orca pane or over SSH, where every frame crosses a link; set it when another web or remote terminal feels late to your keystrokes. Mouse tracking is button-event only (?1002) on every platform, so moving the pointer never costs a frame.- a foreground child (
/fractal open, attach) returns
Steady frames only Clear when the layout signature changes (size, busy line,
input height, sidegraph width) so peeks are not re-uploaded every tick.
Knowledge stack¶
| Command | Purpose |
|---|---|
/graphify |
Query the code knowledge graph |
/plur |
Search shared engram memory |
/ruflo |
Search vector memory |
/skills |
List installed skills (also shows sticky session skills) |
/ecosystem |
Show ecosystem status |
/memory |
Show session memory |
/optmem · /memo |
OptMem permanent memory (~/.optmem): status wake note nap recall zoom forget config doctor. nap lines=[...] drains several compressions in one call |
Quick memory¶
Type # followed by a note to save it directly to ~/.nur/memory.md without starting a turn:
The note is appended to your persistent memory file and recalled automatically in future sessions.
Model and context¶
| Command | Purpose |
|---|---|
/model |
Show and switch models. Run bare to open a picker that fetches your provider's live model list (/models) - filter, arrow, and Enter to switch, or type any id. /model <id> switches directly (e.g. /model gpt-5.5) |
/plugins |
Marketplace picker (same UX as provider//login picker): filter, ↑↓/wheel, ↵ to install or enable/disable. Skills land in ~/.nur/plugins/<id> and mirror in full (incl. references/) to ~/.nur/skills. CLI: nur plugins list\|install\|enable\|disable\|uninstall. Natural-language phrases (e.g. think like fable) or /skill-name auto-activate skills — status chip confirms activation |
/effort |
Reasoning effort: low … max, or ultracode (max effort + parallel subagents). Bare /effort shows the ladder and what the active route receives; /effort <level> saves it |
/provider |
Choose the active provider and sign-in route (/login is an alias) |
/auth |
Manage saved OAuth, API-key, CLI and OMP credentials for every provider |
/headroom |
Context-compression status / doctor (inline tool-result compression is on by default) |
/compact |
Honor configured Jev pruning without a summary; preserve history if no prune is possible; write .precompact.bak (details) |
/usage |
Show token usage and cost (/cost) — includes budget caps when set |
/ledger [today\|7\|month\|all] |
Aggregate local agent usage in the background; charges, estimates, and unpriced requests remain distinct |
/budget |
Optional caps (all unlimited by default): /budget [cost\|tokens\|turns] <n\|unlimited\|0\|off> · clear · save |
/turns |
Agent rounds per prompt (default unlimited). Alias of /budget turns |
/poor |
Toggle cost-saver prompt (skip PLUR/skills/memory; tools full). /poor status shows poor + budget. Does not set spend caps |
/context |
Context-window utilization (bar + tokens) |
/status |
Session snapshot: model · mode · cwd · tokens · cost |
Judgments (TypeSafe - Jev)¶
| Command | Purpose |
|---|---|
/typesafe · /jev |
The Jev layer: status, on/off, and ask <proposition> for one judgment by hand. Keyless on this machine through a local engine - see typesafe.md and jev-local.md |
/typesafe-ai |
The skill: how to design and use judgments (distinct from /typesafe, which is the layer's controls) |
Security agents (Enclave)¶
| Command | Purpose |
|---|---|
/enclave |
Enclave over native MCP: status (default) · tools [name] · login. Status and tool listing run in the background; see enclave.md |
Project and shell¶
| Command | Purpose |
|---|---|
/cd <path> |
Change the working directory tools are sandboxed to (~ and relative paths OK) |
/pwd |
Print the current working directory |
/init |
Initialise project instructions (NUR.md) |
/scan |
Map this codebase → local .foglamp/scan.json, then optionally publish to foglamp.dev. /scan [focus] centers the map. Writes need manual/auto (plan is lifted to auto). Ask only before upload, not before the local file. |
/config |
Show config + data paths |
/permissions |
Show or reload allow/deny/ask rules (permissions.toml); trust / untrust this project's allow rules |
/hooks |
Local tool hook status (hooks.toml) |
/doctor |
Inline health check: version · auth · ecosystem · shell · budgets |
/help |
Show keys + commands reference |
/login |
Multi-provider sign-in (see below) |
/logout |
Sign out of the active provider (clears its credential and saved copies; other providers keep theirs) |
/goal |
Standing session goal (see below) |
/bro |
Chill mode: plain words, no jargon, no preamble — toggle (see below) |
/adhd |
Sticky ADHD-friendly output (toggle) |
/<skill> |
Any installed skill — sticky, or /skill <prompt> one-shot |
/site-cli · /fable-method · /design-eng · … |
Popular skills also listed in the palette |
/btw |
One-off note for the next message only |
/codesearch /cs |
Fast workspace ripgrep |
/mc /mcp |
MCP servers via the Executor gateway |
/fusion |
Multi-model debate → one synthesized answer. /fusion panel <ids> sets the panel, /fusion <question> asks it, /fusion off clears |
/local |
Managed local model (bundled llama.cpp): /local up [tier\|url], status, models, down |
/bench |
Benchmark models on your tasks: /bench add\|list\|run <name> [models]\|remove |
/feedback |
File a GitHub issue (gh or browser) |
/tips |
Mouse + keyboard interaction tips (lean banner counterpart) |
/bug |
Open GitHub issues page (report a bug) |
/exit |
Quit NurCLI |
Multi-provider /login¶
Scrollable, type-to-filter catalog of 70 providers → browser / official
harness sign-in when available (including Muse Code, DeepSeek Harness, ZCode,
Cline) or a masked key → writes provider / base_url / model to config and
hot-swaps the HTTP client.
Opening /login clears nothing, and Esc out of it changes nothing — your
credential is replaced only when a new one is committed. Keys are kept per
provider, so switching does not strand the provider you left: it stays usable
for failover and for subagents running on another provider's model. Use
/logout when you actually want an account's credentials gone.
Full detail: Authentication.
Session goal & side notes¶
| Command | Behaviour |
|---|---|
/goal <text> |
Standing goal for this session. Prepended as context on every turn (not shown as a user bubble). Submitting a new objective also starts a goal-driven turn immediately. |
/goal |
Show the current goal |
/goal clear |
Drop the goal (none / off also work). Also clears the standing context. |
/goal pause · /goal resume |
Suspend / resume the tracked goal without losing it |
/goal complete |
Mark the tracked goal complete yourself |
A goal-driven turn ends in exactly three ways: goal action=complete with
per-part evidence, a BLOCKED: <what is needed> line when only you can
unblock it, or continued tool work. While the tracked goal stays active the
harness auto-continues a stalled turn (up to 5 continuations, visible as
goal · continue (n/5) cards) instead of handing back an unfinished summary.
Completion claims are verified part by part against the transcript by Jev -
hosted key or local engine, whichever is configured - and only a confident
not-done reopens the goal; with no judgment layer the claim is accepted and
marked unverified. Esc stops the chain; /goal pause suspends it; /goal clear drops it.
| /btw <note> | Queues a one-off note that rides along with your next message only (stackable) |
| /bro | Toggle chill mode: every turn asks for plain, low-jargon, no-preamble replies. /bro on / /bro off force a state. Tone only — facts, caveats, and bad news stay complete and accurate. /status shows when it's on. |
| /adhd | Sticky ADHD-friendly shape for every reply this session (action-first, numbered steps, no fluff). /adhd off clears it. |
| /<skill> | Any skill under ~/.nur/skills or ~/.agents/skills: bare /name toggles sticky; /name <prompt> runs a one-shot turn with that skill activated. Palette filters as you type. |
Code search¶
Runs the workspace grep tool immediately and prints matches in the
transcript (no full agent turn).
MCP (/mc)¶
Uses the Executor gateway (executor tool). If MCP is missing:
Integrations¶
| Command | Purpose |
|---|---|
/egaki |
Image / video / speech generation via egaki (egaki login --provider chatgpt supported) |
/image <path> |
Stage an image in the composer for vision; F4 previews it (generation is /egaki) |
/tb · /terminal-browser |
In-terminal browser: open | ls | action | setup (Windows host fallback via agent-browser-cli) |
/draw |
tldraw boards: open a .tldraw, install, or build one from an idea |
/pen · /drawings · /penecho |
Penecho canvas (ink, MathJax, plots); /drawings lists saved canvases |
/akarso |
Post / schedule / reply across 14 social platforms (akarso tool + skill; publishing asks first) |
/openseo |
SEO research and audits through the OpenSEO MCP server |
/dialkit |
Live-tune interface parameters (dialkit skill) |
/cua |
Computer-use desktop driver: on (always-on, elevated) | off (on demand, default) | status |
/failover |
Cross-provider failover in the provider picker (space toggles a provider into the chain) |
/factory-overnight |
Fractal-first overnight factory driven from HANDOFF.md (Unix preferred) |
/prewalk |
OMP-style staging: a strong model plans, then a cheap model takes over at the first edit (on | off | status | into <model> | reset) |
/skeuo |
Activate the skeuomorphic-UI skill (/skeuomorphic-ui) |
/fable-loop · /fable-judge |
Skills: orchestrated Fable multi-step loop · adversarial verification of finished work |
/tech-spec · /test-driven-development · /systematic-debugging |
Skills: typed call-stack handoff · TDD red-green-refactor · root-cause-first debugging |
Feedback¶
Creates a GitHub issue on nuroctane/nur-cli via gh when available;
otherwise opens a prefilled new-issue page in the browser. Includes CLI
version, OS, and model in the body footer.
Cost control (quick)¶
/budget cost 5 # optional $ hard-stop (default is unlimited)
/budget cost unlimited # clear $ cap (also: 0 | off)
/budget turns 80 # optional rounds-per-prompt cap
/turns unlimited # unlimited agent rounds (also: 0 | off)
/budget clear # cost ∞ · tokens ∞ · turns ∞
/budget save # persist ceilings to config.toml
/poor # leaner system prompt (tools unchanged)
/poor status # poor + budget one-liner
Oversized tool results automatically spill under ~/.nur/tool-results/ with a short preview for the model — see Configuration.
Permission modes¶
Cycle with Shift+Tab (manual → plan → auto); switch directly with /manual, /plan, /auto. The change applies immediately, even mid-turn.
| Mode | What runs freely | What needs approval / is blocked |
|---|---|---|
| manual | Reads (read_file, grep, look, git_status, …) |
Writes, bash, extract_frames → prompt y / a / n |
| plan | Reads and shell for reading, parsing, tests, and scratch/media compute (ffmpeg, extract_frames, copying a clip, analysis scripts) |
Blocked: code authoring (write_file / edit_file / multi_edit / apply_patch) and repo/VCS mutation — git commit/push/add/reset/… , gh pr create, dependency installs |
| auto | Everything (no prompts) | — |
Plan mode is for exploring and understanding a codebase without changing it: run whatever analysis you like, but no edits land and nothing is committed until you switch to manual or auto.
Visual design¶
Colour system¶
Tool cards are colour-coded by family:
| Family | Hue | Tools |
|---|---|---|
| read | sky | read_file list_dir grep glob |
| edit | violet | write_file edit_file multi_edit apply_patch |
| shell | amber | bash |
| vision | pink | look extract_frames |
| web | teal | web_fetch web_search |
| git | cyan | git_status git_diff |
| knowledge | indigo / orange | graphify plur ruflo skill memory |
Card frames¶
Every piece of transcript output sits in its own rounded frame, coloured from the active theme's role for that kind of piece. Frames are static: no shimmer, no motion. The NUR banner is the one exception and stays unframed.
| Piece | Frame role | Weight |
|---|---|---|
| Your prompt | nur_gold (the theme's spine) |
strong |
| Answer | seafoam (matches the ● bullet) |
normal |
| Thought | violet |
normal while thinking, quiet when done |
| Tool | the tool's family hue (table above) | normal while running or expanded, quiet when done |
| Failed tool, error | error |
normal / strong |
| Turn strip | success (warn when cancelled) |
quiet |
| Notice | its tone's colour (plan, mode, todos, usage...) | quiet |
| Queued follow-up | warn |
normal |
/graph, /swarm, attachment |
nur_gold |
normal |
Weights are contrast ratios against the canvas (quiet 2.1, normal 2.5, strong
3.0), all at or under the 3:1 text floor so the words inside still lead. Each
frame keeps its role's hue and only moves its lightness to reach the weight:
toward the canvas when the role is bright, toward the ink when it is too faint
on that ground. The same rule serves every theme, dark or light, with no
per-theme table (theme::card_frame).
Consecutive one-line finished tools share a single frame, and each row's sides
keep that tool's own family hue. Frames are drawn around the content, not into
it: text, click targets, links and selection keep their exact columns, and
copying a selection never includes frame glyphs or an extra blank line per
frame (src/tui/cards.rs).
Display math¶
$$...$$ blocks render as images when the build carries the image-peek feature
(the default release build does). Rendering is cache-only on the paint path: the
UI thread never spawns Node or ImageMagick, and a background worker warms PNGs
after each assistant message, so a block is already drawn by the time you scroll
to it. Without image-peek, or when katex/magick are unavailable, the TeX
source is left as-is rather than showing a broken box.
Thought cards¶
The model's reasoning is displayed in violet thought cards that are collapsed by default. Click to expand.
Duration chips¶
Each tool call shows a duration chip (e.g. 1.2s) so you can see where time is spent.
Transcript prose¶
Assistant answers are composed for reading, not dumped as markdown source. src/tui/markdown.rs parses block structure with pulldown-cmark and renders inline styling (bold, italic, code, strikethrough, links, syntax-highlighted code) through tui-markdown. The split exists so the block layer owns how structure looks:
| Element | How it renders |
|---|---|
| Heading | Never shows #. Level marker (▌ ▍ ▪) in the level's own hue, text bold in md_h1/md_h2/md_h3, one blank line either side. Setext forms (Title + ====) included. |
| Paragraph | Body text, one blank line between blocks. |
| List item | • (+ nested indent) or 1. in md_list; items stack tight. |
| Task item | ✓ (success) or ☐ (md_list) — the [x]/[ ] syntax is consumed. |
| Blockquote | ▏ bar in md_quote on every row, text a step down from body. |
| Code block | Fences never render. Every row sits on code_bg with a two-space gutter; syntax colours on dark palettes, the theme's own md_code on light ones (the highlighter's palette is dark-only). |
| Rule | A short ─ rule in border, not literal ---. |
| Link | Label in md_link, URL appended dimmed + underlined so it stays clickable without shouting. |
| Path | A path that exists on disk is a link (see below). Directories take the theme's dir hue. |
Path links¶
Any path in the transcript that exists on the machine is a link, and a click opens it exactly where the OS would:
| What you click | What happens |
|---|---|
A directory (src/tui/) |
Opens in your file manager - explorer.exe on Windows, Finder on macOS, xdg-open on Linux. Painted in the theme's dir role so it reads apart from the files beside it. |
A file (src/open_uri.rs) |
Opens in its default application. Keeps whatever colour it already had, so a directory listing stays legible. |
Precedence is deliberate: queue actions → path links → URLs → card expand. Clicking a path inside a collapsed tool card opens the path rather than toggling the card, and a note confirms what opened (or why it could not).
dir is the palette's own indigo, which every preset already tunes for its identity (matrix green, gruvbox pink, heavenly purple), so folders correspond to the theme with no per-theme table to maintain. It is unused by any other transcript role (md_link carries URLs, md_list list markers, md_code code), and a test asserts it clears the contrast floor on both the canvas and a code band for all 41 registered themes (theme_ids() in src/theme.rs).
Detection is deliberately conservative (src/open_uri.rs::find_path_spans): a token must contain a separator, survive prose-punctuation trimming, resolve against the session working directory, and exist before it becomes a link - so a clickable path is always one that opens. Existence probes are cached for 10 seconds (a directory you just created becomes clickable within that window), and lines without a separator are skipped outright. A URL's own path segments are excluded, so https://host/src is a link to the host, not a folder.
Approval mini-diff¶
When a write tool requests approval, the TUI shows a compact diff preview of what will change. The diff is line-numbered with +/- indicators so you can see exactly which lines will be added or removed before approving.
Transcript diffs¶
Edit tools (edit_file, write_file, multi_edit, apply_patch) render a green/red unified diff inline in the transcript — added lines in green bands, removed in red, with a +adds -dels chip on the card header. Cards always show click to peek; the peek dialogue opens the full path + content/diff (not just the short card preview).
Queued follow-ups - steer · cut in · dismiss¶
While a turn is running, typing and sending queues a follow-up. The transcript shows a queued card with:
| Action | What it does |
|---|---|
| steer | Injects the follow-up into the running turn without cancelling it: tools, subagents and background jobs keep going, and the message lands at the next model round. When idle, it starts a normal turn. |
| cut in | Cancels the current turn and runs this follow-up next, with the full prior session context. |
| dismiss | Drops the follow-up without sending. |
Left alone, a queued follow-up runs after the current turn finishes.
Prompt menu — fork · edit · revert · copy¶
Right-click or double-click any of your prompts (in the transcript or on the sticky header) to open a small menu — styled like every other dialogue:
| Action | What it does |
|---|---|
| Fork | Branch into a new session seeded with the conversation up to that prompt. The original session is kept intact on disk; the prompt lands in your input to continue the fork. |
| Edit | Load the prompt into the input without rewinding history. Send to interject as a new turn with full prior context kept. |
| Revert | Rewind the session to just before that prompt (transcript, messages, and the model's context are all truncated). The prompt returns to the input to edit and resend. |
| Copy | Copy the prompt text to the clipboard. |
No keyboard shortcuts — move the highlight with the wheel or ↑/↓, choose with Enter or a click, dismiss with Esc, the ✕, or a click outside.
Sessions browser¶
Open with /sessions (alias /resume). Browse recent sessions with a prompt-first picker — see the first user message of each session to find the one you want.
- Defaults to all workspaces (not only the current cwd). Toggle here / all with Tab or the scope chip.
- Scans
~/.nur/sessions. - Lists show message counts, tokens, and estimated cost so high-spend sessions are easy to spot.
- Session saves write a sidecar
.json.bakbefore overwrite.
Takeover window¶
The same modal has a second window for foreign sessions. Press c (or i) in either one to switch; the footer always names the window you'd switch to.
/takeover(alias/hijack) opens it directly;/sessions→cgets there too.- Lists migratable Claude Code · Codex · Cursor · Grok Build sessions. ↵ imports one into a native session and resumes it.
- Defaults to all workspaces;
Tabnarrows to the current folder, same as the sessions window. Claude Code stores sessions per project directory, so a folder-scoped listing would hide every session outside that exact directory. - Foreign and native sessions never share a list —
cswitches windows rather than merging them. - Press
cagain to go back to the sessions window.
Sticky prompt¶
The PROMPT banner stays visible at the top as you scroll, so you always see the context of the conversation. It is an overlay on the top two rows: the transcript underneath never shifts when it appears or disappears, so the scrollbar and a drag stay steady as you pass prompts.
Splash screen¶
The splash shows the active model title. The rest of the chrome is model-agnostic.
ADE / Orca integration¶
NurCLI writes live status files for host panels:
| Path | Contents |
|---|---|
~/.nur/status.json |
Live tokens, cost, model, state |
~/.nur/usage.jsonl |
Per-request log; purpose says what each request was for (chat, compaction, compaction-remote, fusion, subagent) |
~/.nur/ade.json |
Discovery manifest |