bise :*design system
/
design.mdbrand bookscreensgithubbise.dev
overview
introduction the five laws the screen
foundations
color typography space & layout motion glyphs themes & fallbacks
components
frame & header your message three levels agent messages tool rows folds agents panel divider composer attachments box key bar inbox inbox item pickers popups find agent palette flashes & tips
patterns
less at rest, more when you hold a key progressive disclosure never block one key for the common case show it, then fold it short on room: a written drop order errors zen while you type your space, their space defaults that decide
content
voice in the UI vocabulary message templates
process
how we design a change checklist open questions
nothing matches
overview

introduction

how bise looks and behaves, and why. the laws, the foundations, every component of the terminal UI and the UX patterns behind them, with the reasons we chose them.

bise is a terminal app: one thread where you talk to main, your team lead, while agents work behind it. everything on screen is text in cells, so this system is made of cells too: colors, glyphs, rows, keys and words.

agents: read design.md, the same system in about 3,000 tokens. this site is the layer above the brand book. the book keeps every exact spec with its issue number. here you get the patterns and the reasons, so a new screen feels like the old ones without anyone having to ask. when the two disagree, the book wins and this site gets fixed.

start here

the five lawsnever block, calm by default, one key, show what happened, never liethe screenevery part of the bise screen, namedcolorcolor is attention: what each color may carrycomponents18 components, each with its states and rulespatternsless at rest, progressive disclosure, feedback, drop order…checklisttwelve questions before a new screen ships

how to read a component page

  • anatomy: the parts, numbered, with what each one is for.
  • states: the mocks have tabs. rest, ctrl held, narrow, NO_COLOR, ASCII. every mock is drawn in the real palette, on the real cells, and follows the site's light/dark switch.
  • rules: what never changes.
  • do / don't: the mistakes we already made once.

the example

every mock tells the same small story, so you can compare them: you asked for three things (signup is slow on mobile, dark mode, the 404 is sad). main started three agents: perf, dark-mode and sad-404. perf is done. dark-mode works in its own worktree. sad-404 has a question for you: the dog: a hat, or a scarf?

nextthe five laws
overview

the five laws

every rule on this site comes from one of these five. when two rules fight, the law higher on the list wins.

1. never block

you can always type, send and move. nothing takes the keyboard away from you, nothing opens while you type, nothing waits for a click to let you go on.

├─ you → main · opus 5.5 · high · yolo · ≈∿~· ──────────── 58k · 22% ─┤
│ │ │
│ │ and the footer too▌ │
│ │ │
│ tab queue ⏎ steer ctrl+c interrupt │
╰──────────────────────────────────────────────────────────────────────╯
the composer is never locked during a turn: ⏎ steers the running turn, tab queues for after it.

2. calm by default, loud only for you

at rest the screen says almost nothing. color, motion and position go to what needs you, and nothing else. a done agent is a small pink ✓. an agent stuck on a question shows a pink ? and an item in your inbox.

3. one key for the common case

the answer you give 9 times out of 10 is one key away, from anywhere. ctrl+1 opens the first inbox item, 1 allows the command, and the next item opens by itself.

4. show what happened

every action leaves a trace you can see for a moment, then gets out of the way: a fold line after an answer, ✓ inbox clear on the divider, the row you changed flashing ✓.

5. never lie

no hidden limit, no fake progress, no key that doesn't work, no promise the product can't keep. without ctrl+digits from the terminal, the inbox says click to open. it never shows ctrl+1.

a law is a tie-breaker. "show what happened" never justifies a pop-up that blocks typing: law 1 wins.
previousintroductionnextthe screen
overviewbook §8 ↗

the screen

one frame, one thread, one panel. every part of bise's main screen, named, so we all say the same word for the same thing.

╭─ bise :* ───────────────────────────────────────────────────────┬──── ~/acme · # 1 in the inbox ─╮
│ │ │
│ │ signup is slow on mobile. and the 404 is sad ✓✓ │ agents │
│ │ │
│ :* on it: perf, dark-mode and sad-404 started. │ 0 ∿ main :* @ 2 1m 22% │
│ ▸ 9 messages between 3 agents │ 1 ✓ perf │
│ │ 2 ∿ dark-mode 3m 12% ψ │
│ ✉ dark-mode → main │ 3 ? sad-404 18% │
│ which gray for the borders? │ 4 ∿ emoji-csv • 42s 31% │
│ :* i answered dark-mode: the gray in tokens.css. │ 5 ○ release 8% │
│ │ │
│ $ runs the signup benchmark ✓ 4.2s │ inbox │
│ ✓ perf is done · signup 4.1 s → 0.9 s │ 1 ? sad-404 the dog: a h… │
│ │ │
│ ╭─ inbox · 1 waiting for you ─────────────────── ctrl+1 open ─╮ │ │
│ │ 1 ? sad-404 · the dog: a hat, or a scarf? 4m │ │ │
│ ╰─────────────────────────────────────────────────────────────╯ │ │
├─ you → main · opus 5.5 · high · yolo · ≈∿~· ───────────────────┴──────────────────── 58k · 22% ─┤
│ │ │
│ │ and give the sad dog a hat▌ │
│ │ │
│ @ file $ skills / commands ctrl+1 inbox │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ bise :* ───────────────────────────────── ~/acme · ≈∿~ 3 working · ✓ 1 done · # 1 in the inbox ─╮
│ │ │
│ │ signup is slow on mobile. and the 404 is sad ✓✓ │ agents │
│ │ │
│ :* on it: perf, dark-mode and sad-404 started. │ 0 ∿ main :* @ 2 working │
│ ▸ ctrl+o expand │ 1 ✓ perf done │
│ │ 2 ∿ dark-mode working ψ │
│ ✉ dark-mode → main │ 3 ? sad-404 asks you │
│ which gray for the borders? │ 4 ∿ emoji-csv • working │
│ :* i answered dark-mode: the gray in tokens.css. │ 5 ○ release idle │
│ │ │
│ $ runs the signup benchmark ✓ 4.2s │ inbox │
│ ✓ perf is done · signup 4.1 s → 0.9 s │ 1 ? sad-404 the dog: a h… │
│ │ │
│ ╭─ inbox · 1 waiting for you ─────────────────── ctrl+1 open ─╮ │ │
│ │ 1 ? sad-404 · the dog: a hat, or a scarf? 4m │ │ │
│ ╰─────────────────────────────────────────────────────────────╯ │ │
├─ you → main · opus 5.5 · high · yolo · ≈∿~· working · 1m ──────┴────── 58k / 262k tokens · 22% ─┤
│ │ │
│ │ and give the sad dog a hat▌ │
│ │ │
│ ctrl+c interrupt ctrl+f find ctrl+1 open an inbox item ctrl+s find agent │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
100 columns. hold ctrl and every word comes back in its own place; let go and it goes.

