Skip to content

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:

  1. NUR art
  2. <active provider> loaded · v<cli>
  3. model · cwd · session
  4. Purple ecosystem line (sandbox · subagents · tools + pack status)
  5. 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

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 agent tool'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 /sidegraph toggles the panel (open -> close). off / freeze freezes refresh, on / live resumes, hide / close closes.
  • 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), and minimap (glyph dots) — so a long graph shrinks vertically without touching the transcript, window, or model. /sidegraph zoom / zoom-out / reset do 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+C there copies only the tool output, never the sticky task. The same kid peek opens by double-clicking a pane in the inline /swarm card.
  • Title shows ◈ sidegraph (N) with the step count, ● live + spinner while running, ◼ frozen when 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
  • /sidegraph opens or closes (horizontal split)
  • a click-to-peek closes (image pixels sit outside the cell buffer)
  • /theme offers 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 transparent toggles see-through mode (panels stop painting backgrounds; pairs with a translucent terminal profile; persisted as [theme] transparent)
  • /theme motion toggles 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 default auto already 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:

# use cargo-nextest for test runner, not cargo test

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

/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. |

/codesearch <regex or text>
/cs foo::bar

Runs the workspace grep tool immediately and prints matches in the transcript (no full agent turn).

MCP (/mc)

/mc                 # list sources (default)
/mc sources         # same
/mc status
/mc search <query>

Uses the Executor gateway (executor tool). If MCP is missing:

nur ecosystem ensure

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

/feedback <what happened / what you'd like>

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.

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.bak before 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 → c gets there too.
  • Lists migratable Claude Code · Codex · Cursor · Grok Build sessions. ↵ imports one into a native session and resumes it.
  • Defaults to all workspaces; Tab narrows 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 — c switches windows rather than merging them.
  • Press c again 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
nur install-hook           # install Orca agent hook
orca terminal create --command nur    # launch in Orca