Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

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 DO pass through is_chrome_row.

Bug: These lines contain none of the 4 chrome markers (⏵, ›, ✻, •), so they are not classified as chrome.


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