anatomy

  1. the frame: a thin rounded border around the whole app. its top border is the header: bise :*, the folder and the inbox count. → frame & header
  2. the history: main's thread, append-only, in a reading column. your messages carry a thin pink bar. → your message, three levels
  3. the agents panel: one row per agent, its status glyph, its numbers. → agents panel
  4. the inbox: what needs you, in its own box above the divider. → inbox
  5. the divider: who you talk to, with which model, effort and mode, and whether it works. → divider
  6. the composer: your space, raised, never locked. → composer
  7. the key bar: the 3-4 keys you can't guess. → key bar
previousthe five lawsnextcolor
foundationsbook §5 ↗

color

color is attention. only what needs you and what failed get a hue. everything else is text, dim or faint.

the palette

roledarklightcontrastcarriesnever
text#ece6da#1b191715:1what you read: answers, names, your message—
dim#a39c90#6b645a6.9:1the model, the agent's own work, durationssomething you must act on
faint#857d72#7d766c4.6:1key labels, numbers, separators · a sentence you must read
rule#4a4540#cfc8bd1.97:1lines: the frame, the panel's rule, borderstext, ever
accent#f4a6b0#b8416b9.7:1needs you, :*, the agent you talk to, done ✓, read ✓✓, your bardecoration
error#ff5a52#b3261e6.1:1failures only: ✗, failing checks, a wrong keya warning, a default
ok#b9d99a#3f7a2a—diff additions onlysuccess

surfaces

surfacedarklightfor
ground#141211#fdfbf7every cell: bise paints its own background
raised#1f1c1a#f4f0e8your space: the composer pane
raised 2#26221f#efeae0an inbox item open in place, one step above
chip#231f1d#efe9dfthe envelope chip of a message between agents
pill#3a2530#f0d3dca quote or image chip in your text
selection#33292c#fdeef2selected text

in context

? sad-404 needs you
the dog: a hat, or a scarf?
✓ perf is done · signup 4.1 s → 0.9 s
✗ release failed · npm publish: 403 forbidden
∿ dark-mode working · 3m
? sad-404 needs you
the dog: a hat, or a scarf?
✓ perf is done · signup 4.1 s → 0.9 s
✗ release failed · npm publish: 403 forbidden
∿ dark-mode working · 3m
three hues on screen, three meanings: pink needs you or is yours, red failed, the rest is grey. under NO_COLOR, bold takes the accent's job.

rules

  • pink is never red. "needs you" must not look like an error.
  • never green for done. done is a small pink check. green success reads like a CI dashboard, and it isn't us.
  • one hue per row. if two things on one row want color, one of them is wrong.
  • every readable text is ≥ 4.5:1 on white, our cream, black and a typical dark grey.
  • the rule color is for lines. it was the old faint text color: too dark to read, so text moved to faint.
✓ do
  • color the one thing on screen that needs the user
  • use dim for the agent's own work, so your words and main's stand out
  • keep the error color for something that really broke
✗ don't
  • color a default (yolo is dim, not red)
  • use green for success or a passing check
  • use the rule color for text, even a hint
previousthe screennexttypography
foundationsbook §5, §9 ↗

typography

one font, the user's. one size. importance comes from contrast, weight and room.

one size

a terminal has one font size, so we never pretend otherwise in the product. what's for you reads "bigger" through contrast (text over dim), weight (the speaker in bold) and room (a blank row above and below).

∴ thought for 14s ▸
$ runs the signup benchmark ✓ 4.2s
:* perf is done. signup went from 4.1 s to 0.9 s on a phone.
the hero image was 4.2 MB, it's 310 kB now.
± edit web/src/hero.tsx ✓ +3 −1 ▸
level 2 (main to you) gets text color, a bold speaker and a blank row around it. the agent's own work stays dim.

rules

  • the user's font in the terminal. JetBrains Mono on the site, the book and every mock.
  • bold is rare: a speaker (:*, @ name to you:), a screen's title, a key you must notice. never a paragraph.
  • lowercase everywhere, except proper nouns (GitHub, Mistral), acronyms (PR, MCP) and keys as printed (ctrl+s). our own name stays bise.
  • no italic, no underline in the product, except a link: the text underlined in the accent.
  • a reading measure: prose wraps at 88 columns at most. code can run to 100.
previouscolornextspace & layout
foundationsbook §8 ↗

space & layout

everything sits on whole cells. a few fixed columns, a reading column, one blank row between blocks.

the grid

column / rowwhat starts there
column 0 and F−1the frame
column 3the frame's title, the history's text, the divider's label
column 7the composer's text and the key bar (x0 + 4: the composer is its own pane)
panel textfrom the panel's rule + 2, 28 columns, to F−4 (wider from 165 columns)
row 0the header, in the frame's top border
H−2the key bar, then the frame's bottom

the reading column

prose wraps at 88 columns whatever the width. more width goes to the margin and the panel, never to longer lines. tables and code may run to 100.

widths

terminallayout
≥ 165the panel grows 1 column for every 5, up to 44 at 240
100–164the panel at 28 columns, its rule joining the frame
90–99the panel at 24 columns
< 90no panel: the header keeps short counts
< 60 or < 16 rowsno frame: a header row, a plain rule for the divider

vertical rhythm

  • one blank row between history blocks. level 2 gets one above and below. two blank rows in a row is a bug.
  • the history starts on row 2 and ends one blank row above the inbox or the divider.
  • the composer pane at rest: divider, bar row, text, bar row, key bar, frame. nothing under the frame.
✓ do
  • line a new element up with an existing column
  • right-align numbers in their column (3m, 42s, 12%)
  • keep every column in place even when its cell is blank, so rows line up
✗ don't
  • start text at a new column of its own
  • use half rows or sub-cell gaps in a mock: the terminal can't
  • let prose grow with the screen
