Terminal UI
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:
| Mode | Behavior |
|---|---|
default | Claude Code follows its built-in tool gating and asks for permission on each write or shell call. |
acceptEdits | Edits proceed without per-call prompts; other tool gates still apply. |
plan | Claude Code plans without writing or executing — useful for previewing intent. |
auto | Claude 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
| Binding | Action |
|---|---|
Ctrl+D | Exit the TUI. |
Ctrl+F | Open transcript search over visible session output. |
Ctrl+R | Open reverse history search above the input region. |
Ctrl+G | Open the current input buffer in $EDITOR. |
Ctrl+X then Ctrl+E | Emacs-style chord that also opens $EDITOR on the current input. |
Ctrl+C | Interrupt the active run (Claude Code run or model prompt). |
Ctrl+Shift+C or Ctrl+Y | Copy the current transcript view to the clipboard. |
Shift+Tab | Cycle the Claude Code permission mode (default → acceptEdits → plan → auto). |
Shift+Enter, Ctrl+J, Alt+Enter | Insert a newline in the input region. |
Esc | Dismiss 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 family | Copy shortcut |
|---|---|
| macOS Terminal and iTerm2 | Cmd+C |
| Linux terminal emulators | Ctrl+Shift+C |
| Windows Terminal | Ctrl+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:
| Method | Use |
|---|---|
| Shift+Enter | Native terminal newline where supported. |
\ + Enter | Universal continuation marker; Craik removes the trailing backslash. |
| Ctrl+J | Universal terminal newline binding. |
| Option/Alt+Enter | Meta newline where the terminal sends Option/Alt as Meta. |
History
The TUI persists prompt and slash-command history locally:
| Mode | History 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.
Modal Flows
/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.