lash / terminal interface dossier

Warm Iron / Fast Amber

The lash TUI is not a glossy desktop app. It behaves like a workshop console: warm-black surfaces, sodium-orange intent markers, ash-grey structure, and just enough ornament to make progress feel tactile. The goal is disciplined terminal presence, not fake skeuomorphism.

Tone
industrial editorial terminal More field notebook than dashboard. More control panel than chat bubble UI.
Current UI cues
sodium, ash, chalk, scribe lines Status chrome and plan/task structures are the strongest recurring visual vocabulary.
Updated for
sticky plan dock Active update_plan checklists live in a single persistent panel anchored to the bottom of the frame, not as inline plan boxes threaded through the transcript.

Identity

lash should read as an operator tool with style, not a toy terminal skin. The logo, language, and layout all lean on cut metal, scoring marks, and measured contrast.

LASH
Agent Runtime
sharp intent quiet chrome progress first terminal-native

Brand character

The interface is terse but not sterile. Sodium is used for decisions, activation, and directional markers. Chalk carries the readable body text. Ash builds the rails, separators, and containers. Everything should feel sturdy enough to hold a long work session without becoming noisy.

Color

The palette is intentionally narrow. Almost every screen is warm black and chalk until sodium appears to signal intent, mode, or the active edge of work.

FORM #0E0D0B · history background, dominant field
FORM_RAISED #141412 · status bar, framed surfaces, overlays
ASH #2A2A28 · borders, dividers, structural lines
ASH_MID #4A4A44 · separators, passive labels, thin chrome
CHALK #E8E4D0 · assistant prose, key readable text
SODIUM #E8A33C · prompt, logo slash, plan/mode indicators
LICHEN #8A9E6C · completion or quiet success accents
ERROR #CC4444 · failures, dangerous edges, interrupt warnings
GHOST_BAR #322818 · assistant bar, subtle live-work trace

Token cascade

Token cascade
flowchart LR A[FORM / FORM_DEEP] --> B[ASH rail system] B --> C[CHALK text hierarchy] A --> D[SODIUM activation] A --> E[LICHEN completion] A --> F[ERROR failure]

Typography

lash’s design language benefits from type contrast: monospaced command authority for chrome, and a calmer reading voice for explanations and documentation.

Display / headers
LASH / STATUS / PLAN
Big Shoulders Display, heavy tracking compression, uppercase only.
Body / editorial copy
Warm-black terminals can get visually dry. A more literary body face softens design documentation without contaminating the TUI itself.
Spectral, medium weight, long-line friendly.
UI / terminal notation
model · plan · cwd
◆ active task
[x] completed step
❯ live prompt
Chivo Mono, compact and readable under dense chrome.

Elements

The TUI is defined less by cards and more by stacked terminal zones: a compact status strip, uninterrupted history, framed plan/plugin blocks, and an input area with mode context pinned on the lower edge.

lash · compact-model 64k / 128k
Use one native checklist tool for substantial multi-step work.
Inspecting plugin/runtime seam and current TUI plan rendering.
Active plan travels in the sticky dock below — not inline. See the plan-dock mock.
queue lanes checkpoint-aware
Queued Input
  • After next tool/result
  • Next full turn
transcript lanes semantic first
wholehog Skill badge — a compact, single-line indicator that replaces the verbose "Model saw transformed input" message. Uses ◆ marker in dimmed sodium with skill name in chalk-dim.
+
cargo test -p lash-cli Shell command rows keep the command itself on the primary line and drop repeated chrome like workdir and exit code.
├─
agent done · inspect queue rendering · 4.2s Subagent results use tree connectors (├─/╰─) to show the child agent's tool call activity as nested items beneath the summary rail.
claude-sonnet · 3 iterations · 5 tool calls
├─
read_file · 12ms
╰─
exec_command · 340ms
+
web "queue preview renderer" Web rows keep the query in the headline and reserve expansion for sources or fetched content.
╭─
edited lash-cli/src/render/mod.rs (+3 -1) Edit rows should feel like revision slates: a calm rail, count-led file copy, then the diff opens beneath it as a separate inspection layer.
revision slate durable artifact
╭─
edited lash-cli/src/render/mod.rs (+3 -1) The first line carries the meaningful outcome, not the transport wrapper.
edited lash-cli/src/render/mod.rs (+3 -1) File rows act like a compact revision ledger. Renames should use arrows, counts should sit on the same line, and status words stay lowercase and precise.
╎ @@ queue preview Patch text lives one level deeper on a scribed inset so scanning the transcript does not collapse into a wall of unified diff noise.
plan dock sticky · single-pane
Rework the anatomy mock so the sub-section gap normalizes at the new breakpoint.
Opening the current mock to audit the spacing ladder.
This one needs a moment…
  • Fix ink 4/ink 3 contrast across themes
  • Rework anatomy layout
  • Collapse sub-section gap + normalize breakpoint
  • Polish mocks + fix toolcall rows attr
  • Quiet the attach thumbnail
  • Typography pass
  • Re-run audit queries
  • Rename graph/knowledgegraph → context map