previoustypographynextmotion
foundationsbook §5, §8 working ↗

motion

motion means something is alive. the gust while an agent works, the cursor, the :* pop, a flash for 2-3 seconds. nothing bounces, nothing slides.

the gust

an agent at work is a gust blowing by: 5 cells, 110 ms a frame, a 9-frame cycle. head ≈ and ∿ in text, ~ dim, · faint, then 5 empty frames.

├─ you → main · opus 5.5 · high · yolo · ≈∿~· ────────────────────────┤
├─ you → main · opus·hi · yolo · ≈∿~ ──────────────────────────────────┤
2 ∿ dark-mode 3m 12% ψ
the gust never disappears while the agent works: it's the last thing kept on a short divider.

timing

motionduration
the gust110 ms a frame, 9 frames
a mode switch (shift+tab)the word in accent for 3 s
a fold line after an answer2 s
✓ inbox clear, ✓ copied2 s
zen fades inat once; comes back 5 s after your last key

rules

  • one animation per thing, never two on one row.
  • ≤ 10 frames a second, only the cells that change are redrawn.
  • stop when the terminal loses focus, when nothing works, and under a reduce-motion setting: a static ∿ then.
  • no motion to decorate. a pop for :* at launch is the one flourish.
previousspace & layoutnextglyphs
foundationsbook §6 ↗

glyphs

one glyph per thing, one thing per glyph. one cell wide, in every common font, with an ASCII form.

the set

