diff --git a/docs/DOCMAP.md b/docs/DOCMAP.md index 89afaf4..ac30bba 100644 --- a/docs/DOCMAP.md +++ b/docs/DOCMAP.md @@ -19,6 +19,7 @@ it is a pointer and should be deleted or replaced. | `docs/OPEN-ISSUES.md` | this project | what is broken or unfinished in the closed project | | `docs/FALLBACK-OMA.md` | this project | what OMA provides, kept in case the pivot is reversed | | `docs/WHAT-WE-ARE-BUILDING.md` | this project | the person's own statement of the product | +| `docs/UI-LAYOUT.md` | this project | what each page must show, where each fact comes from, and the three candidate layouts | ## What is not a document of this project diff --git a/docs/UI-LAYOUT.md b/docs/UI-LAYOUT.md new file mode 100644 index 0000000..538ed93 --- /dev/null +++ b/docs/UI-LAYOUT.md @@ -0,0 +1,168 @@ +# What the interface must show, and three layouts to choose from + +Written 2026-11-10. This is the design document the screens are built against. It says +what each page must show, where every fact comes from, what the keys are, and then three +layouts at three different shapes. Nothing here is decoration: each line exists because a +person needs it to make a decision or to know what is happening. + +## The four questions the interface answers + +1. **What is the state of the work?** todo, in progress, blocked, done — for one project. +2. **What is happening right now?** the run, what the agent changed, what it cost. +3. **What needs me?** blocked tasks, a merge that was refused, a task waiting for a person. +4. **What do I do about it?** reply, unblock, assign, create, merge. + +Anything that does not answer one of those four is not on a screen. + +## Where each fact comes from + +One owner per fact. The middle column is the only place the interface may read it. + +| What is shown | Read from | Never | +|---|---|---| +| task list, status, title, assignee | `GET /api/companies/{id}/issues` | a local cache or folder name | +| blockers ("blocked by AUD-163") | `GET /api/issues/{id}/diagnostics/blockers`, per task | the list endpoint — it carries no blockers | +| thread | `GET /api/issues/{id}/comments` | a copy we keep | +| run state, start and end | `GET /api/issues/{id}/runs` | a log file we write | +| cost | `GET /api/issues/{id}/cost-summary` | our own arithmetic | +| what changed | `git` in `currentExecutionWorkspace.cwd` | a diff we store | +| which folder, machine, session | `/.harness/harness.toml` | Paperclip (it does not know) | +| which task a viewer is on | the same file, `watching` | a hidden second copy | + +The rule that follows: **the interface is allowed to be wrong for one refresh, and is +never allowed to be right for the wrong reason.** Every screen shows the time of its last +read, so a stale screen says it is stale. + +## Pages and panes + +A **page** is a workspace. A **pane** is one program in it. TUIOS keeps part of the +keyboard, so no screen may use `h j k l z n` for its own actions, and a bare Esc must be +free to close a box. + +| Page | Pane | Must show | Keys | +|---|---|---|---| +| shell | shell | a prompt in the project folder | — | +| tree | task tree | groups todo / in progress / blocked / done; identifier, status, assignee, title, blocker; a count per group | ↑↓ Tab Shift-Tab move · `a` assign to Builder · `enter` open this task in reply and log · `r` re-read · `q` quit | +| reply | conversation | the thread with author and time; a box to type in; the status that will be sent with the reply | `tab` focus the box · `enter` send · `s` cycle status · `esc` leave the box · `r` re-read | +| log | run log | run state, start and end, then activity events, newest last | `↑↓` scroll · `g`/`G` top/bottom · `r` re-read · `q` quit | +| diff | change | worktree path and branch; commits on the branch; changed files with counts; the diff itself | `↑↓` scroll · `r` re-read | +| new | new task form | title, what it must do, must finish first, proves it is done, assign | `tab`/`↑↓` next field · `enter` next, and create on the last · `esc` cancel | + +Two decisions to settle with you, because they change the shape: + +- **Is the diff its own pane or the bottom half of the log?** Its own pane is honest (a + long diff never squeezes the log) and costs a workspace. One pane split in two is + tighter and hides the diff while the log scrolls. +- **Does the tree drive the other panes?** My proposal: pressing `enter` on a task writes + `watching = AUD-163` into the project's `harness.toml` and asks TUIOS to show the reply + page. The reply, log and diff panes watch that file and reload when it changes. One + fact, one owner, no message bus. + +## What must never happen + +- A pane that lies: showing a task as in progress after the run ended. +- A key that does nothing visible, or two keys that do the same thing differently. +- A layout that breaks below some size instead of saying "too small". +- A second copy of anything Paperclip owns, on disk or in memory across refreshes. +- An action with no visible result: every write must show what came back, or the error. + +--- + +# The layouts + +## A — one page each (what exists today, and the safe default) + +Every page is its own workspace, one pane, the whole width. Best at 80 columns and on a +phone-sized terminal. Worst for watching two things at once, because switching costs a +keystroke and hides the tree. + +``` +┌ task tree ── workspace 2 of 5 ────────────────────────────────────────────────┐ +│ spike-2026-11-10 · read 11:42:07 · 6 tasks │ +│ │ +│ TODO (2) │ +│ ▸ AUD-166 todo — Add the weekly cost report │ +│ AUD-167 todo — Document the merge gate [AUD-166 todo] │ +│ IN PROGRESS (1) │ +│ AUD-165 in_progress Builder Review gate probe │ +│ BLOCKED (1) │ +│ AUD-162 blocked — Tree render check [AUD-161 todo] │ +│ DONE (2) │ +│ AUD-163 done Builder Write NOTES.md │ +│ │ +│ ↑↓ move · a assign · enter open · r re-read · q quit │ +└──────────────────────────────────────────────────────────────────────────────┘ + 1 shell 2 tree* 3 reply 4 log 5 diff 6 new +``` + +## B — cockpit: tree and conversation side by side + +One workspace holds the work; the tree stays visible while you read and reply. The log +and diff live one workspace away, because during a conversation the change matters less +than what the agent said. + +``` +┌ tree 34% ─────────────────┐┌ reply ────────────────────────────────────────────┐ +│ spike-2026-11-10 ││ AUD-165 in_progress · Builder │ +│ read 11:42:07 ││ │ +│ ││ agent 11:38 │ +│ TODO (2) ││ Workspace Ready — branch AUD-165-… │ +│ ▸ AUD-166 Add weekly cost ││ │ +│ AUD-167 Document merge ││ you 11:40 │ +│ ⤷ waits on AUD-166 ││ Please also guard against HOME being unset. │ +│ IN PROGRESS (1) ││ │ +│ AUD-165 Review probe ││ agent 11:41 │ +│ BLOCKED (1) ││ Done — guard added, tests pass. │ +│ AUD-162 Tree render ││ │ +│ ⤷ waits on AUD-161 ││ │ +│ DONE (2) ││ │ +│ AUD-163 NOTES.md ││ ┌───────────────────────────────────────────────┐ │ +│ AUD-164 List lines ││ │ > _ │ │ +│ ││ └───────────────────────────────────────────────┘ │ +│ ↑↓ move · a assign ││ status → in_progress · s status · enter send │ +└───────────────────────────┘└───────────────────────────────────────────────────┘ + tab focus · esc leave box · r re-read +``` + +## C — cockpit with the change always visible + +Tree on the left, conversation top right, diff bottom right. The most information at once, +and the only layout where a person can see a claim and the code that backs it at the same +time. It needs width: below about 120 columns the diff half is unreadable and the layout +must fall back to B or A. + +``` +┌ tree 28% ──────────┐┌ reply 72% ──────────────────────────────────────────────┐ +│ TODO (2) ││ AUD-165 in_progress · Builder read 11:42:07 │ +│ ▸ AUD-166 cost ││ agent 11:38 Workspace Ready — branch AUD-165-… │ +│ AUD-167 docs ││ you 11:40 Please also guard against HOME being unset.│ +│ ⤷ AUD-166 ││ agent 11:41 Done — guard added, tests pass. │ +│ IN PROGRESS (1) ││ ┌─────────────────────────────────────────────────────┐ │ +│ AUD-165 probe ││ │ > _ │ │ +│ BLOCKED (1) ││ └─────────────────────────────────────────────────────┘ │ +│ AUD-162 tree │├─ diff ──────────────────────────────────────────────────┤ +│ ⤷ AUD-161 ││ cleanup.sh · branch AUD-165-… · 1 commit · +4 −0 │ +│ DONE (2) ││ @@ -1,2 +1,3 @@ │ +│ AUD-163 NOTES.md ││ -rm -rf "$HOME/tmp" || true │ +│ ││ +[ -n "$HOME" ] && rm -rf -- "$HOME/tmp" || true │ +│ ↑↓ · a · enter ││ ↑↓ scroll · r re-read │ +└────────────────────┘└────────────────────────────────────────────────────────┘ +``` + +--- + +# Recommendation + +**C, falling back to B, falling back to A**, chosen by the width the pane actually has, not +by a setting. The person gets the most information their terminal can carry, and never a +layout that pretends to have room it does not. + +Concretely: + +- 150 columns and wider: C. Tree 28%, right split 55/45 between reply and diff. +- 110–149 columns: B, with the diff one workspace away. +- 80–109 columns: A, one page each. +- Below 80×24: the "too small" screen with the numbers, on every page. + +Two things to settle before building: whether the tree drives the other panes through +`harness.toml`, and whether the four screens stay four workspaces or become two.