# The interface: what we need, how it is grouped, and how it is drawn Written 2026-11-10. This replaces the earlier layout note: it is now the one document that says what the interface contains. Layout comes after this, and is chosen from it. Plain English throughout. No invented shorthand. If a word here is not obvious, it is defined in "Words we use". --- ## Words we use - **Workspace** — one page in TUIOS. The person switches between workspaces. - **Panel** — one pane inside a workspace. Each panel is a program, or one area of one program, that holds one kind of content. - **View** — a way of looking at a panel, for example "the task tree" or "the diff". A panel can hold several views and show one at a time. - **Focus** — which panel receives the keys. Exactly one panel has focus at a time, and the person can always see which one. - **Fact** — a piece of truth with exactly one owner. Tasks, blockers, comments, runs, costs and worktrees belong to Paperclip. A workspace holds as many panels as the work in it needs. **Four side by side is a good default**, because more than four at once stops being readable — but it is not a rule. When a workspace needs a fifth thing, there are three honest choices, and all of them are allowed: - **a tab** inside an existing panel, for another view of the same kind of content; - **a tool panel** that opens beside the others and closes again when it is done; - **zoom**, which is TUIOS's own key, for the moment a panel needs the whole screen. The only rule is that everything in a workspace belongs to the same question. If a panel does not help with that question, it belongs in another workspace. --- ## How things are grouped The grouping is by what the person is doing, not by which system the data came from. There are four things a person does with this factory: 1. **Decide and direct.** What is the state of the work, what is blocked, what is waiting on me, what do I do next. 2. **Watch.** What is an agent doing right now, what has it changed, what has it cost. 3. **Talk.** Answer an agent, correct it mid-task, unblock a task with words. 4. **Author and govern.** Write a new task or plan, set the verify command, watch the budget, repair the layout when TUIOS loses it. That gives six workspaces. They are deliberately fewer than the number of things we could show, because a person who cannot find the screen they need has gained nothing from more screens. | Workspace | The question it answers | Panels (a good default set, not a limit) | |---|---|---| | **Board** | what is the state of the work, and what needs me | Task tree · Task summary · Needs you | | **Work** | what is happening now, and what changed | Run log · Diff · Worktree facts | | **Conversation** | what has been said, and what do I say back | Thread · Composer · Task header | | **Author** | what am I asking for, and how will it be judged | Task form · Guidance · Preview | | **Project** | which folder, which machine, what limits, what cost | Project facts · Costs · Settings | | **Repair** | is the layout sound, and what went wrong | Layout map · Health · Log | The **shell** workspace stays as it is: one pane with a prompt in the project folder, for the moments when the person needs a shell and should not have to leave. Inside a workspace, panels are either **side by side** or **stacked as tabs**, and the person switches between tabs without leaving the workspace. A tab is not a second-class panel: it has the same frame, the same footer and the same focus marker as any other. ## Tools that open as panels Several things the person needs already exist as good terminal programs, and wrapping them would be worse than opening them. Each opens in the current workspace, next to what is already there, and closes when it is done. This is the "many panels can simply be terminal tools" idea from the product statement, done deliberately rather than by accident. | Tool | What it is for | Opens with | |---|---|---| | **Lazygit** | branches, commits, staging, history, in the project folder | `t` then choosing it | | **Hunk** | reading a pull request or a branch change as a review | `t` then choosing it | | **shell** | any command the panel does not cover | `t` then choosing it | | **git log and diff** | the task's branch without leaving the interface | `t` then choosing it | | **ocr** | the review of the current change, as it runs | `t` then choosing it | Both Lazygit and Hunk are already installed on this machine, and Hunk is a flake input of the system configuration. Neither is ours to rebuild. --- ## The user interface items These are the pieces the panels are made from. Each one says what it is for, which Charmbracelet component implements it, and what it must show in its empty, loading and failed states. The list is deliberately finite: if an item is not here, a panel does not invent it. ### Navigation and framing **1. Workspace strip.** A one-line strip at the top of every panel showing which workspace this is and how many there are, with the current one marked. Implemented in Lipgloss; TUIOS switches workspaces, so this is a position indicator, not a control. Empty state: never empty. Failed state: never applicable. **2. Panel frame.** A border with a title and a focus marker. Rounded border when the panel has focus, plain border when it does not, plus the word `focus` in the title so the difference does not depend on colour. Implemented with Lipgloss borders. Every panel has one, and the frame is what the "too small" message replaces. **3. Footer key hints.** The keys that work right now, in this panel, in this state. Uses the `help` component with `key.Binding`, so a key that does not apply is not shown. Never shows a key that would do nothing. **4. Notice line.** One line for the result of an action, such as "sent", "created AUD-166", or the exact error text. Disappears when the next action starts. Uses Lipgloss only; the text is always the server's own words, never a paraphrase. **5. Stale marker.** The time of the last successful read, shown in the panel title. The purpose is honesty: a panel that has not read recently says so instead of looking current. ### Lists and rows **6. Task row.** One line per task: selection cursor, identifier, status, assignee, title, and a blocker badge when something blocks it. The `list` component with a custom delegate, so filtering and scrolling come for free. **7. Group header.** A heading with a count, such as "Blocked (2)". Not selectable. Implemented in the list delegate. **8. Status pill.** The task's state as a short word with a distinct style per state, and a different shape as well as colour so it survives a monochrome terminal and colour blindness. **9. Assignee chip.** The agent's name, or a dash. Uses the agent name from Paperclip, never an identifier fragment. **10. Blocker badge.** `waits on AUD-163` on the row, read per task from the blocker diagnosis. When the blocker is finished the badge says `ready`, because a task that is ready but still marked blocked is the most confusing state we have. **11. Needs-you card.** One card per decision waiting on a person: a refused merge, a task waiting for an answer, a task whose blocker finished while it was still marked blocked. Each card says what happened, what is expected, and the one key that acts on it. Implemented as `list` items with a different delegate. **12. Table.** For figures that must be compared: per-task cost, per-run duration, per-file change counts. Uses the `table` component with fixed column widths taken from the panel width, never from a constant. ### Reading long content **13. Thread message.** Author, time, and the body with paragraph breaks and code blocks preserved. Bodies are wrapped to the panel, never truncated with an ellipsis in the middle of a sentence. Scrolls inside a `viewport`. **14. Composer.** A multi-line text area for the reply, growing with the text up to a third of the panel, then scrolling. Uses `textarea`. Enter sends and needs to be stated in the footer, because a text area normally treats Enter as a new line. **15. Diff view.** File headers, hunks, and line numbers, with additions and deletions distinguished by a leading character as well as colour. Scrolls inside a `viewport`. Very large diffs are capped with an explicit line saying how many lines were left out, and a key that shows everything. **16. Run timeline.** One row per run: state, what woke it, start and end, duration, cost, and a link to the agent's final message. Uses `table` or a list delegate. **17. Worktree facts.** The folder, the branch, the base it was cut from, and the delivery state. Small, monospaced, never wrapped. ### Input and forms **18. Form field.** A label, an optional "(required)", a hint line under it, and the value. Single-line fields use `textinput`; the description uses `textarea`. Tab moves forward, Shift-Tab moves back, Enter on the last field submits. **19. Validation message.** Directly under the field that is wrong, in the field's own words, and the submit key stays available so the person can correct and try again. **20. Result receipt.** After a write: the identifier that was created or the state that was set, with the server's response behind it. A failure shows the server's message verbatim, because paraphrasing an error we do not understand is how an afternoon is lost. **21. Confirmation prompt.** For anything destructive: the exact thing being removed, and the word that must be typed to continue. Uses `textinput` with no suggestions. ### Status and feedback **22. Spinner with a verb.** While a read or a write is in flight: what is happening, not just that something is. Uses `spinner`. **23. Progress bar.** Only for things with a known count, such as "3 of 7 tasks read". Uses `progress`. Never used as decoration, and never used to fake a duration. **24. Health row.** One line per check in the Repair workspace: name, pass, fail or not run, and the reason. Three states, never two, because "not run" is not "pass". **25. Empty state.** Every panel says why it is empty: "no tasks in this project", "this task has never run", "no worktree, so nothing to compare". An empty panel with no words is a bug. **26. Error state.** The failed thing, the exact message, and the one action that is still possible, such as retry or open the Repair workspace. ### Working with several panels **28. Tab strip.** For a panel holding more than one view: a single line of named tabs with the current one marked, switched with `[` and `]` while the panel has focus. Implemented in Lipgloss and styled like the panel frame. A tab name is a word, never a number, so it survives being read aloud. **29. Tool panel.** A panel that runs an existing terminal program — Lazygit, Hunk, a shell, a git command, or the running review. It opens on demand in the current workspace, takes focus when it opens, and gives focus back when it closes. It runs the real program, so it is not styled by us and does not pretend to be. **30. Panel closer.** Every tool panel says how to close it in its own footer (`q` or `esc`), and closing it returns the workspace to exactly the arrangement it had before, with focus where it was. ### Icons **27. Glyphs.** A small set used consistently: running, waiting, blocked, done, failed, unread. Never the only carrier of meaning. Measured on this machine, and this matters: TUIOS offers four glyph sets — `ascii`, `default`, `heavy` and `unicode` — and `default` is active. Starship is **not installed here**, and no Nerd Font is present (`fc-list` finds none), so an icon set that expects a patched font would draw empty boxes. Until a Nerd Font is installed deliberately, the interface uses TUIOS's `default` set, which is ordinary Unicode: `╭ ╮ ✕ ▎ ● › …`, with `ascii` as the fallback. --- ## What each panel shows, and where the facts come from | Panel | Shows | Reads from | |---|---|---| | Task tree | groups, rows, badges | company issue list, then the blocker diagnosis per task | | Task summary | status, assignee, priority, blockers, verify command, cost, last run | single task read, blocker diagnosis, cost summary | | Needs you | decisions and waits | task states, merge refusals, pending answers already on the task | | Run log | run timeline and activity | runs, activity | | Diff | changed files and the change | `git` in the task's own worktree | | Worktree facts | folder, branch, base, delivery state | the task's current execution workspace | | Thread | messages | comments | | Composer | the text being written, the status to send | the person, then a comment or a status change | | Task header | identifier, title, status, assignee | single task read | | Task form | the fields being written | the person, then a created task | | Guidance | what a good task needs, and the project's verify command | the project's `.harness` file | | Preview | the description as the agent will receive it | the form, not the server | | Project facts | folder, machine, session, project identifier | the project's `.harness` file | | Costs | spend by task and by agent | cost summary per task, agent budget | | Settings | verify command, budget, watched task | the `.harness` file, then Paperclip for what it owns | | Layout map | workspaces and panels as they actually exist | TUIOS | | Health | checks and their outcome | the checks themselves | | Log | what the repair did | the repair's own output | Two rules follow and are not negotiable: - **A panel never invents a fact.** If Paperclip does not have it, the panel says it does not have it. - **A panel shows when it last read.** So a wrong panel is visibly stale rather than quietly wrong. --- ## How it is drawn **One theme, semantic roles.** Colours are named by role (text, muted, accent, success, warning, error, and a surface colour), and panels ask for the role, never for a hex value. A dark and a light variant exist from the start. **Focus is unmistakable.** The focused panel gets a rounded border, a bright border colour, and the word `focus` in its title. Two of those three do not depend on colour. **Density.** One cell of horizontal padding inside a frame, one blank line between sections, no blank line between rows. Rows are single lines except thread messages, which are the only content that gets paragraph space. **Alignment.** Identifiers, statuses, assignee names and numbers are aligned into columns whose widths are computed from the content in view, capped at a share of the panel width. Never a hardcoded column width. **Truncation.** A truncated title ends in an ellipsis and the full text is available with a key that opens a detail view. Nothing important is truncated silently. **No decoration that carries no meaning.** No gradients, no box-drawing around every row, no colour that does not correspond to a state. **Motion.** Only two things animate: the spinner while something is in flight, and the selection cursor as it moves. Nothing else moves on its own. **The Charmbracelet pieces we use:** `list` for rows and decisions, `table` for figures, `viewport` for anything scrollable, `textarea` for the composer, `textinput` for fields with one line, `help` and `key` for the footer, `spinner` and `progress` for feedback. Tabs are not a component in this collection, so a view switcher inside a panel is built from Lipgloss and the `help` component, and is styled like the rest of the interface. --- ## Keys TUIOS keeps `h`, `j`, `k`, `l`, `z` and `n` in window management mode, so no panel may use them. A bare Esc must stay free, because it closes a box. | Where | Key | Does | |---|---|---| | Any panel | Tab, Shift-Tab | move focus to the next or previous panel | | Any panel | [ and ] | previous or next tab, in a panel that has tabs | | Any panel | t | open a tool panel here: shell, Lazygit, Hunk, git, review | | Any panel | ? | show the keys for this panel | | Any panel | r | read again from Paperclip | | Any panel | q | leave this panel's program, returning the pane to its shell | | Any panel | Esc | close the open overlay or leave the composer, never quit | | Task tree | Up, Down | move the selection | | Task tree | Enter | open this task in the Conversation and Work workspaces | | Task tree | a | assign to the configured agent | | Task tree | Space | expand or collapse a group | | Thread | Up, Down, Page Up, Page Down | scroll | | Composer | Enter | send | | Composer | Shift-Enter | new line | | Composer | s | choose the status to send with the reply | | Diff | Up, Down, Page Up, Page Down | scroll | | Diff | f | show the whole file, not the capped view | | Forms | Tab, Shift-Tab | next or previous field | | Forms | Enter | next field, and submit on the last one | | Destructive | typed word | confirm | No key means two things in two panels. Where a panel needs a key that is taken, it uses a different one rather than overloading. **Zoom is not ours**: `z` belongs to TUIOS, and the interface relies on it rather than reimplementing it. The same is true of switching workspaces: TUIOS does that, and the interface only shows where you are. --- ## Size, and what happens when there is not enough Every panel declares a smallest useful size. When a panel is smaller than that, it draws its own short message with the size it has and the size it needs, and nothing else. The program never draws a broken layout and never invents a scrollbar to hide the problem. | Panel | Smallest useful size | |---|---| | Task tree | 30 columns by 10 rows | | Task summary | 30 by 8 | | Needs you | 30 by 6 | | Run log | 40 by 10 | | Diff | 40 by 12 | | Worktree facts | 30 by 6 | | Thread | 40 by 12 | | Composer | 40 by 4 | | Task form | 50 by 14 | | Guidance | 30 by 6 | | Preview | 40 by 10 | | Project facts, Costs, Settings | 40 by 8 | | Layout map, Health, Log | 40 by 8 | The workspace itself needs 80 columns by 24 rows. Below that, the whole workspace shows one message naming the size it has and the size it needs. Tabs change the arithmetic in a useful way: two panels tabbed into one cost the space of one panel, so a narrow workspace keeps its content by tabbing rather than by shrinking. That is why tabs are part of the design and not a workaround. --- ## How the panels sit together Layout follows the width of the terminal, so the person gets as much as their screen can carry and never a layout pretending to have room it does not. - **150 columns and wider:** Board shows the task tree and task summary side by side, with Needs you tabbed under the tree. Work shows the run log beside the diff. Conversation shows the thread above the composer, with the task header above both. - **110 to 149 columns:** at most two panels side by side; the third becomes a tab in the panel that holds the same kind of content. - **80 to 109 columns:** one panel at full width, with the others tabbed beside it, in the order the work happens: Board, Work, Conversation, Author. - **Below 80 by 24:** one message, nothing else. Two arrangements we already know we want, because they are the moments the person is actually in: - **Reading a claim and its code.** Task tree on the left, thread on the upper right, diff on the lower right. The only arrangement where a claim and the change that backs it are on screen together. - **Deciding.** Needs you on the left with the task it concerns beside it, so the decision card and the evidence are never on different workspaces. ## What happens when you pick a task Plainly: **choosing a task changes what the other panels show.** Pick a task in the task tree, and the summary, the thread, the run log, the diff and the worktree facts all switch to that task. Nothing else has to be typed, and no screen has to be told twice. The rest is implementation, and it is written down only so the behaviour can be trusted: - the chosen task is remembered in the project's own `.harness/harness.toml`, as one line naming its identifier; - the other panels re-read when that line changes, within about a second; - the choice survives a restart or a lost pane, because it is on disk and not in memory; - if the chosen task is ever deleted, the panels fall back to the most active task in the project rather than showing an error. That is the whole mechanism. It is one line in one file, it is not a second copy of anything Paperclip owns, and it can be inspected with a text editor when something looks wrong. ## What is not in this version, deliberately - No chat with an agent as a separate thing: the Conversation workspace is the chat. - No plan editor: a plan is a task's description, and the Author workspace writes it. - No second task board: TUIOS has one, Paperclip has one, and this interface is the one that knows about blockers and worktrees. - No settings for colours: one theme, two variants, no per-panel colour choices. - No dashboards of figures with nothing to act on: every number sits next to the thing it describes. - No replacement for Lazygit or Hunk: they open as tool panels. ## Decided, and what is still open Decided by the person, 2026-11-10: 1. **Switching inside a workspace is wanted.** Tabs and zoom are part of the design, and a workspace may hold more than four panels when the work in it needs them. 2. **Grouping matters more than panel count.** A workspace earns its place by answering one question well. 3. **Picking a task updates the other panels.** That is the behaviour described above. 4. **Lazygit and Hunk belong inside the interface**, as tool panels, not as things the person leaves for a shell. Still open: 1. **Glyphs.** Measured: TUIOS has `ascii`, `default`, `heavy` and `unicode`; `default` is active. Starship is not installed here and no Nerd Font is present. So the interface uses the `default` set with an `ascii` fallback unless a Nerd Font is installed on purpose. If Starship's look is wanted, that is a system change first, then a glyph set. 2. **Which panel wins when the terminal is narrow.** Proposal: the one that answers the workspace's question, with the rest tabbed rather than hidden. 3. **The order of tabs** in each workspace. Proposal: the order in which the work happens — what it is, what it says, what it changed.