Skip to main content
Version: MVP

Terminal UI

7 min readFor operatorsUpdated 2026-05-26

What you'll do

Launch Craik's canonical interactive runtime, work from a chat-first terminal surface, use structured slash commands without leaving the TUI, search current-session output, and review auth, approval, receipt, or confirmation decisions in inline modal flows.

Starts before setup.

The TUI is an operator shell, not an auth gate. It opens before a provider, model, or operator session is configured, then shows readiness state and next actions from inside the same interface.

Launch

Use craik in an interactive terminal. Craik detects the TTY and launches the Textual TUI by default:

craik

Add --name to label the shell session in the status bar and /sessions output:

craik --name "Desk review"

The explicit TUI entrypoints still work:

craik --tui
craik tui

Use --no-tui or CRAIK_NO_TUI=1 when you need the plain shell path for debugging, scripts, or terminal compatibility checks:

craik --no-tui
CRAIK_NO_TUI=1 craik

Non-TTY use stays plain-output by design. Piped commands, CI jobs, and scripted invocations do not open the TUI.

Layout

Transcript

Scrollable prompt, response, link, and audit-trail output.

Slash Popup

Command and argument completions while typing /.

Working Indicator

Elapsed-time status while an agent task is in flight.

Run Activity

Compact live backend, tool, target, approval, denial, queue, and stop-key state.

Input

Bordered prompt region with CLI-prefix detection and paste collapse.

Status Bar

Craik · model · state · mode · session · Claude mode · backend · run state · usage · quota · auto-approve · cwd at the bottom edge, omitting unavailable optional fields.

Modals

Focused auth, logout, and approval decisions without leaving the runtime.

The bottom status bar uses the Craik brand accent for the wordmark and subdued terminal colors for model, readiness, mode, and working directory. Token and quota indicators shift from green to yellow, orange, and red as available capacity tightens. Provider quota data is shown only when the provider exposes non-sensitive rate-limit headers; unauthorized or missing quota endpoints are hidden instead of producing noisy warnings. When the active local policy auto-approves capabilities, the bar includes an auto-approve indicator and /status includes the matching policy id and operator-review warning.

Run-related fields appear only while they are relevant: the named shell session shows when --name or /rename set one, the green Claude <mode> chip mirrors the active Claude Code permission mode (default, acceptEdits, plan, auto), the cyan backend chip names the active run backend (for example claude-code), and the yellow run state chip reports the current run phase such as running or interrupted. CRAIK_THEME=dark|light|monochrome overrides auto-detection. NO_COLOR=1 uses the monochrome path. Use /theme dark, /theme light, or /theme monochrome to persist a theme without restarting the TUI.

The status bar is deliberately quiet: dim text, no highlighted background, and one blank footer row below it so the runtime state does not read as a banner. Transcript dividers use a small centered dot leader, while transient receipt and state changes use a brief lavender accent glyph.

Commands

The TUI uses slash commands as the primary operator control surface:

/help
/status
/login
/auth login openai
/auth status
/provider
/model list
/model set openai/gpt-4o-mini
/mode acceptEdits
/run --backend claude-code Update the docs
/run list
/run inspect <run-or-task-id>
/run timeline <run-or-task-id>
/sessions
/rename Desk review
/resume <session-id>
/theme light
/clear
/copy selection
/copy last
/export transcript
/approvals
/approvals decide <approval-id>
/receipts
/receipts detail <receipt-id>
/gateway
/skills
/mcp
/mcp verbose
/exit

Commands either execute inline, print structured status into the transcript, or open a modal. Setup guidance uses slash-command form while you are inside the TUI, including /login for operator-session authentication.

Run /help <command> for a detail page generated from the slash-command registry. Detail pages include usage, output shape, readiness requirements, examples, action keys, and confirmation notes. If you type a known command without the slash, such as provider, Craik shows a toast with Tab to convert and Enter to send the original text to the model.

/mcp summarizes configured MCP clients from Craik local state. Use /mcp verbose to inspect policy, receipt, redaction, and advertised tool metadata, or add --json when another tool needs structured output.

Use /run --backend claude-code <prompt> to create a Craik task, case file, run, output record, receipt, and handoff while delegating execution to the local Claude Code CLI with the default Claude Code tool set enabled. The backend uses the active /model set ... selector for opus, sonnet, or haiku, and honors the current Claude permission mode shown in the footer. Before the run starts, the TUI asks for one-time authority to read the repository, write documentation files, write Craik receipts/handoffs, and run verification commands. Approving creates an approval.decide receipt attached to the run; denying stops before a task is created. Non-interactive dispatch must set CRAIK_CLAUDE_CODE_RUN_APPROVED=1 deliberately or the backend rejects the Claude Code run.

Raw prompts and /run <prompt> now enter the same audited Gateway session path used by craik run prompt <prompt> and craik tui-backend --jsonl. The Gateway emits lifecycle events for prompt submission, model/profile selection, run start, progress, receipts, outputs, completion, and errors. That keeps the TUI responsive while the backend is working and gives future Textual, Rust, desktop, and channel clients the same provenance stream.