glyphmeansASCII
:*main, your team lead:*
│your message (thin bar, accent)`\`
┃needs you (heavy bar, accent)`\`
∿working: the gust~
?needs you?
✓done (accent); at the end of your message: got it* / v
✓✓read by the modelvv
✗failed (error)x
○idleo
…waiting on another agent;
·starting, sending.
•unread (accent)!
ψits own worktreeY
↑its pull request (designed)P
$a bash call$
ƒa TypeScript callf
±a file edit%
∴thinking:
▸ ▾closed / open+ -
✉︎a message between agents@
▣ ❝an image, a quote#

rules

  • one cell wide in every font we audited. a glyph that turns into a color emoji somewhere is out: ✉ became @ in the panel, ⎇ became ψ.
  • the place tells two marks apart. ✓ leading a row is done; ✓ ✓✓ at the end of your message is got it / read.
  • **every glyph has a row in the /help legend**, and a test fails when one hasn't.
  • a glyph needs no legend after a week. if people ask twice, change it.
  • two meanings for one glyph is a bug. see open questions for the one we still have.
previousmotionnextthemes & fallbacks
foundationsbook §5, §6 ↗

themes & fallbacks

a design isn't done until it works in light and dark, under NO_COLOR, in ASCII and on 16 colors.

the same row, five ways

3 ? sad-404 · the dog: a hat, or a scarf? 4m
2 ∿ dark-mode ψ · dims the borders
✓ perf is done
3 ? sad-404 · the dog: a hat, or a scarf? 4m
2 ∿ dark-mode ψ · dims the borders
✓ perf is done
3 ? sad-404 . the dog: a hat, or a scarf? 4m
2 ~ dark-mode Y . dims the borders
* perf is done
the light theme: use the switch at the top right. every mock on this site follows it.

the forms

formwhat changes
lightthe palette's light column, picked from the terminal's background (OSC 11), or forced
NO_COLORno hue, no tint. the accent becomes bold, dim stays dim, chips get [ ]
16 colorsno tints: the raised pane and chips go, the bar alone marks your space
ASCII (BISE_ASCII=1)every glyph in its ASCII form, boxes in `+ - \, ...` for a cut
reduce motiona static ∿ everywhere
bise paints its own background on every cell, so it reads whatever the terminal's theme. it gives the terminal's color back on exit, on a crash, and when a shell takes the screen.
previousglyphsnextframe & header
componentsbook §8 the frame ↗

frame & header

bise draws itself like an app: a thin rounded frame on the terminal's edge, with the header in its top border.

╭─ bise :* ──────────────────────────────── ~/acme · # 1 in the inbox ─╮
│ │
╭─ bise :* ───── ~/acme · ≈∿~ 3 working · ✓ 1 done · # 1 in the inbox ─╮
│ │
╭─ bise :* ──────────────────────────────────── ∿ 3 · ? 1 · ✓ 1 · # 1 ─╮
│ │
╭─ bise :* · dims the borders to tokens.css ────────────────── ~/acme ─╮
│ │

anatomy

  1. bise bold and :* in accent, from column 3.
  2. in an agent's view, its role line: what it's doing now, ≤ 60 characters, written after each of its turns.
  3. on the right, dim: the folder and the inbox count. with no panel, the short counts (∿ 3 · ? 1), because the panel is the one that shows agents.

rules

  • the frame's lines are in the rule color and paint no background.
  • short on room: the folder goes first, then long counts become short.
  • under 60 columns or 16 rows: no frame, a header row instead.
previousthemes & fallbacksnextyour message
componentsbook §9 ↗

your message

what you said, marked by a thin pink bar on every line. its marks at the end say whether it arrived and was read.

│ signup is slow on mobile. and dark mode. and the 404 is sad ·
│ signup is slow on mobile. and dark mode. and the 404 is sad ✓
│ signup is slow on mobile. and dark mode. and the 404 is sad ✓✓
│ here is the full list of things i noticed on the signup page, in
│ the order i'd fix them:
│ 1. the hero image is 4.2 MB
│ ▸ 12 more lines ✓✓

anatomy

  1. the thin │ bar in accent, on every wrapped line. the heavy ┃ belongs to things that need you.
  2. your text, in the text color.
  3. the mark: · sending, ✓ the agent got it, ✓✓ (accent) the model read it.
  4. past 20 lines: ▸ n more lines, opened by a click, space or ctrl+o.

rules

  • thin bar = you, heavy bar = needs you. you tell at a glance what you said from what they said.
  • a quote or an image is one chip in your text (❝ 1, ▣ 1), never a separate block above it.
previousframe & headernextthree levels
componentsbook §9 ↗

three levels

everything in the history sits on one of three levels: it needs you, it's for you, or it's between agents.

┃ ? sad-404 needs you
┃ the dog: a hat, or a scarf?
:* i answered dark-mode: the gray in tokens.css, like everywhere.
✉ dark-mode → main
which gray for the borders?
✉ main → dark-mode
the one in tokens.css.
top to bottom: level 1, level 2, level 3.
levelwhatlook
1 · needs youa question, an approvalthe inbox; the heavy ┃ and a bold accent title, until you answer
2 · for youmain talking to you, reports on what you askedtext color, the speaker in bold, a blank row above and below
3 · between agentswhat agents tell each otherdim, an envelope chip, folded after a few

rules

  • levels 2 and 3 differ by brightness and the chip, never by hue.
  • a new kind of event gets a level before it gets a look. if it fits none, it probably shouldn't reach the screen.
  • main answering for you is level 2, and it says why: ▸ why.
previousyour messagenextagent messages
componentsbook §9 level 3 ↗

agent messages

when agents talk to each other, it looks like a message: a small tinted chip says who writes to whom, the text goes under it, dim.

✉ dark-mode → main
which gray for the borders? the mock says #2a2623, tokens.css
says #4a4540. … ▸
✉ perf → main
the hero image is 4.2 MB. ok to convert it to webp?
also: the font loads twice.
✉ main → perf
yes to both.
▸ 9 messages between 3 agents
[✉ dark-mode → main]
which gray for the borders?

rules

  • the quietest thing on screen: the chip's tint is its only background, no accent inside, main included.
  • the text sits under the chip, never beside it, so every text starts on the same column.
  • at most 2 rows, then … ▸. the same pair stacks with no blank row; a new pair gets one.
  • short on room, the receiver's name is cut before the sender's. never the arrow, never the envelope.
previousthree levelsnexttool rows
componentsbook §11 calls ↗

tool rows

each bash or TypeScript call is one dim row: its glyph, what the model says it's doing, in your language, and its state.

$ installs the deps ✓ 3.1s
ƒ reads the open issues on GitHub ∿ 12s
$ runs the tests ✗ exit 1 · 0.8s
FAIL signup.spec.ts › keeps the email after a reload…
$ ▸ 6 commands · weighs the hero image ✓ 3.2s
╭─ $ weighs the hero image ✓ 0.1s ─────────────────────────────────────╮
│ ls -la public/hero.png │
├──────────────────────────────────────────────────────────────────────┤
│ -rw-r--r-- 1 gab staff 4.2M hero.png │
╰──────────────────────────────────────────────────────────────────────╯
$ installs the deps ok 3.1s
f reads the open issues on GitHub ~ 12s
$ runs the tests x exit 1
> 6 commands · weighs the hero image ok 3.2s

anatomy

  1. $ bash or ƒ TypeScript, in the lead column (error color when it failed).
  2. the model's own description, one short line in your language. running, it's in the text color.
  3. the state, right-aligned: ∿ 12s running, ✓ 0.3s done (dim, never green), ✗ exit 1 · 0.8s failed.
  4. a failure adds one row: the first error line, cut with ….

rules

  • 4 done calls or more in a run fold into ▸ n commands. failed and running calls keep their rows.
  • a click or space opens one call as a box (15 rows); ctrl+o opens every one.
  • a failure never opens by itself: its first error line is enough to decide.
previousagent messagesnextfolds
componentsbook §11 ↗

folds

▸ means there is more here. one line by default, everything one key away. folded is never gone.

∴ thought for 14s ▸
± edit web/src/hero.tsx ✓ +3 −1 ▸
▸ 9 messages between 3 agents
│ ▸ 12 more lines ✓✓
∴ thought for 14s ctrl+o expand
± edit web/src/hero.tsx ✓ +3 −1 ctrl+o expand
▸ ctrl+o expand
│ ▸ ctrl+o expand ✓✓

rules

  • ▸ closed, ▾ open. a click or space toggles one, ctrl+o opens or closes all.
  • the fold row says what's inside and how much: ▸ 12 more lines, ▸ 6 commands.
  • search (ctrl+f) finds text in a folded part and opens it.
  • what you must act on is never folded.
previoustool rowsnextagents panel
componentsbook §8 agents panel ↗

agents panel

one row per agent: its number, its status glyph, its name, and on the right what changes: the turn time, the context, its worktree.

agents
0 ∿ main :* @ 2 1m 22%
1 ✓ perf
2 ∿ dark-mode 3m 12% ψ
3 ? sad-404 18%
4 ∿ emoji-csv • 42s 31%
5 ○ release 8%
agents
0 ∿ main :* @ 2 working
1 ✓ perf done
2 ∿ dark-mode working ψ
3 ? sad-404 asks you
4 ∿ emoji-csv • working
5 ○ release idle
agents · ⌥↑↓ select
⌥0 ∿ main :* @ 2 1m 22%
⌥1 ✓ perf
⌥2 ∿ dark-mode 3m 12% ψ
⌥3 ? sad-404 18%
2 ∿ dark-mode 3m 12% ↑
6 ✓ login-fix 9% ↑
with a PR: ↑ takes ψ's column (a PR implies a branch). red only when its checks fail. designed, not built yet.

anatomy

  1. number, faint: ⌥ + it opens the agent. it never changes while the agent lives.
  2. status glyph: the breathing gust, ✓, ?, ✗, ○, ….
  3. name, then its marks: main's :* and @ n, the pink • unread.
  4. turn time, 3 columns, right-aligned, only while it works.
  5. context %, 3 columns, right-aligned.
  6. ψ far right when it works in its own worktree.

rules

  • no state words at rest: the glyph says them. holding ctrl writes them in the time and % columns.
  • every column stays in place even when blank, so the rows line up.
  • a name takes the room its row leaves and is cut with … only there.
previousfoldsnextdivider
componentsbook §8 divider ↗

divider

the rule between the history and your space. it says who you talk to, with which model, effort and mode, and whether it works.

├─ you → main · opus 5.5 · high · yolo · ≈∿~· ──────────── 58k · 22% ─┤
├─ you → main · opus 5.5 · high · yolo ───────────────────── 18k · 2% ─┤
├─ you → main · opus 5.5 · high · yolo · ≈∿~· working · 1m ─── 58k / 262k tokens · 22% ─┤
├─ you → main · opus 5.5 · high · auto ───────────────────── 18k · 2% ─┤
├─ you → dark-mode · sonnet 5.5 · low · yolo · ψ sb/dark-mode · ≈∿~· ─┤
├─ you → main · opus·hi · yolo · ≈∿~ ──────────────────────────────────┤

anatomy

  1. you → dim, the agent's name in accent.
  2. model and effort, dim, · faint between them.
  3. the approvals mode, dim (accent for 3 s after shift+tab).
  4. the gust, only while it works.
  5. on the right, the context, short: 58k · 22%.

rules

  • the divider is also where short notes land: ✓ inbox clear, ✓ copied 9 chars, an open item's you → ? sad-404 · your answer.
  • short on room: the long context falls back to the short one, then the context goes, then the branch name, then opus 5.5 · high becomes opus·hi. the mode goes last. the gust stays.
previousagents panelnextcomposer
componentsbook §8 composer, §13 ↗

composer

your space: a raised pane with your pink bar. it's never locked, and markdown shows as you type it.

├─ you → main · opus 5.5 · high · yolo ───────────────────── 18k · 2% ─┤
│ │ │
│ │ what's on your mind? │
│ │ │
│ @ file $ skills / commands │
╰──────────────────────────────────────────────────────────────────────╯
├─ you → main · opus 5.5 · high · yolo ───────────────────── 18k · 2% ─┤
│ │ │
│ │ make the 404 page **funnier**, and give the dog a hat▌ │
│ │ │
│ @ file $ skills / commands │
╰──────────────────────────────────────────────────────────────────────╯
├─ you → main · opus 5.5 · high · yolo · ≈∿~· ──────────── 58k · 22% ─┤
│ │ │
│ │ and the footer too▌ │
│ │ │
│ tab queue ⏎ steer ctrl+c interrupt │
╰──────────────────────────────────────────────────────────────────────╯

rules

  • raised, edge to edge inside the frame: it's the one place where you type.
  • the bar is faint while empty, accent with text, an image or a recording.
  • never locked: during a turn ⏎ steers it, tab queues for after it.
  • markdown is colored, never hidden: every mark stays, the message sent is the text typed.
  • text starts at column 7, one column right of the history's: the pane is its own space.
previousdividernextattachments box
componentsbook §13 the composer block ↗

attachments box

what comes with your message, but isn't your text, sits in its own small box above it. so you never think it's part of what you typed.

│ ╭─ attached ─────────────────────────────────────────────────────╮ │
│ │ ❝ 1 “la licence du repo,” │ │
│ │ ▣ 2 404.png 1440×900 │ │
│ ╰─ backspace on a chip removes it ───────────────────────────────╯ │
│ │ tu recommandes quoi pour ❝ 1 ? et regarde ▣ 2▌ │
│ @ file $ skills / commands │

rules

  • a quote or an image is a chip inline in your text; the box lists what each chip is.
  • the box has its own border and title, so it reads as a tray, not as lines of your message.
  • backspace on a chip removes it from both places.
previouscomposernextkey bar
componentsbook §8, §16 ↗

key bar

the 3 or 4 keys you can't guess, under the composer. holding ctrl shows every other one.

@ file $ skills / commands ctrl+1 inbox
tab queue ⏎ steer ctrl+c interrupt
esc back to main @ file $ skills / commands
ctrl+c interrupt ctrl+f find ctrl+1 open an inbox item
1-2 answer ←→ choose ↑↓ other items esc back to your message

rules

  • the key in text color, what it does dim, 3 spaces between pairs.
  • only keys you can't guess. ⏎ send and ? help went: everybody knows them.
  • only keys that work here. ctrl+1 inbox shows only while the inbox has items, and only when the terminal sends ctrl+digits; otherwise /inbox.
  • the bar follows the mode: steering, an agent's view, an open item each have their own.
previousattachments boxnextinbox
componentsbook §12 ↗

inbox

what needs you, in its own box above the divider. it never blocks: you keep typing to main while items wait.

╭─ inbox · 1 waiting for you ──────────────────────────── ctrl+1 open ─╮
│ 1 ? sad-404 · the dog: a hat, or a scarf? 4m │
╰──────────────────────────────────────────────────────────────────────╯
╭─ inbox · 4 waiting for you ────────────────────────── ctrl+1-3 open ─╮
│ 1 ? t3 · $ npm publish --access public 2m │
│ 2 ? api-v2 · $ git push origin main 3m │
│ 3 ? sad-404 · the dog: a hat, or a scarf? 4m │
│ + 1 more · ↑ #409 ready to merge │
╰──────────────────────────────────────────────────────────────────────╯
╭─ inbox · 4 waiting for you ────────────────────────── ctrl+1-3 open ─╮
│ 1 ? t3 · $ npm publish --access public 2m │
│ 2 ? api-v2 · $ git push origin main 3m │
│ 3 ? sad-404 · the dog: a hat, or a scarf? 4m │
│ + 1 more · ↑ #409 ready to merge │
╰──────────────────────────────────────────────────────────────────────╯
╭─ inbox · 1 waiting for you ────────────────────────── click to open ─╮
│ 1 ? sad-404 · the dog: a hat, or a scarf? 4m │
╰──────────────────────────────────────────────────────────────────────╯

what goes in

kindanswers
an approval1 allow · 2 always allow … here · 3 no
a hard rule (push to main, secrets, a wipe)1 allow · 3 no: no "always"
a sandbox rerun1 run it again without the sandbox · 2 always here · 3 no
a questionits choices, or free text
ready to merge (designed)1 merge it · 2 not yet

reports, done notes and FYI stay out: they're main's thread.

rules

  • its own box, rounded, in the rule color, on the ground. no box when there's nothing.
  • numbered the same everywhere: the row that says 1 here says 1 in the panel, and ctrl+1 opens it.
  • approvals first, then questions, then merges. 3 rows, then + n more.
  • the title's right side only names a key that works: ctrl+1-3 open, click to open, or /inbox opens it.
previouskey barnextinbox item
componentsbook §12 ↗

inbox item

an item opens where its row was, with what the agent did last. one key answers it, and the next one opens by itself.

╭─ inbox · 2 waiting for you ────────────────────────── ctrl+1-2 open ─╮
│ ┃ │
│ ┃ ? t3 wants to run 1 of 2 · 2m │
│ ┃ $ npm publish --access public │
│ ┃ │
│ ┃ it publishes the package: everyone can install it. │
│ ┃ t3 is shipping 2.5.0 · its last step: ✓ npm run build │
│ ┃ │
│ ┃ 1 allow 2 always allow npm publish * here 3 no │
│ ┃ or type why not, ⏎ says no │
│ ┃ │
│ 2 ? sad-404 · the dog: a hat, or a scarf? 4m │
╰──────────────────────────────────────────────────────────────────────╯
├─ you → ? t3 · your answer ───────────────────────────────────────────┤
╭─ inbox · 2 waiting for you ────────────────────────── ctrl+1-2 open ─╮
│ ┃ ? t3 wants to run 1 of 2 · 2m │
│ ┃ $ npm publish --access public │
│ ┃ │
│ ┃ 1 allow 2 always allow npm publish * here 3 no │
│ ┃ or type why not, ⏎ says no │
│ 2 ? sad-404 · the dog: a hat, or a scarf? 4m │
╰──────────────────────────────────────────────────────────────────────╯
╭─ inbox · 1 waiting for you ──────────────────────────── ctrl+1 open ─╮
│ ✓ you allowed t3: npm publish --access public │
│ ┃ ? sad-404 asks 1 of 1 · 4m │
│ ┃ the dog: a hat, or a scarf? │
│ ┃ │
│ ┃ 1 a hat 2 a scarf │
│ ┃ or type your answer, ⏎ sends it │
╰──────────────────────────────────────────────────────────────────────╯
├─ ✓ inbox clear ──────────────────────────────────────────────────────┤
│ │ │
│ │ and give the sad dog a hat▌ │
after the last answer, the box goes, your draft comes back and the divider says ✓ inbox clear for 2 s.

keys

keydoes
ctrl+1…9, a clickopen item N, in place
1–9pick that option (empty composer)
← →highlight an option; ⏎ picks it
↑ ↓the previous / next item
type, then ⏎answer in words (for an approval: a no, with your note)
ctrl+ofull screen, the other items as tabs
escback to your message, the cursor where it was

rules

  • the open item is raised one step above the composer, with the heavy ┃ on every row.
  • your draft is set aside, never lost: the divider says you → ? t3 · your answer while you answer.
  • after an answer, a fold line for 2 s, then the next item opens by itself: 1, 1, 3, 1 clears four.
  • past half the feed, the item shows its start and … n more lines · ctrl+o full screen.
previousinboxnextpickers
componentsbook §8 /models, /provider ↗

pickers

every full-screen choice looks the same: a question, a filter, what works first, enter forward, esc back.

which model does what?
each role picks a provider, then a model. one provider can serve several.
› main Mistral mistral-large-latest · high
agents same as main · Mistral · mistral-large-latest
small jobs auto · Mistral · ministral-8b-latest
voice Mistral voxtral-mini-latest
↑↓ choose · enter change · esc back
agents: which provider?
now: same as main · Mistral · mistral-large-latest
› same as main Mistral · mistral-large-latest
Mistral ✓ ready · main, small jobs use it
Anthropic ✓ ready
OpenAI not set up
more providers…
agents · Anthropic: which model?
type to filter, or a model id that isn't listed.
› son▌
› claude-sonnet-5-5 recommended
claude-sonnet-4-6

rules

  • a bold question as the title, one dim line saying what it changes.
  • what works comes first: ready providers before the rest, same as main / auto first, with what they resolve to.
  • the current one says now (dim). one recommended at most, in accent.
  • enter forward, esc back one step, digits pick at once. a step with one choice is skipped.
  • after the last step you land where you started, the row flashing ✓.
previousinbox itemnextpopups
componentsbook §16 ↗

popups

/, @ and $ open a small list right above the composer. tab completes, ⏎ runs, esc closes. typing never stops.

╭──────────────────────────────────────────────────────────────────────╮
│ › /models which model does what │
│ /model the model of the agent in view │
│ /theme light · dark · auto │
╰──────────────────────────────────────────────────────────────────────╯
│ │ /mo▌ │

rules

  • / commands, @ a file, $ a skill. the list filters as you type.
  • tab completes, ⏎ runs once nothing is left to pick, esc closes and keeps your text.
  • the arguments of a command are listed the same way (/theme → light · dark · auto).
previouspickersnextfind
componentsbook §16 ctrl+f ↗

find

ctrl+f (or cmd+f) finds text in the history, in a small box over its top-right corner, like an editor's find.

╭─ find ──────────────────────────╮
│ › hero▌ 2/5 │
╰──────────────────────────╯
the hero image was 4.2 MB, the hero loads twice.

rules

  • 3 rows, its top border on the history's first row, left of the panel's rule.
  • ⏎ next, shift+⏎ previous, esc closes. it searches folded text too, and opens it.
  • it never covers the line it found: the history scrolls.
previouspopupsnextagent palette
componentsbook §16 switch agents ↗

agent palette

type part of an agent's name to jump to it. live agents first, archived ones dim.

╭─ find agent ─────────────────────────────────────────────────────────╮
│ › dar▌ │
│ │
│ › ∿ dark-mode · dims the borders to tokens.css │
│ – dart-sass · archived │
╰──────────────────────────────────────────────────────────────────────╯

rules

  • ctrl+s everywhere; cmd+k once the terminal has passed a cmd key. /switch works too.
  • ↑↓ choose, ⏎ opens the agent's view, esc closes.
  • the part that matches is bold; an archived agent opens read-only.
previousfindnextflashes & tips
componentsbook §12, approvals ↗

flashes & tips

a flash says what just happened, where your eyes already are, for 2-3 seconds. a tip explains something the first time, once.

├─ you → main · opus 5.5 · high · auto ───────────────────── 18k · 2% ─┤
auto · safe calls run, risky ones ask you
├─ you → main · opus 5.5 · high · yolo · ✓ copied 9 chars ─────────────┤
├─ ✓ inbox clear ──────────────────────────────────────────────────────┤
╭──────────────────────────────────────╮
│ you're in yolo: everything runs. │
│ ⇧⇥ changes it. │
╰─────────────────────────────────────╯
├─ you → main · opus 5.5 · high · yolo ───────────────────── 18k · 2% ─┤

rules

  • where your eyes are: the divider, the row you touched, the key bar. never a pop-up in a corner.
  • a sentence of state, not a cheer: ✓ inbox clear, never "all done!".
  • a tip shows once, ever, over the thing it explains, and goes on the next key.
previousagent palettenextless at rest, more when you hold a key
patterns

less at rest, more when you hold a key

at rest the screen shows what changes and what needs you. holding a modifier brings every word back, in place, and letting go puts it away.

2 ∿ dark-mode 3m 12% ψ
3 ? sad-404 18%
2 ∿ dark-mode working ψ
3 ? sad-404 asks you

the modifiers

holdshows
ctrlevery ctrl key where it acts (▸ ctrl+o expand, the inbox numbers in accent), the state words, the long forms (58k / 262k tokens), the full header, the full key bar
⌥the panel's numbers as ⌥0 ⌥1, ⌥↑↓ select
cmdthe cmd keys, once a cmd key has really reached bise

rules

  • the held form replaces the rest form in the same cells. nothing moves, nothing pushes.
  • the glyph already says it, so the word waits for ctrl.
  • a key you hold types nothing: it's the cheapest way to see more.
why: "on affiche trop d'informations" (the user). the glyphs said the state, and the words said it again.
previousflashes & tipsnextprogressive disclosure
patternsbook §11 ↗

progressive disclosure

one line by default, details one key away. folded is never gone, and what you must act on is never folded.

itemby defaultopened
thinking∴ thought for 14s ▸the full text
a bash / TypeScript callone row with the model's descriptionits box: script and output
4+ calls in a run▸ 6 commands · …the rows
a file edit± edit hero.tsx ✓ +3 −1 ▸the diff
agents talking▸ 9 messages between 3 agentsthe chips
your long message20 rows, ▸ 12 more linesthe whole message
a report✓ perf is done ▸ reportthe report

rules

  • space or a click opens one, ctrl+o opens all, ▾ closes.
  • a failure shows its first error line, a question shows in full: you never open something to know you must act.
  • search finds what's folded and opens it.
previousless at rest, more when you hold a keynextnever block
patterns

never block

you can always type, send and move. nothing takes the keyboard away, nothing opens while you type.

where it shows

  • the composer is never locked. during a turn, ⏎ steers it, tab queues for after it.
  • the inbox never takes the composer. it's a box above it. an item opens only when you ask (ctrl+N, a click), never while your draft has text.
  • an open item sets your draft aside, and esc gives it back, cursor in place.
  • talk to any agent, anytime. ⌥ + its number, then back to main. nobody has to stop.
  • restart whenever. the agents, your thread, your draft and your queue come back.
✓ do
  • let the user answer later: an item waits in the inbox, the agent waits for it
  • keep the thread in sight while answering: open in place, not on a new screen
✗ don't
  • open a modal that eats the next keys
  • auto-focus a new item while the user types
  • block sending because an item waits
previousprogressive disclosurenextone key for the common case
patternsbook §16 ↗

one key for the common case

the answer you give 9 times out of 10 is one key away, from anywhere. digits pick, the same digit everywhere.

rules

  • digits pick. in an item, a menu, a picker: 1–9 takes that option at once.
  • one number, one thing, everywhere. the inbox row 1 is 1 in the panel, and ctrl+1 opens it from anywhere.
  • the next one comes to you. after an answer the next item opens by itself: 1, 1, 3, 1 clears four.
  • one key, one meaning. esc is always back one step. ⏎ is always "do it". ctrl+o always opens what's folded.
  • every key that's shown works. we check what the terminal sends; no ctrl+digits → click to open, /inbox.
  • leave the system's keys alone. macOS keeps ctrl+arrows for Spaces, so we don't build on them. when we must take one (cmd+f), the book says how to free it per terminal.
  • every key has a mouse twin, and every click a key.
previousnever blocknextshow it, then fold it
patterns

show it, then fold it

every action leaves a trace you can see for a moment, where your eyes already are, then gets out of the way.

what happenedwhere it showshow long
you switched modethe mode word in accent on the divider, its words on the key bar3 s
you answered an itema fold line in the box, then the next item2 s
the last item✓ inbox clear on the divider, your draft back2 s
a setting changedthe row flashes ✓1 flash
you copied✓ copied 9 chars on the divider2 s
your message· → ✓ → ✓✓ at its endstays
an agent finishedits glyph turns ✓, one line in main's threadstays

rules

  • the same fold line lands in main's thread, so the history keeps the decision.
  • a flash is a state, never a cheer. no exclamation marks.
previousone key for the common casenextshort on room: a written drop order
patternsbook §8 short on room ↗

short on room: a written drop order

every line that can run out of room has its order written down, and we apply it one step at a time.

├─ you → dark-mode · opus 5.5 · high · yolo · ψ sb/dark-mode · ≈∿~· ──── 58k ─┤
├─ you → dark-mode · opus 5.5 · high · yolo · ψ · ≈∿~· ─┤
├─ you → dark-mode · opus·hi · yolo · ψ · ≈∿~ ─┤
├─ you → dark-mode · yolo ∿ ───┤
the same divider as the room shrinks. the gust is the last thing to go: never, while it works.

the order

  1. explanation words first (working · , in the inbox),
  2. long forms become short (opus 5.5 · high → opus·hi, ∿ 3 working → ∿ 3),
  3. whole details go (a branch's name, the model tag),
  4. names are cut last, with …, never through a glyph or an arrow,
  5. what says "alive" or "needs you" is never dropped: the gust while working, ?.
every new line ships with its drop order, tested at 80 and 150 columns.
previousshow it, then fold itnexterrors
patternsbook §8 voice, providers ↗

errors

one line: what happened, then how to fix it, with the command that fixes it. nothing is lost.

✗ turn stopped: no OpenRouter key yet. /provider sets it up.
✗ Mistral says the voice key is wrong. /provider fixes it.
401 · Unauthorized
your recording is kept: ctrl+r retry
? your Mistral account has no credit yet. add some here:
console.mistral.ai/billing

rules

  • ✗ in error color for what broke; ? in accent when it's your call (no credit: you decide).
  • the fix ends the line: a command (/provider sets it up.), a key, a place.
  • the provider's own words go dim under it, never instead of it.
  • nothing is lost: the draft, the clip, the queue are kept, and the line says so.
  • bise says "i": i couldn't reach Mistral, not "an error occurred".
previousshort on room: a written drop ordernextzen while you type
patternsbook §8 zen ↗

zen while you type

start typing and everything else fades: the agents, the counts, the chatter. just you and your words. send it and it all comes back.

in and out

  • in: a key that changes your text (a character, backspace, a paste).
  • holds while you edit or move inside the composer.
  • out: 5 s after your last key, or at once on ⏎, esc, a shortcut, the mouse, focus lost, or anything that needs you.

the look

the chrome goes 45 % of the way to the background: the header, the frame, the panel, the divider's right side, the key bar. the history you read and your text stay as they are. nothing moves, only brightness.

why: "parfois j'ai quand même besoin de lire pour pouvoir écrire. mais j'ai pas besoin de voir tout ce qui se passe ailleurs" (the user).
previouserrorsnextyour space, their space
patterns

your space, their space

your space is raised and carries your pink bar. their space is the ground. you never type in theirs, they never draw in yours.

yours (raised)theirs (ground)
the composer panethe history
an inbox item, openthe agents panel
the attachments box, above your textthe agents' tool rows and chips

rules

  • everything you type or answer happens on the raised tint, with the │ bar.
  • what isn't your text (attachments, queued messages) sits in its own box, so you never think it's part of it.
  • the raised tint fills edge to edge inside the frame; the frame's lines stay on the ground.
previouszen while you typenextdefaults that decide
patternsbook §8 /models, approvals ↗

defaults that decide

bise has opinions, so you don't need settings. every default says what it resolves to, and every pick is remembered.

rules

  • the first run asks one thing: which model does the work. every other role says same as main or auto.
  • **never a bare auto**: auto · Mistral · mistral-small-latest.
  • name what leaves the machine the first time: auto sends commands to Jev (TypeSafe) to check them.
  • remembered: a pick is saved and survives restarts. never asked twice.
  • one recommended option at most, and only when we'd really pick it.
✓ do
  • show what a default resolves to, on the same row
  • ask once, at the moment it matters
✗ don't
  • add a setting to avoid a decision
  • tag something "recommended" because it's ours
previousyour space, their spacenextvoice in the UI
contentbook §4 ↗

voice in the UI

bise speaks as i, the user is you. human, short, concrete. lowercase.

rules

  • bise says "i": i'll work in ~/acme, i couldn't reach Mistral.
  • lowercase everywhere, except proper nouns, acronyms and keys as printed.
  • short sentences. show the moment, not the feeling.
  • no final period on a title or a key label. a full sentence keeps it.
  • nothing LLM-y: no "seamless", no "X, not Y", no "never deleted", no "let's", no exclamation marks.
  • the user's language for what models write to you (a tool row's description, main's answers). the chrome stays English.
✓ do
  • ✓ inbox clear
  • i start an agent when a job needs one.
  • mistral says this key is wrong. copy it again from <link>.
✗ don't
  • All done! 🎉
  • Your agents work seamlessly together.
  • An error occurred while processing your request.
previousdefaults that decidenextvocabulary
contentbook §4 ↗

vocabulary

four nouns to learn: you, main, agents, the inbox. and the same short state words everywhere.

the nouns

saynever say
youthe user, operator
main, your team leadorchestrator, hub, coordinator
an agenttask, sub-agent, worker, hand
the inboxcards, notifications
a question, an approvala card, a ticket
a worktreea sandbox, a clone

the state words

working · idle · done · waiting · asks you · failed · starting · stopped

the same word for the same state in the panel, the header, the help and the site.

units

numbers before units, no fluff: 58k · 22%, 3m, 42s, 4.2 MB, 1 of 2.

previousvoice in the UInextmessage templates
contentbook §17 copy deck ↗

message templates

the shapes we reuse, so new strings sound like the old ones.

kindtemplateexample
error✗ <what happened>. <command> <fixes it>.✗ voice needs a key. /voice setup picks one.
your call? <what>. <where to do it>:? your Mistral account has no credit yet. add some here:
flash✓ <state>✓ inbox clear, ✓ copied 9 chars
mode<mode> · <what it means>auto · safe calls run, risky ones ask you
tip<the fact>. <key> <does what>.you're in yolo: everything runs. ⇧⇥ changes it.
picker titlea questionwhich provider?, how hard should it think?
picker linewhat it changesyou can change it any time with /model.
fold▸ <n> <things>▸ 12 more lines, ▸ 6 commands
item head? <agent> <wants to / asks>? t3 wants to run
answered✓ you <verb> <agent>: <what>✓ you allowed t3: npm publish --access public
hard rule<what it does>. this one always asks.it rewrites main. this one always asks.
previousvocabularynexthow we design a change
process

how we design a change

from the user's words to a signed-off capture. nothing is built before he picks.

  1. start from the user's words, quoted in the issue. the design answers them, nothing more.
  2. mock it on the real geometry: a local page drawn with the TUI's real columns, colors and rows. a screenshot-level mock, not a sketch.
  3. variants only where we hesitate, the pick clearly marked, with one line of why.
  4. the user picks. nothing is built before.
  5. the builder sends real captures: tmux, 80 and 150 columns, ctrl up and held. the designer signs off, or lists the changes.
  6. the book gets the final spec, with the user's words and the issue number. this site follows.
previousmessage templatesnextchecklist
process

checklist

twelve questions before a new screen ships.

  1. does it block typing, sending or switching agents? it must not.
  2. what is the one key for the common case?
  3. which level is it: needs you, for you, between agents?
  4. what does it show at rest, and what only with ctrl held?
  5. is any color used for something that doesn't need the user?
  6. does any glyph mean two things? is it one cell in every font?
  7. does every shown key work in this terminal? what's the fallback?
  8. what shows right after the user acts, and for how long?
  9. what's the drop order at 80 columns?
  10. dark, light, NO_COLOR, ASCII: all drawn?
  11. every word: lowercase, short, one of the four nouns, no LLM tells?
  12. on failure: one line, what happened, the command that fixes it, nothing lost?
previoushow we design a changenextopen questions
process

open questions

what we haven't settled yet.

the inbox's mark

the panel shows @ 2 on main's row and the header says # 1 in the inbox. @ is also the file key on the key bar, and # a pull request's number. proposal: bring back ✉︎ (its text form, one cell) for the inbox only, in its own issue.

light theme syntax colors

the dark syntax colors are set; the light ones are still to pick.

pull requests

PR support is designed (the ↑ mark, the ready-to-merge item), not built yet. its pages here say designed until it ships.

previouschecklist