Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Claude Code — UI Layout Reference

Agent-specific layout reference for Claude Code (Anthropic). See agent-ui-analysis.md for shared concepts.

Observed version: v2.1.81 (2026-03-21) Rendering engine: Ink (React for terminals) Rendering approach: ANSI relative cursor positioning (\033[NA, \033[1B)


Layout Anatomy (bottom → top)

[agent output / response text]
[empty line(s)]
✶ Undulating… (1m 32s · ↓ 2.2k tokens)     (spinner — above separator, while working)
[empty line]
──────────────────────────────────── (upper separator, may contain label)
❯ [user input]                       (prompt line)
──────────────────────────────────── (lower separator)
  [status line(s)]                   (0-N lines, indented 2 spaces)
  [mode line]                        (last row, indented 2 spaces)

Real-world Examples (live sessions, 2026-03-21)

Standard idle — no subprocess

❯
──────────────────────────────────────────────────────────────────────────
  [Opus 4.6 (1M context) | Max] │ tuicommander git:(main*)
  Context █░░░░░░░░░ 8% $0 (~$2.97) │ Usage ⚠ (429)
  ⏵⏵ bypass permissions on (shift+tab to cycle)

With subprocess — new format (count left)

───────────────────────────────────────────────────────── extractor ──
❯
──────────────────────────────────────────────────────────────────────────
  [Opus 4.6 (1M context) | Max] │ mdkb git:(feat/document-organizer*)
  Context ░░░░░░░░░░ 4% $0 (~$79.88) │ Usage ⚠ (429)
  1 shell · ⏵⏵ bypass permissions on

Subprocess only — no mode indicator

───────────────────────────────────────────────────────── extractor ──
❯
──────────────────────────────────────────────────────────────────────────
  [Opus 4.6 (1M context) | Max] │ mdkb git:(feat/document-organizer*)
  Context ░░░░░░░░░░ 4% $0 (~$79.81) │ Usage ⚠ (429)
  1 shell

Default mode (no bypass) — single status line, no mode line

❯
───────────────────────────────────────────────────────────────────────────────
  [Opus 4.6 (1M context) | Max] ░░░░░░░░░░ 3% | tuicommander git:(main*) |… ○ low · /ef…

Agent working — spinner above, no prompt box

  ⎿  $ ls -la /Users/stefano.straus/Documents/.mdkb/index.sqlite

✶ Undulating…


Separator Line

A row containing a run of 4+ box-drawing characters (─ ━ ═ — ╌ ╍). May contain embedded labels:

────────────────────────────────────────────────────────────────────────────────
──────────────────────────────────────────────────────────────── extractor ──
──────── ■■■ Medium /model ────────

Spinner / Timer Lines (above upper separator)

✶ Undulating…
✻ Sautéed for 1m 19s
✳ Ideating… (1m 32s · ↓ 2.2k tokens)
✻ Sautéed for 2m 9s · 1 local agent still running
· Proofing… (1m 14s · ↓ 1.6k tokens)

Markers: (U+2736), (U+273B), (U+2733), (U+2722), · (U+00B7). Detected by is_chrome_row (✻ check) and parse_status_line (dingbat range U+2720–U+273F).


Status Lines (between lower separator and mode line)

Zero or more lines. Content is arbitrary and agent-customizable. Indented with 2 spaces (via \033[2C).

  [Opus 4.6 (1M context) | Max] │ tuicommander git:(main*)
  Context █░░░░░░░░░ 5% $0 (~$0.64) │ Usage ⚠ (429)

Or Wiz HUD:

  [Opus 4.6 | Team] 54% | wiz-agents git:(main)
  5h: 42% (3h) | 7d: 27% (2d)
  ✓ Edit ×7 | ✓ Bash ×5

Configured via ~/.claude/settings.jsonstatusLine, but rendered through the PTY using ANSI cursor positioning. They appear as changed_rows and pass through is_chrome_row.

Custom status lines are never a detection signal. Their content is user-defined — the two blocks above are just two of countless possible layouts — so nothing in the state machine reads them: no model name, no context percentage, no cost, no usage counter is parsed from these rows. They matter in exactly one direction, getting classified as chrome so they do not reset the silence timer or stamp last_output_ms.

Coverage today (chrome.rs, asserted by status_line_not_chrome, cc_status_context_bar, cc_wiz_hud_line):

Rowis_chrome_rowWhy
Context █░░░░░░░░░ 8% $0 (~$2.97) │ Usage ⚠ (429)yesblock glyphs /
[Opus 4.6 (1M context) | Max] │ repo git:(main*)nocarries no chrome glyph — known gap
5h: 42% (3h) | 7d: 27% (2d)nosame gap

A status line is also barred from proving the agent is alive: is_spinner_row requires the spinner glyph to lead the row, so a HUD progress bar that ticks every second cannot be read as a working spinner. That rule is the fix for the regression that pinned Claude BUSY forever under a wiz status bar (#446-596f).


Mode Line (last row)

The final visible row. Always chrome. Indented with 2 spaces.

Observed variants

FormatExampleSource
Mode only ⏵⏵ bypass permissions ontest
Mode + hint ⏵⏵ bypass permissions on (shift+tab to cycle)live
Mode + subprocess (old) ⏵⏵ bypass permissions on · 1 shelltest
Mode + subprocess (old, plural) ⏵⏵ bypass permissions on · 2 local agentstest
Subprocess + mode (new) 1 shell · ⏵⏵ bypass permissions onlive
Subprocess only 1 shellscreenshot
Plan mode ⏸ plan mode on (shift+tab to cycle)test
Accept edits ⏵⏵ accept edits on (shift+tab to cycle)test
Auto mode ⏵⏵ auto modetest
Empty``test
Absent (default mode)N/A — no mode line at alllive

Key markers

  • ⏵⏵ (U+23F5 x2) — current mode-line prefix
  • ›› (U+203A x2) — older mode-line prefix
  • (U+23F8) — plan mode prefix
  • · (U+00B7) — separator between mode and subprocess count

Subprocess types observed

shell / shells, local agent / local agents, bash, background tasks


Interactive Menus

Permission Prompt

Replaces the entire bottom zone when CC requests tool approval.

⏺ Write(/tmp/test-permission-prompt.txt)
────────────────────────────────────────── (BLUE separator, rgb 177,185,249)
 Create file
 ../../../../../tmp/test-permission-prompt.txt
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ (dotted ╌ U+254C, rgb 80,80,80)
  1 hello
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
 Do you want to create test-permission-prompt.txt?
 ❯ 1. Yes                                (❯ colored BLUE, rgb 177,185,249)
   2. Yes, allow all edits in tmp/ during this session (shift+tab)
   3. No

 Esc to cancel · Tab to amend
FeatureNormalPermission prompt
Top separatorGray (rgb 136,136,136)Blue (rgb 177,185,249)
Content separatorNoneDotted (U+254C)
charGray promptBlue selection (rgb 177,185,249)
Mode line⏵⏵/⏸ on last rowNone
Last lineMode indicatorEsc to cancel · Tab to amend

Custom Ink Menu (e.g., /wiz:setup)

────────────────────────────────────── (dim gray separator, \033[2m)
← ☐ Essential  ☐ Workflow  ☐ Tools  ✔ Submit  →
Select essential components to install:
❯ 1. [ ] notifications              (checkbox, ❯ blue)
  ...
────────────────────────────────────── (dim gray separator)
  6. Chat about this
Enter to select · Tab/Arrow keys to navigate · Esc to cancel

May clear the entire screen (\033[2J\033[3J\033[H).

Built-in Menu (/mcp)

───────────────────────────────────── (blue separator, rgb 177,185,249)
  Manage MCP servers
  ❯ tuicommander · ✔ connected
    context7 · ✔ connected
    mac · ✘ failed
  ※ Run claude --debug to see error logs
  https://code.claude.com/docs/en/mcp for help   (OSC 8 hyperlink)
 ↑↓ to navigate · Enter to confirm · Esc to cancel   (italic, \033[3m)

Built-in (/stats)

───────────────────────────────────────────────────────────────────────
    Overview   Models
      Mar Apr May Jun ... Mar
      ··········░·▓██▓█·
  ...
  You've used ~29x more tokens than The Count of Monte Cristo
    Esc to cancel · r to cycle dates · ctrl+s to copy

Built-in (/status)

───────────────────────────────────────────────────────────────────────
   Status   Config   Usage
  ╭───────────────────────────────────────────────────────────────────╮
  │ ⌕ Search settings...                                             │
  ╰───────────────────────────────────────────────────────────────────╯
    Auto-compact                              true
    ...
  ↓ 3 more below
  ←/→ tab to switch · ↓ to return · Esc to close

Uses box-drawing ╭╮╰╯│ for search box (not matched by is_separator_line).


OSC 777 Notifications

CC emits terminal notifications for user attention events:

\033]777;notify;Claude Code;Claude needs your permission to use Write\007
\033]777;notify;Claude Code;Claude Code needs your attention\007

All share the prefix \033]777;notify;Claude Code;.


Ink Rendering Mechanics

Spinner animation (above separator)

\033[8A          ← cursor UP 8 rows (to spinner position)
✶               ← overwrite spinner character
\r\n × 7        ← 7 empty newlines back down to bottom

The cursor-up count equals the bottom zone height:

  • 8 = bypass mode (spinner + empty + sep + prompt + sep + 2 status + mode)
  • 6 = default mode (spinner + empty + sep + prompt + sep + 1 status, no mode)
  • 10 = with subprocess in bypass mode

Full bottom zone redraw

\r\033[1B  separator ────
\r\033[1B  ❯ [input]
\r\033[1B  separator ────
\r\n       \033[2C [status line 1]    ← 2C = cursor forward 2 = indent
\r\n       \033[2C [status line 2]
\r\n       \033[2C [mode line]

Key implications

  • All bottom-zone rows transit the PTY as ANSI sequences
  • The vt100 parser processes them into screen buffer rows
  • Spinner updates touch the spinner row AND all rows below it, causing the entire bottom zone to appear as changed rows
  • The 2-space indent on status/mode lines comes from \033[2C