craik tui-backend --jsonl is the first frontend protocol. It reads JSONL messages from stdin:

{"type":"session.status"}
{"type":"model.set","model":"anthropic/claude-opus-4-7","reasoning_effort":"high"}
{"type":"prompt.submit","text":"Review the plan"}
{"type":"slash.submit","text":"/run list"}
{"type":"approval.decide","approval_id":"approval_123","decision":"approved","reason":"reviewed"}
{"type":"run.interrupt","run_id":"run_123","reason":"operator requested stop"}

and writes JSONL Gateway events such as session.ready, run.progress, model.changed, approval.resolved, run.interrupt.requested, receipt.created, and run.completed. Use /mode (or press Shift+Tab to cycle) to choose the Claude Code permission mode for the next run. The current mode is shown both in the status bar's Claude <mode> chip and the activity panel header:

ModeBehavior
defaultClaude Code follows its built-in tool gating and asks for permission on each write or shell call.
acceptEditsEdits proceed without per-call prompts; other tool gates still apply.
planClaude Code plans without writing or executing — useful for previewing intent.
autoClaude Code proceeds through edits and tool calls without per-call prompts.

Plan mode asks Claude Code to plan without editing; switch to Accept Edits or Auto before /run --backend claude-code ... when you want it to modify files. During execution the TUI streams Claude Code progress events into the transcript, including assistant text, tool-use markers, tool targets, and permission-denial summaries. Craik also persists the raw Claude Code stream events, parsed progress events, structured tool events, changed-file targets, commands, permission denials, and runtime approval requests in the run output so failures can be inspected later. Diff-like tool output highlights added, removed, and hunk lines in the transcript. Use /run list and /run inspect <run-or-task-id> to review the recorded run state, outputs, receipts, and activity summary after execution. If Claude Code emits a runtime approval-request event, Craik records and displays it as activity without opening a second Craik modal. The local Claude Code -p stream path does not provide a reliable channel for Craik to send a modal decision back into the same subprocess, so mid-run approval events remain observational. Use /mode acceptEdits or /mode auto before starting the run when you want Claude Code to proceed through edits with fewer native prompts. While a run is active, the input remains available. Submitting another prompt queues it and shows the queue count in the activity panel; Craik dispatches the next queued item after the active run completes. Use /run timeline <run-or-task-id> for a chronological event view. Press Ctrl+C while a Claude Code run is active to request interruption. Craik terminates the active Claude subprocess, records the run as interrupted, and persists an interruption receipt/handoff summary. /stop and /interrupt also request interruption when the composer is available, but Ctrl+C is the reliable control while input is paused.

Prefix a line with ! to run a local command without model involvement:

! npm test

Shell mode executes through Craik's local-process backend with shell=False. Each invocation writes a redacted shell_invocation receipt, HMAC signs it, and stores redacted stdout/stderr side logs under ~/.craik/state/shell-output/.

Use /rename <name> to rename the current shell session. Valid names are 1 to 64 characters and may contain letters, numbers, spaces, _, and -. The name is local operator metadata, so avoid putting secrets or prompt content in it.

If you accidentally type a shell command shape such as craik auth login openai into the TUI prompt, Craik leaves your input in place and shows a warning with the matching slash-command path. Press Ctrl-D to exit if you intended to run a command from your operator shell.

Walkthrough

Use this path to verify the v0.12.3 interactive surface from a clean local home without choosing a provider first:

craik --name "Desk review"
/status
/theme monochrome
/rename Desk review
/mcp
! python -c "print('walkthrough')"
/sessions
/help
/help clear
/receipts
/clear

Expected behavior:

Launch

The TUI opens before auth and keeps setup guidance in /status.

Name

The status bar and /sessions show Desk review.

Theme

/theme monochrome persists the monochrome terminal palette.

Slash help

/help clear shows usage, output shape, and confirmation behavior.

Receipts

/receipts renders a structured receipt table or an empty-state message.

Shell

The ! command returns output inline and records a signed shell receipt.

Confirmation

/clear opens a confirmation modal before discarding visible transcript lines.

Completion

Slash completion starts when you type /. Completion is context-aware:

/auth login

Lists configured provider families.

/model set

Lists aliases and provider default model selectors.

/resume

Lists persistent sessions sorted by recent activity.

/approvals decide

Lists open approval ids.

Typing @ opens file mention completion for paths under the current working directory. Selected paths are inserted as @path tokens and resolved by the runtime when the prompt is submitted.

Input Ergonomics

Press Ctrl+R to open reverse history search above the input region. Typing filters local shell history newest-first, Up and Down move through matches, Tab inserts the selected match, and Enter submits it immediately. Esc dismisses without modifying the input. Ctrl+S cycles the search label through session, project, and all-history scopes.

Press Ctrl+F to search the current transcript. Typing filters visible session output, Enter moves to the next match, Backspace edits the query, and Esc returns focus to the prompt. Search is current-session only.

Keyboard Bindings

