·Vision
Every visual element on this page is something the terminal can paint: box-drawing characters, truecolor fg/bg, bold/dim/italic, and a single monospace font. No rounded corners, no shadows, no gradients — that's what makes it look like a terminal app instead of a web UI pretending to be one. Inspirations: k9s, btop, lazygit, glow.
01Inline shell
Two zones, no fullscreen. Scrollback on top — every card prints once and stays in the terminal's native scroll history (mouse wheel works, ⇧+drag selection works, copy-paste works). Composer block at the bottom — sticky via Ink's normal render loop, holds the live status row + input + hint. Nothing app-managed scrolls; the terminal's own scrollback is the source of truth.
No top chrome. A top status bar would be pushed off-screen the moment a card prints. Live state (mode / cost / cache / balance) sits in the bottom strip above the input — the only row Ink can pin reliably without alt-screen. Session metadata (workspace · branch · model) prints once at session start as the first row of scrollback and is allowed to scroll away.
◈ session-7 · main · ~/projects/reasonix · deepseek-chat ◇ you · just now refactor the SKIP_DIRS list out of chunker.ts so directory_tree can reuse it ▎ ◆ Reasoning · 3 paragraphs · 412 tok ▸ ▎ ▶ Step 2 of 5 · Refactor exclude config 4.2s · running ▎ ▎ Pull SKIP_DIRS / SKIP_FILES out of chunker.ts so directory_tree ▎ can reuse them. ▎ ▎ ✓ read src/index/semantic/chunker.ts 0.08s · 250 lines ▎ ✓ read src/tools/filesystem.ts 0.07s · 712 lines ▎ ✓ write src/index/config.ts 0.12s · created ▎ ▶ edit src/tools/filesystem.ts running… ▎ ○ verify npm run typecheck && npm test queued ▎ ▶ The change maps to three edits — I'll start with the config module, ▎ then the chunker, then wire it through the CLI command. Each step ▎ ships a passing test before moving on
───────────────────────────────────────────────────────────────────────────────────── ● auto · session-7 · main · $0.018 session · ¥28.4 · cache 91% › type a message · / for commands · @ to attach a file ⏎ send · ^J newline · ↑↓ history · esc abort · ctrl-c quit
Fixed-width baseline: 88 cols. Cards reflow at narrower widths (down to ~60). Wider terminals get extra right-side gutter (we don't full-bleed past 100 cols).
02Palette
Truecolor (24-bit). Every modern terminal supports it — Windows Terminal, iTerm2, VS Code, kitty, alacritty, gnome-terminal, WezTerm. We're not back-porting to 16-color VTs.
Surfacessolid backgrounds — never tint over user's terminal bg
Accentsone color identifies a card type — never two on the same card
Textfive-step grayscale, hierarchy via tone not size
03Glyph vocabulary
All Unicode, all renderable in JetBrains Mono / Cascadia Code / SF Mono / DejaVu Sans Mono. Color comes from the card type, not the glyph.
Card types one glyph per card · always at column 0
Status / stateused inside cards — color carries the state
Structuralbox-drawing + block characters — terminal native
04Type weights
Terminal can't change font size. Hierarchy comes from weight, tone (fg-0 → fg-4), and style (italic). That's it. No sizes, no spacing tricks.
Title · bold + fg-0 · card titles, key names Body · regular fg-1 · primary content text Sub / hint · regular fg-2 · card subtitles, group labels Meta · regular fg-3 · timing, counts, secondary Faint · regular fg-4 · inactive, queued, dim borders Reasoning text · italic + fg-3 · thinking blocks (always italicised) Accent · bold + color · glyphs, status pills, focus
05Cards · user message
No accent bar — the user's input is the conversational anchor, deserves a quieter treatment than agent activity.
◇ you · 2 min ago refactor the SKIP_DIRS list out of chunker.ts so directory_tree can reuse it
06Cards · reasoning
Default collapsed — reasoning is opt-in noise. Always italic + dim when expanded so it never competes with primary content.
▎ ◆ Reasoning · 3 paragraphs · 412 tok ▸
▎ ◆ Reasoning · 3 paragraphs · 412 tok ▾ ▎ ▎ Two paths: replace the hardcoded list when config is set, or merge ▎ user values in. The first matches the explicit "config-driven" ask; ▎ the second is safer default. Going with the first since the user's ▎ words outrank my safety instinct here. ▎ ▎ Files to touch: chunker.ts (drop constants, accept resolved config), ▎ filesystem.ts (drop its own copy), and the index command (load + pass).
07Cards · task / step
A multi-step work unit — wraps tool calls + reasoning under one collapsible header. Default expanded for the active step, collapsed for completed ones.
▎ ▶ Step 2 of 5 · Refactor exclude config 4.2s · running ▎ ▎ Pull SKIP_DIRS / SKIP_FILES out of chunker.ts so directory_tree ▎ can reuse them. ▎ ▎ ✓ read src/index/semantic/chunker.ts 0.08s · 250 lines ▎ ✓ read src/tools/filesystem.ts 0.07s · 712 lines ▎ ✓ write src/index/config.ts 0.12s · created ▎ ▶ edit src/tools/filesystem.ts running… ▎ ○ verify npm run typecheck && npm test queued
▎ ✓ Step 1 of 5 · Read chunker + filesystem 0.4s · 2 tools · done ▸
▎ ✗ Step 4 of 5 · Sandbox check 0.2s · failed ▾ ▎ ▎ ✓ read src/sandbox/policy.ts 0.04s · 88 lines ▎ ✗ verify policy.allows("rm") denied
08Cards · tool call
Single tool invocation. Collapsed = one row. Expanded = input args summary + output preview inside a sharp-cornered code box.
▎ ▣ read_file src/cli/ui/App.tsx 0.08s · 1224 lines ▸
▎ ▣ read_file src/cli/ui/App.tsx 0.08s · 1224 lines ▾ ▎ ▎ 1 /** App.tsx — primary chat surface, owns log + input. */ ▎ 2 ▎ 3 import React, ... from "react"; ▎ … [1218 lines hidden — press space to load all] ▎ 1224 export default App;
▎ ▣ run_command npm run verify 23.4s · exit 0 ▾ ▎ ▎ $ npm run verify ▎ > reasonix@0.17.0 verify ▎ > npm run lint && npm run typecheck && npm run test --silent ▎ … ▎ Test Files 99 passed (99) ▎ Tests 1784 passed (1784)
09Cards · plan / todo
Ordered checklist. State per item via the bracket char + color: [✓] done · [▶] running · [ ] queued · [!] blocked · [✗] failed. Footer offers revise / skip actions.
▎ ⊞ Plan · Migrate selection to terminal-native 5 of 7 done ▾ ▎ ▎ [✓] 1. Snapshot current selection state ▎ [✓] 2. Drop @xterm/headless dep ▎ [✓] 3. Remove screen-mirror.ts ▎ [✓] 4. Strip LogSelection from log-frame.tsx ▎ [✓] 5. Strip drag handlers from App.tsx ▎ [▶] 6. Add /copy slash command ← in progress ▎ [ ] 7. Update CHANGELOG & push ▎ ▎ [r] revise [s] skip step [↵] expand item
10Cards · diff / edit
Per-file changeset. Removed lines coral-red foreground · added green foreground · context dim. No background tinting (fights user's terminal bg). Footer = apply / skip / reject.
▎ ± Edit src/index/semantic/chunker.ts +12 / -47 ▾ ▎ ▎ @@ -30,40 +30,5 @@ ▎ /** Skip lists shared with src/tools/filesystem.ts */ ▎ -const SKIP_DIRS: ReadonlySet<string> = new Set([ ▎ - "node_modules", ".git", ".hg", ▎ - ... 18 more lines collapsed ▎ -]); ▎ +import { DEFAULT_INDEX_EXCLUDES } from "../config.js"; ▎ +const SKIP_DIRS = new Set(DEFAULT_INDEX_EXCLUDES.dirs); ▎ ▎ [a] apply [s] skip [r] reject
11Cards · error
Failed tool call or hard error. Stack folded by default. Coral-red bar + glyph; the body stays at fg-1 except the actual error message line.
▎ ✖ Error tool call failed 2 retries ▾ ▎ ▎ read_file src/index/semantic/chunker.ts ▎ ▎ ENOENT: no such file or directory, open ▎ '/usr/local/etc/secrets/api.key' ▎ ▎ The agent attempted to read outside the sandbox root. Path was ▎ normalised but the absolute prefix put it outside. ▎ ▎ ▸ stack trace ▎ ▎ [r] retry [s] skip
12Cards · warning
Non-fatal: degraded service, slow upstream, soft policy hit. No actions usually — informational.
▎ ⚠ MCP server slow notion · 8.4s elapsed ▾ ▎ ▎ The notion server hasn't responded to tools/list in 8.4s. ▎ The session continues without it; reconnection on next turn.
13Cards · usage / cost
Per-turn meter with three tracks (prompt / reason / output) plus a session running total. Bars use density blocks █░ — terminal renders these natively.
▎ Σ Usage turn 12 $0.0014 · 1.2s ▾ ▎ ▎ prompt ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 41,238 / 1M · 4.1% ▎ reason ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 412 ▎ output ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 1,847 ▎ ▎ cache hit ██████████████████████████░░░ 91.3% ▎ ▎ session ⛁ $0.018 · balance ¥ 28.4 ≈ ¥0.10 / turn at this rate
14Cards · sub-agent
Forked agent runs in a nested mini-stream. Each nesting level adds another ▎ bar — depth is visually obvious without extra chrome.
▎ ⌬ Sub-agent · code-reviewer running ▾ ▎ ▎ Task review the diff in src/index/config.ts for safety ▎ Tools read_file, search_content ▎ ▎ ▸ sub-agent stream ▎ ▎ ◆ Reasoning · 2 paragraphs ▸ ▎ ▎ ▣ read_file src/index/config.ts 0.08s ▎ ▎ ▶ streaming response …
15Cards · approval prompt
Modal — cannot scroll past until resolved. Header band uses bg-elev + 3-cell amber left edge; body sits on default bg. The bg→default transition is the visual divider, no extra ruling required.
? Approve · run_command awaiting The agent wants to run: $ rm -rf node_modules dist Working dir /home/user/project Effect removes 12,847 files (228 MB) ▸ allow once run this command, ask again next time allow always remember `rm -rf` for this project deny skip; agent will pick an alternative ───────────────────────────────────────────────────────────────────────────── ↑↓ pick · ⏎ confirm · esc cancel
16Cards · streaming response
Live text in progress. Brand-blue accent bar like a task card, but the body is bare prose — no glyph header, just a leading ▶ caret on the first line and a blinking cursor at the tail.
▎ ▶ The change you described maps cleanly to the existing ▎ ResolvedIndexConfig structure. Three edits are needed: ▎ ▎ 1. src/index/config.ts: add the new excludePatterns field ▎ 2. src/cli/ui/App.tsx: surface it in the Settings card ▎ 3. tests/index-config.test.ts: cover the merge semantics ▎ ▎ Want me to draft the diff?
17Cards · search results
Hit list grouped by file. Match terms inverse-highlighted (terminal native). Each row clickable — opens a tool-call card focused on that file:line.
▎ ⊙ Search "writeClipboard" 3 hits in 2 files · 0.04s ▾ ▎ ▎ src/cli/ui/clipboard.ts ▎ 15 │ export function writeClipboard(text: string): ClipboardWrite ▎ ▎ src/cli/ui/App.tsx ▎ 85 │ import { writeClipboard } from "./clipboard.js"; ▎ 1491 │ writeClipboard(text); ▎ ▎ ↑↓ navigate ⏎ open hit [n] narrow…
18Cards · memory / context
What's currently in scope from persistent memory. Default collapsed — a one-line summary. Expanded breaks down by category (user / feedback / project / reference).
▎ ⌑ Context · 4 user · 2 feedback · 1 reference ~1.2K tok ▸
▎ ⌑ Context · 4 user · 2 feedback · 1 reference ~1.2K tok ▾ ▎ ▎ USER ▎ ◇ Reasonix maintainer · prefers terse Mandarin replies ▎ ◇ Windows Terminal + PowerShell · CNY/RMB balance ▎ ▎ FEEDBACK ▎ ✦ No Co-Authored-By: Claude trailer in commits ▎ ✦ Comments document why, not chat history ▎ ▎ REFERENCE ▎ → Linear "INGEST" project tracks pipeline bugs
19Composer · input states
The composer is the bottom-sticky input zone. One row of input + one row of hints. Pickers (`/`, `@`, history) overlay above the input row, never below — mouse / scroll never hides them.
Empty / placeholderfirst row, no text yet
› type a message · / for commands · @ to attach a file ⏎ send · ^J newline · ↑↓ history · esc abort · ctrl-c quit
Typingcursor at end of single line
› refactor the SKIP_DIRS list out of chunker.ts so directory_tree ⏎ send · ^J newline · ↑↓ history · esc abort · ctrl-c quit
Multi-line^J inserts newline; continuations indent under the prompt glyph
› refactor the SKIP_DIRS list out of chunker.ts so directory_tree can reuse it, also strip the duplicate from filesystem.ts ⏎ send · ^J newline · ↑↓ history · esc abort · ctrl-c quit
History recall↑ pops a popover with prior turns; ↵ loads the highlighted entry into the input
history · 12 / 47 14 · 3m show the last failing tool call 13 · 8m what's the cache hit rate today ▸ 12 · 14m refactor the SKIP_DIRS list out of chunker.ts so directory_tree … 11 · 22m drop the screen-mirror module entirely 10 · 1h why is the indexer skipping .gitignore'd dirs? ↑↓ pick · ⏎ load · esc cancel › refactor the SKIP_DIRS list out of chunker.ts so directory_tree can …
Paste collapsedlarge clipboard payloads collapse to a chip; ^O expands into a separate panel
› here's the stack trace: ┌ 📋 pasted 142 lines · 4.8 KB · stacktrace ^O expand · ⌫ remove ┐ what's going on? ⏎ send · ^J newline · ↑↓ history · esc abort · ctrl-c quit
@ mention pickertyping `@` opens a file picker filtered by the substring after it
files · "ui/log" · 8 matches ▸ src/cli/ui/log-frame.tsx 1134 lines · ts src/cli/ui/log-rows.tsx 613 lines · ts src/cli/ui/EventLog.tsx 961 lines · ts src/cli/ui/LiveRows.tsx 360 lines · ts … 4 more ↑↓ pick · ⏎ insert · esc cancel › why is @ui/log
/ command pickertyping `/` opens slash-command picker; descriptions are dim, names are fg-0
commands ▸ /cost show cost & token usage for this turn /context show what's currently in the prompt context /memory view / edit persistent memory /diff diff session changes vs HEAD /copy copy last N rows to clipboard /init generate CLAUDE.md from current repo /doctor health check (api / index / workspace) /clear clear the on-screen scrollback … 6 more ↑↓ pick · ⏎ run · esc cancel › /
/ arg pickercommands with required args open a second-stage picker
/copy · pick range ▸ last 1 most recent card only last 5 last five cards last 10 last ten cards all whole session custom… type a number ↑↓ pick · ⏎ run · esc cancel › /copy
! shell modeleading `!` swaps the prompt to a shell; sends the line to a shell tool, not the model
$ git status shell mode · ⏎ run · esc back to chat · output appears as a tool card above
Abortedesc during a turn — the agent stops, the composer reopens with a faint hint
› turn aborted by user · esc again to clear · ⏎ to ask a follow-up
20Status row · live state
Single row pinned above the composer input. The only place live state can sit reliably without alt-screen — Ink redraws this row every frame, so it never scrolls away. Carries: mode pill · session id · running cost · balance · cache hit. Mockups below show the row + the input/hint underneath for context.
Mode pillsone of: auto · ask · plan · edit; pill color reflects the action class
───────────────────────────────────────────────────────────────────────────── ● auto · session-7 · main · $0.018 · ¥28.4 · cache 91% ───────────────────────────────────────────────────────────────────────────── ◐ ask · session-7 · main · $0.018 · ¥28.4 · cache 91% ───────────────────────────────────────────────────────────────────────────── ⊞ plan · session-7 · main · $0.018 · ¥28.4 · cache 91% ───────────────────────────────────────────────────────────────────────────── ± edit · session-7 · main · $0.018 · ¥28.4 · cache 91%
Network statesdot color = state; verbose text appears only when not green
───────────────────────────────────────────────────────────────────────────── ● auto · online · session-7 · main · $0.018 · cache 91% ───────────────────────────────────────────────────────────────────────────── ◌ auto · slow · 4.2s p95 · session-7 · main · $0.018 · cache 91% ───────────────────────────────────────────────────────────────────────────── ✗ disconnect · retry 3/5 · session-7 · main · $0.018 · cache 91% ───────────────────────────────────────────────────────────────────────────── ↻ reconnecting… · session-7 · main · $0.018 · cache 91%
Auto-confirm countdownin auto mode after a tool emits an approval — countdown digit flashes brand, esc to cancel
───────────────────────────────────────────────────────────────────────────── ● auto · approving in 3s · esc to interrupt · cache 91%
Live cost tickerturn cost on the left, session total on the right; balance ¥ shows when DeepSeek wallet is hooked
───────────────────────────────────────────────────────────────────────────── ● auto · ▸ $0.0014 turn · $0.0193 session · ¥30.5 · cache 91%
RecordingREC pill replaces the mode pill while a recording is being written
───────────────────────────────────────────────────────────────────────────── ●REC 1.4 MB · 142 evt · → ~/.reasonix/recordings/2026-04-29.jsonl · ^R stop · ^P pause
21Modals · the full family
Every modal opens with a header band — a single bg-elev row with a 3-cell colored left edge that signals the action class (warn / accent / info / err / ok). Body sits on default bg below; the bg→default transition is the divider, so no full-box border is needed. Up/down picks, ⏎ confirms, esc cancels — always.
Plan · confirmdrafted plan above; the user picks the disposition
⊞ Approve plan awaiting The agent has drafted a 5-step plan above. ▸ accept run it now, in order refine give the agent more guidance, draft a new plan revise edit the plan inline before running reject discard, agent will retry from scratch ───────────────────────────────────────────────────────────────────────────── ↑↓ pick · ⏎ confirm · esc cancel
Plan · refinefree-text guidance that goes back into the planner prompt
✎ Refine plan Tell the agent what to change about the plan above. Free text; the planner re-runs with this added as guidance. › skip step 4 — the sandbox check is overkill, just rely on the verify gate ───────────────────────────────────────────────────────────────────────────── ⏎ submit · esc cancel
Plan · revisestructural edit of the plan: skip / reorder / strike steps without retalking to the model
✎ Revise plan · 5 steps [✓] 1. Read chunker + filesystem [✓] 2. Drop @xterm/headless dep [s] 3. Remove screen-mirror.ts ← skipped ▸ [ ] 4. Strip drag handlers from App.tsx [ ] 5. Run verify gate ───────────────────────────────────────────────────────────────────────────── ↑↓ focus · space toggle skip · k/j move · ⏎ accept · esc cancel
Plan · checkpointsnapshot the plan + workspace before running so abort can resume cleanly
⛁ Save checkpoint Snapshot current plan + workspace before running? If something goes wrong mid-run, you can resume the plan from this exact state instead of starting over. ▸ save & continue recommended for plans > 3 steps skip run without snapshotting ───────────────────────────────────────────────────────────────────────────── ↑↓ pick · ⏎ confirm · esc cancel
Workspace · switchopening a different folder mid-session — surfaces unsaved-plan risk
? Switch workspace current ~/projects/reasonix new ~/work/customer-portal Switching ends the current session. Plan progress (3 of 7 done) will be archived; you can replay it later via /replay. ▸ open & archive plan recommended open & discard plan throw away the snapshot cancel stay in this workspace ───────────────────────────────────────────────────────────────────────────── ↑↓ pick · ⏎ confirm · esc cancel
Shelltighter than the generic approval card — shows just the command + 3-way choice
? Shell command $ npm run verify cwd ~/projects/reasonix timeout 120s ▸ allow once run this command, ask again next time allow always remember `npm run verify` for this project deny skip; agent will pick an alternative ───────────────────────────────────────────────────────────────────────────── ↑↓ pick · ⏎ confirm · esc cancel
Edit · multi-filebatch confirmation when several files change in one turn
± Apply 3 edits awaiting src/index/config.ts +84 / -0 created src/index/semantic/chunker.ts +12 / -47 src/tools/filesystem.ts +4 / -28 ▸ apply all land all three, run verify next review one by one step through each diff card with [a/s/r] reject all discard everything; agent will revise ───────────────────────────────────────────────────────────────────────────── ↑↓ pick · ⏎ confirm · esc cancel
Deny w/ reasonafter pressing "deny" on any approval — optional free-text feeds the next attempt
✗ Deny — provide context optional Tell the agent why you denied this. The next attempt will see your reason as additional context. › that command would clobber my git stash — try with `git stash --keep-index` instead ───────────────────────────────────────────────────────────────────────────── ⏎ submit · esc skip (deny without reason)
Generic choicefor ambiguous prompts the agent can't resolve on its own; info-blue border (non-destructive)
? Continue with this approach? My confidence in step 4 is low — the policy file format may have changed in a way I can't verify without running it. ▸ continue trust me, run it try a different approach drop this branch, plan again abort stop here, give me the partial result ───────────────────────────────────────────────────────────────────────────── ↑↓ pick · ⏎ confirm · esc cancel
22Onboarding · welcome / setup / picker
Pre-session screens. These print to scrollback like everything else; once dismissed they don't come back unless the user explicitly opens them again.
Welcome bannerfirst launch in a workspace · single-print, then the empty session screen
╔═══════════════════════════════════╗ ║ ║ ║ ◈ REASONIX ║ ║ ║ ║ DeepSeek-native coding agent ║ ║ cache-first · flash-first ║ ║ ║ ╚═══════════════════════════════════╝ type a message to start your session /help · /init · /memory · /cost
Setup wizardlaunched on first run or via `reasonix setup`; key/value rows, ↑↓ between fields
◈ REASONIX · setup Provider ▸ DeepSeek Anthropic OpenAI ↩ pick Model deepseek-chat · tab to cycle API key •••••••••••••••••••••••••••• ✓ verified Default mode ● auto ◐ ask ⊞ plan space toggle Telemetry ▸ on (anonymous) off Workspace root ~/projects/reasonix Index database ✓ ~/.reasonix/index/reasonix.db 12 days fresh ───────────────────────────────────────────────────────────────────────── ↑↓ field · ⏎ next · esc back · ctrl-s save & exit
Session pickerresume an old session or start fresh; sorted newest-first
◈ REASONIX · pick a session · ~/projects/reasonix ▸ session-7 · main · refactor exclude config 2 min ago 18 turns · $0.18 session-6 · main · TUI redesign yesterday 44 turns · $0.62 session-5 · feat-bg · MCP probe 2 days ago 7 turns · $0.04 session-4 · main · v0.13 row pipeline 3 days ago 93 turns · $1.42 … 12 more ───────────────────────────────────────────────────────────────────────── ↑↓ pick · ⏎ open · [n] new session · [d] delete · [r] rename · esc quit
23Replay & Record
Replay re-renders an old session's events.jsonl in card form. Record snapshots the live event stream for later replay or as bug repro material.
Replay timelineread-only; bottom strip controls playback like a video scrubber
◈ REASONIX · replay · session-6 · main · "TUI redesign" ⏸ 12 / 44 turns ◇ you · 14:22:11 abandon fullscreen mode, switch to inline scrollback ▎ ◆ Reasoning · 4 paragraphs ▸ ▎ ⊞ Plan · 5 steps 5 of 5 done ▾ ▎ [✓] 1. Snapshot current selection state ▎ [✓] 2. Drop @xterm/headless dep ▎ … ───────────────────────────────────────────────────────────────────────────────────── ⏮ first ⏪ -10 ◀ -1 ⏯ play ▶ +1 ⏩ +10 ⏭ last speed 1× · [q] quit
Recordwhile recording, the REC pill replaces the mode pill in the bottom status row (see §20 · Recording)
… normal session cards stream as usual above … ───────────────────────────────────────────────────────────────────────────── ●REC 1.4 MB · 142 evt · → ~/.reasonix/recordings/2026-04-29.jsonl · ^R stop · ^P pause › type a message · / for commands · @ to attach a file
Stats panelreplay-only overlay (or `/stats` in live) — turn-by-turn drill-down
Σ Stats · session-6 · 44 turns · 1h 12m turn role tokens (in / out) tools cache cost elapsed ──── ───────── ────────────────── ───── ───────── ────────── ──────── 1 user 412 / 0 · · · · 2 assistant 37,121 / 1,847 3 91.2% $0.0014 1.2s 3 user 12 / 0 · · · · 4 assistant 38,003 / 2,402 5 93.7% $0.0016 1.6s … ──── ───────── ────────────────── ───── ───────── ────────── ──────── total 1,612,840 / 84,202 142 91.8% $0.62 1h 12m ↑↓ pick row · ⏎ jump in replay · q quit
24MCP · server browser
Reasonix talks to MCP servers (notion / linear / github / fs / …). The browser is a focused panel — list of attached servers, their tool surface, last health-check.
◈ MCP browser · ~/.reasonix/mcp.json · 4 servers ▸ notion ● healthy · 142ms 12 tools · 8 resources · 0 prompts tools/list tools/call resources/list prompts/list linear ◌ slow · 4.2s p95 7 tools · 3 resources · 0 prompts github ● healthy · 88ms 22 tools · 0 resources · 4 prompts fs-local ✗ handshake failed · ENOENT ─ ───────────────────────────────────────────────────────────────────────── ↑↓ pick · ⏎ inspect tools · [r] reconnect · [d] disable · esc quit
25States · empty / streaming / nesting / banners
The variants below are not new card types — they're alternate states of cards already covered, plus a few session-level overlays.
Empty sessionafter /clear or first launch — the only place we volunteer slash-command hints
◈ nothing yet — say something
/help commands & shortcuts
/init generate CLAUDE.md from this repo
/memory view persistent memory
/cost token usage & spend so far
Streaming reasoninglive italic dim while bytes arrive; settles into the collapsed reasoning card on completion
▎ ◆ Reasoning · streaming… ▾ ▎ ▎ Two paths: replace the hardcoded list when config is set, or merge ▎ user values in. The first matches the explicit "config-driven" ask; ▎ the second is safer default. Going with the first since the user's
Long stdout streaminge.g. npm install — tail mode, auto-scroll, ⏯ pauses to let you read
▎ ▣ run_command npm install 12.4s · streaming… ▾ ▎ ▎ $ npm install ▎ ⠋ resolving (1542 packages) ▎ added react@18.3.1 ▎ added react-dom@18.3.1 ▎ added ink@5.1.0 ▎ added ink-text-input@6.0.0 ▎ … ▎ [tail · auto-scroll · ⏯ to pause · ⌫ collapse]
Tool · no outputtool ran but returned nothing useful — single line, no expand
▎ ▣ search_content "writeClipboard" 0.04s · 0 hits ▸
Sub-agent · deep nestingeach level adds a bar — depth becomes obvious without indent text
▎ ⌬ Sub-agent · researcher running ▾ ▎ ▎ ▎ ⌬ Sub-agent · code-reader running ▾ ▎ ▎ ▎ ▎ ▎ ▣ read_file src/cli/ui/App.tsx 0.08s ▎ ▎ ▎ ◆ Reasoning · 1 paragraph ▸ ▎ ▎ ▎ ▎ ▶ summarising findings… ▎ ▎ ▶ aggregating sub-agent reports…
Plan · resumedloaded from a prior session checkpoint; the resume marker shows where to pick up
▎ ⊞ Plan · resumed from session-6 3 of 7 done · ⏮ resume ▾ ▎ ▎ [✓] 1. Snapshot current selection state ▎ [✓] 2. Drop @xterm/headless dep ▎ [✓] 3. Remove screen-mirror.ts ▎ [▸] 4. Strip LogSelection from log-frame.tsx ← resume here ▎ [ ] 5. Strip drag handlers from App.tsx ▎ [ ] 6. Add /copy slash command ▎ [ ] 7. Update CHANGELOG & push ▎ ▎ [↵] resume [r] revise [d] discard checkpoint
Plan · replay archivehistorical, read-only — single line until expanded; ⏪ icon and dim accent
▎ ⊞ Plan · ⏪ archive · session-3 · 2026-04-26 7 of 7 done ▸
Step progresssingle-line completion notice — emitted between steps so you don't need to expand the task card
✓ Step 3 of 5 · Remove screen-mirror.ts 0.4s · done
Disconnect bannernetwork fell over mid-turn — toast-style above the composer, persists until reconnect
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ✗ Disconnected from api.deepseek.com — retrying in 4s [r] retry now · [c] cancel turn ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
26Inline elements
Tiny stylings the agent (or user) drops inside running text — they're not cards, they're enrichments. Each pattern is recognised by a regex on emit and styled by the renderer.
File:line referencerecognised: `path/to/file.ts:42`. Sky underlined; OSC-8 hyperlink so terminals that support it open the editor at that line.
The change you described maps cleanly to src/index/config.ts:24, where DEFAULT_INDEX_EXCLUDES is defined. See also src/cli/ui/App.tsx:1491.
@ mentionamber underline distinguishes user-attached files from agent-discovered references
As we discussed in @src/index/config.ts and @CLAUDE.md, the rules should live in one place.
Countdownlive-decrementing digit, brand color, used in approval / disconnect banners
auto-approving in 3… retrying in 4s… timeout in 12s…
Highlightterminal-native inverse for substring matches; used in search hits and `/find` output
function writeClipboard(text: string): ClipboardWrite import { writeClipboard } from "./clipboard.js";
27Command outputs
Slash commands emit a card just like any other event. Most reuse existing card types — `/cost` produces a Usage card, `/context` produces a Memory card. The two interactive ones (`/memory`, `/doctor`) get their own variants.
/costprints a one-shot Usage card for the most recent turn
◇ you · just now /cost ▎ Σ Usage turn 12 $0.0014 · 1.2s ▾ ▎ ▎ prompt ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 41,238 / 1M · 4.1% ▎ cache hit ██████████████████████████░░░ 91.3% ▎ session ⛁ $0.018 · balance ¥ 28.4
/contextprints a Memory card with what's in the current prompt, including system + history budget
◇ you · just now /context ▎ ⌑ Context · 4 user · 2 feedback · 1 reference ~1.2K tok ▾ ▎ ▎ SYSTEM CLAUDE.md (132 lines) ~480 tok ▎ MEMORY 7 entries from MEMORY.md ~720 tok ▎ HISTORY last 8 turns kept verbatim ~38K tok ▎ TOOLS 14 tools (incl. 4 MCP) ~1.8K tok ▎ FILES 2 attached via @ ~6.2K tok
/memoryinteractive memory editor; navigate, edit, delete entries
▎ ⌑ Memory 7 entries · ~2.1K tok ▾ ▎ ▎ USER (3) ▎ ▸ Reasonix maintainer · prefers terse Mandarin replies ▎ Windows Terminal + PowerShell · CNY/RMB balance ▎ Internal checkpoints over git pollution ▎ ▎ FEEDBACK (3) ▎ No Co-Authored-By: Claude trailer in commits ▎ Comments document why, not chat history ▎ Use libs for text width / unicode ▎ ▎ REFERENCE (1) ▎ Linear "INGEST" project tracks pipeline bugs ▎ ▎ [a] add new [e] edit focused [d] delete focused ↑↓ navigate
/doctorhealth check — pass/fail per check, summary at the bottom
▎ ⚕ Doctor 7 checks · 6 passed · 1 warn ▾ ▎ ▎ ✓ node version v22.10.0 OK ▎ ✓ api key present, 47 chars OK ▎ ✓ deepseek reachable api.deepseek.com 142ms OK ▎ ✓ workspace writable, in git, on main OK ▎ ✓ CLAUDE.md found, 132 lines OK ▎ ⚠ index database 12 days stale, run /reindex warn ▎ ✓ permissions ~/.reasonix readable + writable OK
28Compare · SplitDiff
Side-by-side diff of one file. Used for `/diff <file>` and historical compares. Both panes share line numbers so the eye can sweep across; matching anchor lines align.
▎ ± Compare src/cli/ui/App.tsx +12 / -47 ▾ ▎ ▎ HEAD working tree ▎ ─────────────────────────────────────── ─────────────────────────────────────── ▎ 1 /** App.tsx — primary chat … */ 1 /** App.tsx — chat surface … */ ▎ 2 2 ▎ 3 import React from "react"; 3 import React from "react"; ▎ … … … … ▎ 142 <Box> 142 <InlineShell> ▎ 143 <LogFrame ...> 143 <CardStream ...> ▎ 144 </Box> 144 </InlineShell> ▎ ▎ ↑↓ scroll · h/l switch pane · n/N next/prev hunk · q quit
29Live indicators
Transient one-row signals that print inline, between cards. They're not cards (no accent bar, no expand) — just a visual notification you can scroll past.
Thinking spinnerwindow between user msg and the first reasoning / streaming card
◐ thinking · deepseek-chat · 2.3s esc abort
spinner cycles: ◐ ◓ ◑ ◒ (200ms cadence, ink-spinner pattern)
Context pressureprompt budget warning at 80% / 95% / over-limit
▎ ⚠ Context 821K / 1M · 82% ▾ ▎ approaching the budget; older turns will be dropped past 95%
▎ ✖ Context 990K / 1M · 99% ▾ ▎ trimming oldest 12 turns to fit; expect some short-term memory loss
Undo bannerctrl+z reverted an edit; banner stays for ~5s
↶ Undid: edit src/cli/ui/App.tsx +12 / -47 5s · ctrl+y to redo
Aborted cardesc cut a streaming / tool card mid-flight; the card retains what was printed and tags itself stopped
▎ ▶ — aborted — 1.2s · stopped ▎ The change you described maps cleanly to the existing ▎ ResolvedIndexConfig structure. Three edits ar…[truncated by esc]
Tool retry / repaircache-first loop retried a failed call — header annotates the attempt
▎ ▣ run_command npm run typecheck ↻ retry 1/3 ▾ ▎ ▎ [last attempt timed out at 30s · increasing to 60s] ▎ $ npm run typecheck ▎ …
Checkpoint firedinternal checkpoint system snapshot landed (auto, never via git)
⛁ Checkpoint saved · edit-history#142 · 3 files · 248 bytes /undo to revert
30Markdown rendering
Reference for how markdown elements look when emitted by the model inside reasoning / streaming / assistant cards. Inline spans are styled in place; block elements get their own row.
Inlinestyling that doesn't break the line
A normal sentence with bold and italic and both mixed in. Inline code looks like stringWidth(s) — bg-elev pad, fg-0. A link reads as jump to docs (https://reasonix.dev/docs). A file ref like src/cli/ui/App.tsx:142 is sky underline. A keyboard hint: ⏎ esc — same chip style as inline code.
Blockelements that take whole rows
Heading 2 A paragraph below a heading. Headings render as a band; H1 / H2 / H3 share the same styling — terminal can't change font size. ▎ A blockquote. Sky bar + italic dim, single rule. A bulleted list: · first item · second item · third item A numbered list: 1. first step 2. second step A code block — bg-elev panel, no box, monospace already (we're a TUI): const SKIP = new Set(["node_modules", ".git"]); if (SKIP.has(name)) continue; A table — borders are rule chars, no box-drawing: name size role ──── ──── ──── App.tsx 4.7K root + loop log-frame 1.1K renderer PromptIn 569 composer ───────────────────────────────────────────────────────────────────────────── A horizontal rule above looks like that — fg-4 hairline.
31Editor mode
Triggered by /edit <file> or ctrl+e on a focused diff card. Replaces the composer block (input + status row) with an inline editor pane bound to one file. Esc returns to chat with the buffer intact (dirty marker stays).
± edit src/cli/ui/App.tsx dirty · 4740 lines 1 /** App.tsx — primary chat surface, owns log + input. */ 2 3 import React from "react"; … ▸ 142 <InlineShell> 143 <CardStream ...> 144 </InlineShell> … ───────────────────────────────────────────────────────────────────────────── ↑↓ scroll · ⏎ edit row · ^s save · ^z undo · ^y redo · esc back to chat
± edit src/cli/ui/App.tsx saving… · 4740 lines
± edit src/cli/ui/App.tsx ✓ saved · 0.2s · 4740 lines
32Toasts · transient banners
A toast appears just above the status row hairline, pushing the status row down by one row for ~3s, then unmounts. Used for events the user should notice but doesn't need to act on. Disconnect (§25) is the persistent variant — sticks until resolved.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ✓ Checkpoint saved · 142 events · 3 files snapshotted 3s
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ⓘ Memory updated · 1 entry added · feedback / no-coauthor 3s
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ⚠ MCP `notion` slow · 8.4s p95 over the last 5 calls 5s
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ✗ Tool denied · rm -rf node_modules · sandbox policy 5s
33Help & key reference
Two surfaces: a printed /help card that scrolls into history, and a transient ? overlay that takes over the composer for as long as you hold the key.
/help · printed cardscrollable, comprehensive; reuses the regular card shell
▎ ⓘ Help · keys, commands, modes ▾ ▎ ▎ COMPOSER ▎ ⏎ send the message ▎ ^J newline (multi-line input) ▎ ↑↓ cycle history ▎ / slash command picker ▎ @ file attachment / mention ▎ ! shell mode (one-shot bash) ▎ esc abort current turn ▎ ^c quit ▎ ▎ CARDS ▎ j / k focus next / prev ▎ ⏎ expand / collapse focused ▎ y copy focused card text ▎ ? key overlay ▎ ▎ MODES ▎ /auto approve all tool calls ▎ /ask prompt for each tool call ▎ /plan draft a plan before executing ▎ /edit enter editor mode on focused file ▎ ▎ SLASH COMMANDS — full list at /help all ▎ /cost /context /memory /diff /copy /init /doctor
? overlaytransient cheat-sheet — replaces composer for as long as `?` is held; releases on any keypress
───────────────────────────────────────────────────────────────────────────── shortcuts · press any key to dismiss ⏎ send ↑↓ history / commands ^J newline @ attach ! shell mode esc abort ^c quit ^L clear screen j / k focus card y copy card ? this overlay ─────────────────────────────────────────────────────────────────────────────
34Shell output (! mode)
When the user submits with a leading !, the line bypasses the model and runs as a shell command via the same tool-call path. It lands as a regular ▣ shell tool card — same expand/collapse rules as any other tool result.
◇ you · just now ! git status ▎ ▣ shell git status 0.04s · exit 0 ▾ ▎ ▎ On branch main ▎ Your branch is up to date with 'origin/main'. ▎ ▎ nothing to commit, working tree clean
▎ ▣ shell git push 2.1s · exit 1 ▾ ▎ ▎ error: failed to push some refs to 'origin' ▎ hint: Updates were rejected because the remote contains work… ▎ hint: integrate the remote changes first.
35DiffApp · standalone CLI
Invoked as reasonix diff <file> — a one-shot terminal app that opens a SplitDiff card with a session intro at the top and a key hint at the bottom. No composer, no agent. Quits on q / esc / ^c.
$ reasonix diff src/cli/ui/App.tsx ◈ diff · ~/projects/reasonix · src/cli/ui/App.tsx · HEAD → working ▎ ± Compare src/cli/ui/App.tsx +12 / -47 ▾ ▎ ▎ HEAD working tree ▎ ─────────────────────────────────────── ─────────────────────────────────────── ▎ 1 /** App.tsx — primary chat … */ 1 /** App.tsx — chat surface … */ ▎ … … … … ▎ 142 <Box> 142 <InlineShell> ▎ 144 </Box> 144 </InlineShell> ───────────────────────────────────────────────────────────────────────────── ↑↓ scroll · h/l switch pane · n/N next/prev hunk · q quit
36Account & quota
Three states: balance low (warn) · exhausted (err) · rate limited (warn). Each lands as a regular card so it's part of scrollback and the user can scroll up to find it later.
▎ ⚠ Balance low · ¥ 1.24 remaining ▾ ▎ ▎ At your current burn rate (¥0.10 / turn) ≈ 12 more turns. ▎ Top up at https://platform.deepseek.com/usage.
▎ ✖ Out of balance · ¥ 0.00 ▾ ▎ ▎ Cannot send. Composer disabled until top-up. ▎ Top up at https://platform.deepseek.com/usage, ▎ then /refresh to re-check.
▎ ⚠ Rate limited · retry in 4s ▾ ▎ ▎ api.deepseek.com responded 429: 60 RPM exceeded ▎ Reasonix will retry automatically with backoff. esc to cancel.
37MCP lifecycle
One-line cards for each lifecycle event of an MCP server connection. Steady-state servers don't print anything — only state changes emit a card so scrollback isn't noise.
⌘ MCP · notion ↻ handshake… initialise → tools/list → resources/list ⌘ MCP · notion ✓ connected 12 tools · 8 resources · 142ms ⌘ MCP · notion ◌ slow tools/list took 8.4s · added p95 to context ⌘ MCP · notion ↻ reconnect 2/5 backoff 4s ⌘ MCP · notion ✖ failed handshake error · ENOENT: server binary missing ⌘ MCP · notion ○ disabled via /mcp disable notion
38Session ops
One-line outputs from /fork, /archive, /resume, /reset. They land as a single inline row so the chain of session state changes is readable in scrollback.
◍ Forked session-7 → session-8 from turn 12 · 142 events copied reasonix --session=session-8 ⌑ Archived session-7 ~/.reasonix/sessions/session-7.jsonl · /resume to bring back ↺ Resumed session-7 at turn 12 · 142 events replayed · plan reloaded ⚠ Reset — session-9 cleared 142 events archived · /resume session-9 to recover
39Dropped surfaces
Things that used to exist in older Reasonix versions but don't fit the inline + bottom-pinned model. Listed here so the absence is intentional, not a TODO.
File tree sidebar
A persistent sidebar requires alt-screen (otherwise it'd scroll away with content). Replaced by @ mention picker (§19) for picking files into a turn, and /files slash command for an on-demand printable file list. Same job, no sticky chrome required.
Persistent top chrome bar
Replaced by the bottom status row (§20). Anything that was on the top bar (mode pill / cost / cache / balance) now lives one row above the input — Ink can pin it, top-row positioning can't.
App-managed scroll viewport
No more ↑ 24 ▕───●─────▏ 62% ↓ 12 indicator. The terminal's native scrollback is the source of truth — wheel up, ⇧+drag to select, the OS handles it. Reasonix doesn't try to clip / paginate.
Mouse-tracking modes
No ?1002h / ?1006h button-event tracking. Without alt-screen there's no point — and disabling it lets the terminal's native selection (⇧+drag, double-click word, triple-click line) just work.
40Motion & cadence
Terminals don't do tweens, opacity, or sub-cell positions. What Ink can do is rerender any row on an interval — that gives us discrete-frame animation, color steps, and content swaps. Below: the seven primitives we use, their cadence, and what we never try.
Live previews below — every animation in this section actually runs. If you don't see motion you're either looking at a screenshot or your browser is too old (needs CSS content animation, ≥ Chrome 109 / Firefox 119 / Safari 16).
1 · Spinner — circle200ms / frame · 4-frame cycle · used for "thinking" / model wait
◐ thinking · deepseek-chat · 2.3s esc abort frames cycle: ◐ → ◓ → ◑ → ◒ → ◐ … (the live row above is rotating ◐ at 200ms / step)
2 · Spinner — braille80ms / frame · 8-frame cycle · used for tool calls (faster, distinguishable from "thinking")
▎ ▣ run_command npm install 12.4s ▾ frames cycle: ⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ (live row above swaps content every 80ms)
3 · Streaming cursor1s blink · always at the tail of in-progress streaming content
▎ ▶ The change you described maps cleanly to the existing ▎ ResolvedIndexConfig structure. Three edits are needed cycle: on (500ms) → off (500ms) → … the brand block at the tail above is the live cursor
4 · Focus pulseaccent bar pulses at 1.4s ease-in-out when a card is the current focus
▎ ⊞ Plan · Migrate selection 5 of 7 done ● FOCUSED ▸ opacity: .35 → 1.0 → .35 → … ease-in-out (the bar to the left is the live pulse)
5 · Toast fadesolid 2s → fade to faint over 1s → unmount. Tone drop, not alpha (which terminals can't do)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ✓ Checkpoint saved · 142 events · 3 files snapshotted cycle: solid 2s → dim over 1s → loop. In Ink we replace opacity with a fg-1→fg-2→fg-3 ramp.
6 · Number tickerdata-driven · new value flashes brand for one render frame then settles to fg-1
▸ turn · cycles every 4s in this preview · in real session, ticks on each cost-emit event applies to: cost ticker, cache hit %, balance ¥, token counters
7 · Countdown1Hz tick · digit flashes brand on each step · used in auto-confirm + disconnect retry
approving in s · esc to interrupt cadence 1000ms · digit always brand · surrounding text stays warn · flash-and-step, no slide
8 · Row arrivala 600ms fade-in when a new card lands. The only transition we permit — and only for newly-printed cards, never for already-on-screen content
▎ ✓ Step 1 of 5 · Read chunker + filesystem 0.4s · 2 tools · done ▸ a one-shot fade from opacity 0 to 1; reload the page to see this row appear again
Things we never dothese are unsafe / ineffective in a terminal cell grid
✗ sliding / position transitions terminals only redraw whole rows ✗ opacity / alpha fade no opacity per cell — drop tone instead ✗ color gradients across cells stutters at 256 / 16 color depth ✗ marquee / scrolling text hides content, hurts scrollback ✗ whole-screen flash / inverse blink accessibility hazard, photosensitive risk ✗ automatic auto-scroll override terminal scrollback is the user's, not ours
41Edge cases
Smaller surfaces I missed in the per-feature pass — clipboard feedback, empty pickers, fatal crash, dirty exit. Each reuses an existing pattern (toast / picker / card), no new primitives.
Clipboard copy feedbacky key on a focused card or /copy — shows an ok toast
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ✓ Copied to clipboard · 3 cards · 1.4 KB 3s
Empty picker/ or @ with no matches — picker stays open with a single zero-state row
commands · "/xyz" no matches. type to filter or esc to close › /xyz
Fatal crashunhandled exception in the agent loop — print the trace, offer /report, exit cleanly on ^c
✖ Reasonix crashed · this is a bug, not your fault TypeError: Cannot read property 'then' of undefined at App.tsx:142:18 at processTicksAndRejections (node:internal/process/task_queues:96:5) … 4 more frames hidden The session log is preserved at: ~/.reasonix/sessions/session-7.jsonl ───────────────────────────────────────────────────────────────────────────── [r] /report file an issue with the trace + last 10 events [s] stack show the full trace [c] copy copy crash report to clipboard ^c quit
Dirty exit warning^c with unsaved editor buffer — block once, second ^c discards
⚠ Unsaved editor buffer src/cli/ui/App.tsx has +12 / -3 unsaved. ▸ save & quit ^s then quit discard & quit ^c again cancel esc — back to editor ───────────────────────────────────────────────────────────────────────────── ↑↓ pick · ⏎ confirm · esc cancel
Long card · "show more"a card whose collapsed preview hits the row budget — truncate with a single dim row
▎ ▣ search_content "writeClipboard" 3 hits in 2 files ▾ ▎ ▎ src/cli/ui/clipboard.ts ▎ 15 │ export function writeClipboard(text: string) ▎ ▎ … 4 more rows · press space to load all · ⏎ to expand fully
All MCP servers offlinewhen zero MCP tools are available, the agent says so explicitly so the user isn't confused why /tools is short
⌘ All 4 MCP servers offline notion · linear · github · fs-local /mcp browse
42Interaction
Mouse + keyboard parity. Focus a card, expand, fire actions — every click target has a key.
Focused vs unfocused focus = brighten the accent bar from dim to full
▎ ⊞ Plan · Migrate selection ▸ ▎ ⊞ Plan · Migrate selection 5 of 7 done ● FOCUSED ▸
Keyboard parity no mouse required — every action has a key
43Demo flow
A real session, in card order. User asks → context sweep → reasoning → plan → step (tools) → diff → approval. Terminal scrolls naturally as cards arrive.
◇ you · just now refactor the SKIP_DIRS list out of chunker.ts so directory_tree can reuse it ▎ ⌑ Context · 4 user · 2 feedback · 1 reference ~1.2K tok ▸ ▎ ◆ Reasoning · 3 paragraphs ▸ ▎ ⊞ Plan · 5 steps 0 of 5 done ▾ ▎ ▎ [▶] 1. Read chunker + filesystem to understand current structure ▎ [ ] 2. Create src/index/config.ts with shared defaults ▎ [ ] 3. Strip constants from chunker.ts ▎ [ ] 4. Strip duplicate from filesystem.ts ▎ [ ] 5. Run verify gate ▎ ▶ Step 1 · Read chunker + filesystem 0.4s ▾ ▎ ▎ ✓ read src/index/semantic/chunker.ts 0.08s · 250 lines ▎ ✓ read src/tools/filesystem.ts 0.07s · 712 lines ▎ ▶ Step 2 · Create src/index/config.ts 0.2s ▾ ▎ ▎ ✓ write src/index/config.ts 0.12s · 84 lines · created ▎ ± Edit src/index/semantic/chunker.ts +12 / -47 ▾ ▎ ▎ @@ -30,40 +30,5 @@ ▎ -const SKIP_DIRS: ReadonlySet<string> = new Set([ ▎ - "node_modules", ".git", ".hg", ▎ - ... 18 more lines ▎ -]); ▎ +import { DEFAULT_INDEX_EXCLUDES } from "../config.js"; ▎ +const SKIP_DIRS = new Set(DEFAULT_INDEX_EXCLUDES.dirs); ? Approve · apply edits to 2 files awaiting The agent wants to apply the edit shown above plus a related one in src/tools/filesystem.ts. ▸ apply both land both edits, run verify next apply this only land chunker.ts; review filesystem.ts separately reject discard both; agent will revise ───────────────────────────────────────────────────────────────────────────── ↑↓ pick · ⏎ confirm · esc cancel