subagent lifecycle agent tree
spawn agent · inspect queue rendering · 52ms The spawn event uses a filled diamond (◆) when standalone, or a tree connector (├─) when child details follow. Model and tier are shown as detail lines.
claude-sonnet (medium)
├─
agent done · inspect queue rendering · 4.2s The result block shows a summary stats line (model · iterations · tool calls), then renders each child tool call as a nested tree branch.
claude-sonnet · 3 iterations · 5 tool calls
├─
read_file · 12ms
├─
exec_command · 340ms
├─
search_files · 89ms
├─
read_file · 8ms
╰─
edit_file · 45ms
agent stopped · inspect queue rendering · 1.8s Kill events use the standalone diamond and the error color to signal forced interruption.

Layout stack

Layout stack
flowchart TD A[Status Bar] --> B[History Stream] B --> C[Strike Zone while running] C --> D[Task Tray] D --> E[Pending Input Preview] E --> F[Input / Prompt Area]

Texture

lash should never feel flat. The background field is deep and quiet, then layered with scored diagonals, soft noise, and sodium scribe strokes that suggest motion without becoming decorative clutter.

Scribe gradients are used sparingly to give active rails and headers a sense of drag across the page.
Diagonal scoring keeps the background from collapsing into pure black emptiness.
Subtle grain prevents perfect digital cleanliness and helps the UI feel worked-in.

Iconography

lash does not need a full icon set. A handful of repeated terminal-native marks do the job: the slash, the prompt spear, the diamond task marker, and the boxed plan/task rails.

/
slash The brand cut. Use as a decisive interruption, not decoration.
prompt spear The warm-sodium signifier for live input and active agency.
task diamond Denotes active task pressure better than a generic dot.
│ ┌ ┐
terminal rails Plan blocks and trays should feel framed, not carded.

Principles

These rules keep the TUI coherent as new surfaces get added. If a future component breaks one of these, the component should probably change instead of the system.

  1. Accent Means Action

    Sodium is reserved for the active edge — prompts, plan mode, key labels, plan updates, headings that genuinely matter. Info (cool steel blue) is for ambient metadata: scroll position, expansion level, status indicators that inform without demanding attention.

  2. Structure Before Ornament

    Every line, rail, and box should clarify hierarchy before it tries to look good. Beauty comes from discipline.

  3. Terminal Native, Not Faux Desktop

    Use borders, glyphs, spacing, and dense text rhythm. Avoid pretending the interface is a web dashboard squeezed into a terminal.

  4. Mode Separation Should Be Visible

    Plan mode and update_plan are different concepts. The UI should signal planning-only turns as a badge, checklist tracking as a durable block, and plugin-authored proposals as their own framed history panels.

  5. Plan Lives in the Dock, Not Inline

    An active update_plan checklist lives at the logical tail of the transcript — a blank gutter row followed by the item list. No PLAN header, no scribe rule. It is not pinned to the bottom of the frame; scrolling the history scrolls the plan with it, so older turns remain readable without the plan covering any row.

    New activities push in above the plan, so at the foot of history the reader sees the plan framed by whatever just happened. The active step uses ; done uses ; pending uses . is reserved for the live-assistant-text marker so the two never collide visually. No stacked Current Plan / Proposed Plan panes, no duplicate copies across turns.

  6. Long Sessions Must Stay Calm

    The palette and typography should survive hours of reading. No high-saturation backgrounds, no fragile thin text, no ornamental overload.

  7. Every Surface Should Earn Its Height

    Status strips stay compressed. Task trays summarize. Plan blocks are framed because they are durable reference artifacts, not transient chatter.

  8. Semantic First, Transport on Demand

    The first line should name the user-meaningful action — command, query, agent task, task transition, patch result. Transport details belong in expansion or failure states, not as default transcript filler.

  9. Edits Should Read Like Revisions

    Patch output is durable evidence, not a transient tool side effect. Successful edits use lichen green lane rails to visually separate them from explorations (amber) and shell commands (dim chalk). Diff surfaces should feel inspectable rather than dumped.

  10. Glyph Vocabulary Is Load-Bearing

    The transcript has a small, fixed alphabet of lead glyphs. Each carries one meaning:

    • — user input marker (brand amber)
    • — live assistant text only; never reused for plan steps, activity status, or anything else
    • — reasoning gutter (both live-streaming and compact forms)
    • — completed generic activity (bullet, not middle-dot — · is too light to read as "a thing happened")
    • × — failed activity
    • — ask / subagent
    • ▶ / ✓ / □ — plan dock: active, done, pending

    Avoid glyph collisions. If two surfaces want the same symbol, one of them is reading the transcript wrong.

  11. Keybinding Hints Should Be ASCII

    Inline keybinding hints (e.g. the compact reasoning tail's "alt+o to expand") render in terminal fonts that may not carry , , or . Use plain ASCII — alt+o, ctrl+o — so the hint is legible everywhere.

  12. Wrapped Continuations Indent Past the Prefix Column

    When an activity detail line wraps, the continuation row gets two extra columns of indent. The prefix column stays clean and a wrapped line cannot be misread as a new detail item starting fresh.