BindingAction
Ctrl+DExit the TUI.
Ctrl+FOpen transcript search over visible session output.
Ctrl+ROpen reverse history search above the input region.
Ctrl+GOpen the current input buffer in $EDITOR.
Ctrl+X then Ctrl+EEmacs-style chord that also opens $EDITOR on the current input.
Ctrl+CInterrupt the active run (Claude Code run or model prompt).
Ctrl+Shift+C or Ctrl+YCopy the current transcript view to the clipboard.
Shift+TabCycle the Claude Code permission mode (default → acceptEdits → plan → auto).
Shift+Enter, Ctrl+J, Alt+EnterInsert a newline in the input region.
EscDismiss the slash-popup, history-search, or transcript-search overlay.

/stop and /interrupt are typed aliases for Ctrl+C and request the same interruption when the composer is available. While input focus is paused, prefer the Ctrl+C binding because it is delivered directly to the runtime.

Text Selection

Craik enables terminal text selection while keeping clickable and keyboard controls active. Click a transcript row to mark it for copying, then run /copy selection or press Ctrl+Y. Shift-click extends the selected row range when the terminal reports modifier state. /copy last copies the latest transcript row, and /export transcript writes the visible session transcript under $CRAIK_HOME/state/exports/. Native terminal click-drag selection still works; use your terminal's copy shortcut for arbitrary text ranges.

Terminal familyCopy shortcut
macOS Terminal and iTerm2Cmd+C
Linux terminal emulatorsCtrl+Shift+C
Windows TerminalCtrl+Shift+C

Selected text uses the active TUI theme's selection highlight. The first TUI launch shows a short toast with the copy reminder. Set CRAIK_TUI_SELECTION_HINT=0 to suppress the hint in scripted demos.

Press Ctrl+G to open the current input buffer in an external editor. Craik uses $EDITOR, then $VISUAL, then vi when available. The temporary file is created under ~/.craik/state/external-editor/ with owner-only POSIX permissions and is removed after the editor exits. If the editor fails, the original input stays unchanged.

Craik tokenizes $EDITOR with shlex.split and executes the editor with shell=False. Shell metacharacters are not expanded; the variable's literal value is the editor command. A misconfigured value such as rm can still delete the temporary draft file, so check echo "$EDITOR" if editor behavior looks wrong.

Multi-line input works through four equivalent paths:

MethodUse
Shift+EnterNative terminal newline where supported.
\ + EnterUniversal continuation marker; Craik removes the trailing backslash.
Ctrl+JUniversal terminal newline binding.
Option/Alt+EnterMeta newline where the terminal sends Option/Alt as Meta.

History

The TUI persists prompt and slash-command history locally:

ModeHistory file
Single-operator local~/.craik/state/shell-history.jsonl
Audited operator mode~/.craik/state/shell-history-<subject-hash>.jsonl
Audited mode without a session yet~/.craik/state/shell-history-anonymous.jsonl

History files use owner-only permissions on POSIX systems. The default cap is 10,000 entries. Set CRAIK_HISTORY_MAX_ENTRIES=0 to disable persistence.

/login shows operator-session login guidance for audited operator mode.

/auth login [provider] opens a credential capture modal with a provider picker and password-masked credential input. The modal verifies the credential before writing the cached profile and never writes credential material to the transcript.

/auth logout [profile] opens a confirmation modal before removing a cached profile or keyring reference.

/approvals decide <approval-id> opens an approval decision modal with the capability, target, risk, policy, and retry path. Approve or deny with a reason; Craik records a redacted decision receipt.

/receipts detail <receipt-id> opens a receipt detail modal showing receipt identity, integrity state, result status, and redacted summary.

/clear opens a destructive-action confirmation modal. Confirming clears the visible transcript and records a redacted slash.confirmation receipt; declining also records the decision. Persisted receipts and side logs remain stored.

Transcript Signals

Craik uses transcript widgets to keep runtime state visible:

  • Action markers show tool actions, waiting states, approvals, and review events tied back to receipt ids.
  • Section dividers separate turns.
  • Long slash-command tables collapse after 50 lines with an expand/search hint.
  • Toasts surface warnings and confirmations with severity-specific lifetimes.
  • URLs render as terminal links where supported.
  • Pasted content with three or more lines collapses to [N lines of text] in the input while preserving the full submitted content.

Security and Redaction

The TUI renders from the same readiness, auth, policy, receipt, and local-store surfaces used by the CLI and dashboard. It does not bypass operator gates for mutating actions. Read-only diagnostics are available before auth so operators can understand setup state and fix configuration without leaving the runtime.

Credential input is masked and redacted. Approval modals show bounded context: capability, target, risk, policy, retry path, and decision receipt ids.

Accessibility

The TUI is keyboard-first and text-native. It avoids mouse-only controls, keeps labels visible, and leaves /help as the linear command index. The bottom hint bar keeps runtime state visible without hiding transcript content. Fixed bindings keep behavior predictable across macOS Terminal, iTerm, Linux terminals, and Windows Terminal.