From 8ea6413cccecf90e67b76c768307fa0ae65a640c Mon Sep 17 00:00:00 2001 From: Jacob Stephens Date: Mon, 19 Oct 2026 12:05:11 -0400 Subject: [PATCH 1/2] Grill #711 Q27: the Console's Inbox, Themes and health words Record the prototype verdict (the console variant: one layout, Themes made of tokens, an attention-grouped Inbox) and Rounds 6 and 7 of the grilling. Add Inbox, Needs you, Silent, Slow, Usual range and Theme to the glossary, ADR 0018 for one layout with Themes, and the three research notes behind the prototype. Co-Authored-By: Claude Opus 5.5 --- .scratch/grill-with-docs/711-live-runs.md | 199 +++++++++++++- CONTEXT.md | 26 +- ...8-the-console-has-one-layout-and-themes.md | 14 + docs/research/console-run-monitoring-ui.md | 225 ++++++++++++++++ docs/research/focus-theme-attention.md | 161 ++++++++++++ .../software-factory-console-trends.md | 246 ++++++++++++++++++ 6 files changed, 867 insertions(+), 4 deletions(-) create mode 100644 docs/adr/0018-the-console-has-one-layout-and-themes.md create mode 100644 docs/research/console-run-monitoring-ui.md create mode 100644 docs/research/focus-theme-attention.md create mode 100644 docs/research/software-factory-console-trends.md diff --git a/.scratch/grill-with-docs/711-live-runs.md b/.scratch/grill-with-docs/711-live-runs.md index 1e266185c..d2ff18412 100644 --- a/.scratch/grill-with-docs/711-live-runs.md +++ b/.scratch/grill-with-docs/711-live-runs.md @@ -308,6 +308,8 @@ The variations would live in `.scratch/prototypes/711-console/` and go on a thro *Checked:* Open until you pick a variant (see Waiting on research). The handoff predates Q18's accounts, so its prototype sign-in is a single password field. An email field and the code step (Q30) are worth a look in whichever variant you pick. +*Checked (2026-10-19):* decided on your laptop: the `console` variant, opening on its Inbox page. It's on the throwaway branch `prototype/711-console` (commit `05b1b0a`), with three research notes. The verdict is under "Settled" (the Q27 bullets), and the questions it raised are Round 6. The prototype's sign-in is still a stub; the real one is Q18 and Q30. + ## Round 4 (answered) **Q28 - Where Console accounts are kept.** This builds on your Q18 answer: email and password accounts, for the addresses the User config allows. Each account is an email, a password hash, and whether the address has been verified. Its sign-ins need to survive a restart of `thirdshift console`, since a session lasts 30 days. Accounts change from the page (create, reset), but the Credentials are written by Setup and hold the Resend key. The options: @@ -396,15 +398,165 @@ The options: *Answer:* we'll run /to-spec to create the specs, then /to-tickets for each spec +## Round 6 (answered) + +From the Q27 verdict. Everything in #711, the CLI, has shipped (see Research results, 2026-10-19), so changes to the CLI below become Tickets in #776, the Console Spec. + +**Q35 - The Inbox replaces "live Commands first, then history".** In the prototype you chose, the Console opens on the **Inbox**: Commands grouped by what they ask of you, not by whether they're live. The groups are Needs you, Ready for review, Landing, Working, Done and Resolved. That reopens Q1's "live ones first". The options: +- (a) **The Inbox is the Console's home page.** The History page holds every ended Command, newest first, with filters for outcome and repository, back to the oldest logs. +- (b) Keep "live first, then history" as the home page, and make the Inbox a page of its own. + +*Recommended:* (a). It's what you picked after trying both. A failure from last night needs you more than a Run that's working fine, and "live first" puts the Run first. + +*Answer:* agree + +**Q36 - What goes in Needs you, and in what order.** In the prototype, Needs you holds: +- **Died:** the process is gone with no outcome. +- **Silent:** a live Run whose logs have stopped growing (Q38). +- **Failed.** +- **Triage:** a Stop that labelled the issue `needs-triage`. +- **A Security finding waiting** on you. +- **Slow,** shown as "look" rather than urgent. + +It sorts urgent first, then by escalation step, then oldest first. That puts yesterday's failures above a Run that's silent right now. The options: +- (a) **Live problems first** (Silent, then Slow), then the ended ones (Died, Failed, Triage, Finding), each newest first. +- (b) Keep the prototype's order. + +*Recommended:* (a), as the laptop agent recommended too. A live problem still costs machine time, and a Stop can still save it. An ended one waits the same either way. + +*Answer:* agree + +**Q37 - How an item leaves Needs you.** "Acknowledge" is ruled out (nothing the CLI can't do), and the Console reads only this machine's files. In the prototype, a failure stays in Needs you forever, so nine months of failures would pile up. The options: +- (a) **It leaves when a later Command on the same issue starts on this machine, or once it is 7 days old.** After that it's only on History. Done shows the last 24 hours; Resolved shows Commands that ended 1 to 7 days ago with nothing waiting. +- (b) It leaves when GitHub says the issue moved on (closed, or relabelled). That means the Console reading GitHub on every refresh, which neither it nor `status` does today. +- (c) It leaves by age alone. + +*Recommended:* (a). A later Command on the issue means someone (you, or a Pickup run) has already acted. 7 days covers a weekend away, and nothing is read from GitHub. + +*Answer:* agree, and I want the user to be able to configure in their User config how long they want that period for being moved to resolved is - for 7 to be the default but for the view in the web ui console to be controlled by that user config. + +*Checked:* The setting's name, and whether it also sets how far back Resolved reaches, is Q45. + +Though alternatively I'm considering allowing users to "Acknowledge" by adding a folder to .thirdshift which stores some web ui state - initially probably just these acknowledgements / dismissals. I'm a bit wary to do this though as that introduces maybe a new kind of state stored on the machine. However, it's not entirely groundbreaking, as while much state is stored on GitHub, the log, trace, and configuration data is still stored on the host. I want to weigh the tradeoffs here. The CLI would need to be able to read this state file. I suppose though that this means there's a way to write to the server from the Console, which may be fine and worth it, just an expanding of the console. + +**Q38 - Silent and Slow, precisely.** The research says a stall is silence, not stage length, and you accepted that. These need definitions the CLI and the page share. The options: +- (a) **Silent** means a Run in a stage whose Session log and Command log have both stopped growing for 10 minutes. It escalates at 30 ("silent 45 min · past 30"). Stages that wait, such as CI watch and Self-merge, write a waiting line to the Command log at least every 5 minutes. Today CI watch logs only when the count of running checks changes (see Research results), so a long CI run would read as silent. **Slow** means the stage has run past the top of its **usual range**, and it escalates at twice that. The **usual range** is the middle half (the 25th to 75th percentile) of that stage's times over the last 30 Command records in the same repository. It's shown only when there are at least 3. The thresholds are fixed in code, not User config settings. +- (b) The same, but the usual range is machine-wide, across all repositories, as in the prototype. +- (c) The thresholds go in the User config. + +*Recommended:* (a). chart35's checks take far longer than thirdshift's, so a machine-wide range would call one repository slow and miss slowness in the other. Settings can come later if a fixed number turns out wrong. + +*Answer:* agree, and I want the silent time definition to be configurable in the User config (default 10 minutes), as well as maybe the waiting line write frequency (default 5 min as it is now). + +*Checked:* Both settings are read by `thirdshift status` as well as by the page, so they can't sit under `[console]`. Their names and the check that the waiting line comes more often than the silent time are Q45. + +**Q39 - The CLI's side of the new pages.** Every view must also be a CLI command with `--json` (Q10). The options: +- (a) **`thirdshift status` shows the Inbox's groups in the Inbox's order,** Needs you first, with the Silent and Slow words. `--json` gives each Command its group and health. Lanes, Stages and Waterfall draw data that `status --all --json` and `show --json` already carry: stage start times, with the usual range added. So they get no commands of their own, and the parity test pairs each page with the command whose JSON holds its data. Choosing a theme only changes how the page looks, not what it shows about Commands, so it has no CLI command. +- (b) A new `thirdshift inbox` command, with `status` left as it is. + +*Recommended:* (a). `status` already answers "what's on this machine", and one ordering for both means the page and the terminal never disagree about what needs you. + +*Answer:* agree + +**Q40 - Which pages #776 builds.** You chose seven pages: 1 Inbox, 2 Lanes, 3 Stages, 4 Waterfall, 5 History, 6 Logs, 7 Security. #776's Out of Scope says "charts", and the handoff left them out. The options: +- (a) All seven in #776. +- (b) **Inbox, Lanes, Stages, History, Logs and Security in #776. Waterfall gets a follow-up issue.** +- (c) Inbox, History, Logs and Security now; the three time views later. + +*Recommended:* (b). Lanes and Stages need only stage start times and the usual range (Q38). The Waterfall goes down to single tool calls, and Session log lines carry no time (see Research results). Its times would have to be matched from the Command log's `HH:MM:SS` lines, which is a parser of its own. Out of Scope then reads "the Waterfall, and charts of totals over time". + +*Answer:* a, but we'll handle the scope by the to-spec skill then to-tickets workflow, so we can make additional tickets to handle the waterfall extra, or make two specs then two ticket sets alternatively. Then we can fit charts in somehow too. + +*Checked:* How the Specs are cut, and the charts, are Q48. + +**Q41 - Where themes and other per-viewer choices live.** In the prototype, the chosen theme, the themes you make, "new since you last looked", hidden sections and Pause motion are all kept in the browser. None of them hides a problem. Each machine's Console is its own site, so one browser's choices don't carry from `console.thirdshift.app` to `thirdshift.stephens.page`. The options: +- (a) **The built-in themes are compiled into the binary. Everything per-viewer stays in the browser,** and themes move between Consoles by JSON export and import. Nothing is saved on the server. +- (b) Also a machine default in the User config (`[console] theme = …`) and theme files in the config folder. The page reads them but doesn't write them. + +*Recommended:* (a) now. (b) gets an issue if moving themes by hand gets tiresome. It is read-only, so it fits Q10, but it means more for #776 to build. + +*Answer:* a and b - though thinking again here about the Q37 answer and how much if any writing to the server to allow right now from the console. And then wondering whether to make it so that from the console the user can write to the console section of their User Config. That could be nice for them and intuitive - that that is where all their thirdshift settings on that host live, rather than some in their browser and some in the server, and that would smooth out using multiple browsers too - one theme showing on different browsers for a user on that host by the server. + +*Checked:* The page writing the User config is a second action beside Stop, so ADR 0016 ("only reads, and does what the CLI does") needs amending, and each write needs a CLI command too (Q10). What the page may write is Q46. + +**Q42 - Fonts, given "nothing loaded from another site".** #776 says no CDN, fonts included. The prototype and thirdshift.app both load Google Fonts. The built-in themes use ten families: Big Shoulders Display, JetBrains Mono, Inter, Caprasimo, Nunito, Barlow Condensed, Titillium Web, Atkinson Hyperlegible, IBM Plex Sans and IBM Plex Mono. All are under the SIL Open Font License, which allows bundling. The editor lists eight more. The options: +- (a) **Embed Latin-subset woff2 files for the built-in themes' fonts only, at the weights they use.** The editor offers those, plus the system font stacks. A theme naming any other font falls back to its stack. +- (b) Let themes load from Google Fonts. That breaks the rule, and tells Google about every page view. +- (c) System fonts only. Press and Factory would lose their look. + +*Recommended:* (a). Ten families at one or two weights each comes to a few hundred KB in a binary already measured in MB, and the page works with no internet at all. + +*Answer:* agree, though I wonder how easy or difficult it will be in this case for users to use their own fonts. I wonder about a theme system that allows putting fonts in a .thirdshift/console/themes folder or something. + +*Checked:* A themes folder that holds fonts too is Q47. + +**Q43 - Glossary terms and ADRs.** The candidates: +- **For `CONTEXT.md`:** **Inbox** (naming its groups), **Needs you**, **Silent**, **Slow**, **Usual range** and **Theme**. Each group and page name is a heading on the page, not a term. +- **An ADR,** "The Console has one layout, and its looks are themes made of tokens". It's hard to reverse once people have exported themes, a reader might wonder why there aren't several layouts, and you weighed both. + +Silence as the stall rule goes in Silent's definition. "Motion only for thirdshift's activity" and "visual calm" go in #776 as rules, since they're cheap to change. + +*Recommended:* yes to both. + +*Answer:* agree + +*Checked:* `CONTEXT.md` now has Inbox, Needs you, Silent, Slow, Usual range and Theme, and the Console entry opens on the Inbox. The ADR is [0018](../../docs/adr/0018-the-console-has-one-layout-and-themes.md). + +**Q44 - Recording the verdict.** #711 is closed, now that the CLI has shipped, so the pointer belongs on #776. The options: +- (a) **Copy the three research notes from the prototype branch onto `web-ui` and commit them with this round.** Leave the prototype on `prototype/711-console`. Post a comment on #776 with the verdict and the branch commit. Then rewrite #776's body (the look, the pages, the new stories and rules) and run `/to-tickets 776`. +- (b) The same, but leave the research notes on the prototype branch. + +*Recommended:* (a). The notes cite primary sources and are the reasons behind Silent, the Inbox and Focus, and `docs/research/` is where such notes live. Posting the comment and pushing are the steps you asked to approve first; "agree" approves both. + +*Answer:* agree + +*Checked:* The three notes are copied to `docs/research/`, pointing at the prototype branch. The software-factory note's claim that `--requeue` was invented is corrected. Committed and pushed with this round, and the verdict is posted on #776. #776's body is rewritten once Round 7 is answered. + *Checked:* Read as (b), two Specs, since `/to-tickets` runs "for each spec". The ADR is written: [ADR 0016](../../docs/adr/0016-the-console-is-a-long-running-reader.md). +## Round 7 (open) + +**Q45 - The new settings: names, and what they govern.** Q37 and Q38 add three settings to the User config. `thirdshift status` reads them too, so they belong outside `[console]`. The options: +- (a) **`inbox.days = 7`** sets how long an ended problem stays in Needs you, and how far back Resolved reaches. Done stays at one day. **`inbox.silent_minutes = 10`** sets when a Run is Silent; it escalates at three times that. **`logs.waiting_line_minutes = 5`** sets how often a waiting stage, such as CI watch or Self-merge, writes a line. If the waiting line doesn't come more often than the silent time, `status`, the page and Setup warn, and thirdshift uses half the silent time instead, so a waiting stage never reads as Silent. +- (b) The same settings, but one for Needs you and another for Resolved. + +*Recommended:* (a). Your answer named one period, and with one number Needs you and Resolved never disagree about what happened this week. Clamping the waiting line keeps a typo from turning every CI watch red. + +*Answer:* + +**Q46 - What the page may write.** You'd like settings on this host to live in the User config, so a Theme follows you from browser to browser, and the page can change them. The options: +- (a) **The page writes only the Console's look, under `[console]`: the chosen Theme and the hidden sections.** It never writes the allowlist, the addresses, the thresholds, or any other section. Every write is also a CLI command: `thirdshift console theme ` and `thirdshift console sections`. Each one keeps the file's comments, as Setup does, and goes in the Console log naming the account. The setting is per machine, so every account on that Console sees the same Theme. "New since you last looked", Pause motion, what's folded, and the peek stay in the browser. ADR 0016 is amended: the page reads, Stops, and sets its own look. +- (b) The same, but each account's look is kept with its Console account, so two people on one machine can each have their own. +- (c) As (a), but the page can also change the `inbox.*` settings. + +*Recommended:* (a). One place for settings is what you asked for, and a signed-in phone that can change only the look can't widen who signs in. (b) is worth doing only once a machine has more than one person. + +*Answer:* + +**Q47 - Your own Themes and fonts.** The options: +- (a) **A folder, `~/.thirdshift/console/themes/`, holds one `.json` per Theme you made, and a `fonts/` folder of `woff2`, `woff`, `otf` or `ttf` files.** The Console serves those fonts from its own address, so nothing comes from another site. A Theme names a font in one of three ways: a built-in family, a system stack, or a file in `fonts/`. The page's editor saves Themes into the folder. Fonts are added by copying files in, not by uploading them through the page. The CLI has `thirdshift console theme list`, `import ` and `export `. +- (b) As (a), with font uploads through the page too. +- (c) Themes inline in the User config, and no font files. + +*Recommended:* (a). Copying a font file in is one `scp` for whoever runs the machine. An upload form would be the page's first way of putting arbitrary files on the server, for little gain. + +*Answer:* + +**Q48 - How the Console's Specs are cut, and the charts.** Q40 put all seven pages in, with scope managed through `/to-spec` and `/to-tickets`. The options: +- (a) **Rewrite #776 to cover all seven pages, Themes and the settings.** `/to-tickets` puts the Waterfall's Tickets last, including matching tool calls to the Command log's times. Charts get an issue of their own (`needs-triage`), to be grilled later, since nothing yet says what they'd show. Candidates are Commands per day by outcome, each stage's time week by week, and tokens per day. +- (b) Two Specs: #776 without the Waterfall, and a second for the Waterfall and the charts. + +*Recommended:* (a). The Waterfall is settled enough to cut Tickets for, and the charts aren't. Putting the charts in a Spec now would hold the Waterfall up behind questions nobody has asked yet. + +*Answer:* + ## Settled by earlier answers (shout if any is wrong) - Nothing schedules itself to keep the Console current. State comes from what each Command writes as it goes (ADR 0009). - Logs keep their place, `///`, and their names. The Console reads them where they are (ADR 0011). - The Console can't assume `thirdshift.app`. Someone else running thirdshift has their own domain, or none, so the address is a setting, not built in. Here it's `console.thirdshift.app` (Q8). - **The page does nothing the CLI can't** (your note before Q1, Q10). Every view and action reaches the CLI first or at the same time, Stop included, and a test pairs each page route with its command. The CLI's `--json` is the only API anyone is promised. -- **The first version can act, so it's more than a viewer** (Q1 c). It lists every Command on this host, live ones first, with their logs, and it can Stop a live one. +- **The first version can act, so it's more than a viewer** (Q1 c). It lists every Command on this host, with their logs, and it can Stop a live one. "Live ones first" is reopened by the Inbox (Q35). - **History goes back as far as the logs in the current layout do** (Q1, Q26 b). From 2026-10-03, Commands come from the Activity logs and Command logs, without stages until the Command record exists. From 2026-09-25 to 2026-10-02 there are only Session logs, grouped by issue and stamp, with no outcome. - **Each machine serves its own Console** (Q2 a). Nothing needs a list of machines. Finding from GitHub which machine a Run is on is left for when there's a second machine. - **Each Command keeps a Command record:** one file beside its Command log, kept after it ends, with its process id, its issue, each child Run's stages and when each began, and its outcome (Q3 b, Q11 a). One whose process is gone, with no outcome, shows as died at its last stage. A SQLite index built from these files can come later, if a query gets slow. The term is now in `CONTEXT.md`. @@ -423,7 +575,7 @@ The options: A Command is named by its issue, such as `chart35#239` or the issue URL, or for a Pass with no issue, by its kind and stamp. - **A Spec run shows every Ticket:** running (with its stage and age), merged, failed, waiting on named blockers, or not started (Q20 a). - **The code stays portable,** with systemd only in `console install`. An issue will be filed for launchd on macOS (Q21 a). -- **Only the current log layout is read** (Q26 b). stephens.page's flat Session logs from before ADR 0011 aren't shown unless you move them. This host's earliest Session logs, from 2026-09-25, are already in the current layout, so they still show. +- **Only the current log layout is read** (Q26 b). stephens.page's flat Session logs from before ADR 0011 aren't shown unless you move them. **Corrected 2026-10-19:** this host's Session logs from 2026-09-25 to about 2026-10-12 are in `sessions/`, which isn't the current layout. Since #599 (2026-10-09), Session logs sit beside their Command log. So those older Commands show from their Command logs, without their Session logs, unless you move them. Shout if you'd rather the Console also read `sessions/`. - **Console accounts are kept in a file of their own** beside the Credentials, readable only by you, holding argon2id hashes and hashed session tokens (Q28 a). Taking an address off the allowlist ends its sessions and blocks it at once, but keeps the account. With nobody on the list, `thirdshift console` refuses to start unless `--no-sign-in` is given (Q29 a). - **One "set your password" flow by email code creates an account or resets its password** (Q30 a). The page answers the same way whether or not an address is allowed. A code is 6 digits, valid for 15 minutes, with 5 tries, and codes go out at most once a minute and 10 times a day per address. `thirdshift console password --email
` does the same on the CLI. Without a Resend key, the email flows are off and the CLI is how accounts get passwords (Q31 a). Sign-in emails come from `email.from`. - **Setup asks whether to run the Console,** its whole address (with an example), and the allowed emails, which default to `email.to`. Then it offers `console install` (Q32 a). @@ -431,6 +583,34 @@ The options: - **Who did what** (Q33 a). A Stop writes an Activity log line naming who asked: the account's email from the Console, or the Unix user from the CLI. Account events go in a **Console log** per machine, which `thirdshift console log` prints and the page shows. Page views aren't recorded. `CONTEXT.md` has the Console log, and the Activity log and Stop entries now mention who asked. - **Two Specs, made with `/to-spec`, then `/to-tickets` for each** (Q34 b). #711 is the CLI: the Command record, `status`/`show`/`logs`, then Stop. A new Spec covers the Console: the read-only page with the Session log view, accounts and sign-in, Stop on the page, `console install`, Setup's questions, the Console log, and the look last, once Q27 is decided. The follow-up issues are filed separately: launchd on macOS, stopping a single Ticket's Run, and a Claim that names its machine. The CLI Spec goes first and doesn't wait on Q27; the Console Spec's last Ticket, the look, does (your note on 2026-10-18). - **ADR 0016 records `thirdshift console` as a reader that runs all the time,** next to ADR 0009's "nothing schedules itself". +- **The look (Q27), from the `console` prototype,** in your words where quoted: + - **One layout, many themes:** "I want the layout to be the same, but for there to be an idea of appearance themes that the user can choose between or even create themselves". A theme is design tokens: colours, fonts, shape, effects and motion. There's a picker and an editor, and themes export and import as JSON. + - **The default is Focus, following the system's light or dark setting.** The picker lists Focus, Plain, Press, Signal, Garden and Factory, each as auto, light and dark. Focus means "weight follows need". Plain is the quiet inbox look. Press is thirdshift.app's press look in plain words. Signal uses colour only for state, in Okabe–Ito colours. Garden and Factory are themed; Factory takes after Factorio. Every built-in theme passes AA text contrast, and Focus also passes APCA. + - **Pages, a level above sections:** 1 Inbox, 2 Lanes, 3 Stages, 4 Waterfall, 5 History, 6 Logs, 7 Security. Keys `1` to `7` switch pages, and the page is in the URL as `?page=`. Lanes has 3.5 h, 12 h and 24 h windows: "I like how the lanes variant shows the time different processes take". Which pages #776 builds is Q40. + - **Inbox rows** show a state word (never colour alone), the issue and title, a one-line now-line and the age. A Spec run's Tickets show under it as a plan checklist. Needs you is open on load and can be folded. + - **The peek** is the details beside the list, or a bottom sheet on a phone, and it's closed on load. + - **A stall is silence, not stage length.** "Slower than usual (12–17 min), still working" is different from "no output for 14 min, may be stuck". Problems escalate in words: "silent 45 min · past 30", "3× usual". It's defined in Q38. + - **Motion only for thirdshift's activity:** "I want animation to be reserved to communication of some activity of thirdshift". That keeps the Working spinner, a heartbeat dot when a log moves, the latest-line flash, the live log cursor, the stopping bar, and stripes on the running stage. A silent alarm pulses three times, then holds. Factory's conveyor and Garden's bed move only while a Command is live. A Pause motion control meets WCAG 2.2.2. + - **Visual calm:** no coloured bars between sections, though the title's bar is fine. With Needs you open, every section heading fits above the fold on a 14" laptop. + - **Keys:** + - `j` and `k` walk rows and section headings, and wrap. + - `space` folds a heading, or opens or closes the peek on a row. `enter` opens the full log. + - `esc` closes things one layer at a time, then hides the selection mark. + - `g` plus a letter jumps to a section or page; a tooltip lists them. `z` folds the current section. `?` lists every key. `Shift+T` opens themes. + - **Chrome:** a Sections chooser hides the sections you pick. The tab title says "‹n› need you", and the favicon gets a dot when something is urgent. + - **The page has no acknowledge, shelve or steer,** since the CLI can't do them (Q10). The research agrees. + - **It works at 390 px** with no sideways scroll. +- **The Inbox is the home page** (Q35 a). History holds every ended Command, newest first, filtered by outcome and repository. +- **Needs you puts live problems first** (Q36 a): Silent, then Slow, then Died, Failed, Triage and Finding, each newest first. +- **An ended problem leaves Needs you** when a later Command on the same issue starts on this machine, or once it's older than a User config setting, 7 days by default (Q37 a). Done is the last day. Nothing is read from GitHub. The setting is Q45. +- **Silent and Slow** (Q38 a). Silent is no growth in the Session log or Command log for the silent time, a User config setting with a default of 10 minutes. Waiting stages write a line at a set interval, a User config setting with a default of 5 minutes. Slow is past the top of the usual range, which is the middle half of that stage's last 30 times in the repository, shown once there are 3. Their names are Q45. +- **`thirdshift status` shows the Inbox's groups and order,** and `--json` carries each Command's group and health (Q39 a). Lanes, Stages and Waterfall draw `status --all --json` and `show --json`, with the usual range added. Choosing a Theme has a CLI command only because the page writes it (Q46). +- **All seven pages are wanted** (Q40 a). Scope is handled when the Specs and Tickets are cut (Q48). +- **Built-in Themes are compiled in. Settings live in the User config, which the page can write in part** (Q41 a and b). What it may write is Q46, and where user Themes live is Q47. +- **The built-in Themes' fonts are embedded,** as Latin-subset woff2 files at the weights they use (Q42 a). Users' own fonts are Q47. +- **`CONTEXT.md` has Inbox, Needs you, Silent, Slow, Usual range and Theme,** and [ADR 0018](../../docs/adr/0018-the-console-has-one-layout-and-themes.md) records one layout with Themes made of tokens (Q43). "Motion only for thirdshift's activity" and "visual calm" go in #776 as rules. +- **The research notes are on `web-ui`, the prototype stays on its branch, and the verdict is on #776** (Q44 a). +- **The confirm step's "requeue instead" is `thirdshift stop --requeue`,** which shipped with #773 and #774. The laptop agent thought the flag was invented; it was settled in Q12. - **The page borrows** nested child Runs, each stage with its age, a one-line latest event, and Stop only while the process is alive, with a confirm step on the page. Session logs get folded tool calls, collapsed thinking, a renderer per tool over a plain fallback, and appends rather than redraws (Q16 a). ## Research results (2026-10-17) @@ -475,6 +655,19 @@ The options: - **stephens.page's DNS:** Cloudflare, with a `*.stephens.page` wildcard to 68.183.62.24. `console.stephens.page` is taken: a redirect to `dashboard.stephens.page`, behind Cloudflare's proxy. No enabled site mentions `thirdshift`. Confirmed by `dig` and `grep` over `sites-enabled`. - **Lingering is off for you on stephens.page,** and the long-running apps there are system units. `systemctl --user` works only because a desktop session is open. Confirmed by `loginctl` and `/etc/systemd/system/`. +## Research results (2026-10-19) + +- **#711, the CLI, has shipped and is closed.** Its Tickets #768 to #774 merged as #777 and #779 to #784, `thirdshift stop --requeue` included. Confirmed by `gh issue view` and `src/args.rs` on `main`. +- **#776 is also labelled `architect-idea`,** so an Architecture review chose it as the next move. While it's `needs-triage`, every Architect run on thirdshift is skipped (CONTEXT.md, Architect idea). Confirmed by `gh issue view 776`. +- **Session log lines carry no time.** A Codex Session log is bare `thread.started`, `item.completed` and similar events. The Command log stamps every line `HH:MM:SS`, including one line per tool call (`implement: $ rg …`). Confirmed by `712-20261018T210511-0400-implement.jsonl` and its `.log`. +- **CI watch logs only when the count of running checks changes.** #712's CI watch had gaps of up to 2.5 minutes, so a longer CI run could go 10 minutes without a line. Confirmed by `712-20261018T210511-0400.log`, lines 218 to 223. +- **Session logs moved beside their Command log on 2026-10-09** (#599, commit `b26821d`). The ones before that are in `sessions/`. Confirmed by `git log` and `ls`. +- **thirdshift.app and the prototype load Google Fonts.** The built-in themes use ten families, all under the SIL Open Font License. Confirmed by `site/index.html` and the prototype's `themes.js`. +- **From the laptop's research notes** (on `prototype/711-console`, each citing primary sources): + - `docs/research/console-run-monitoring-ui.md` covers CI, workflow and trace UIs, and the SRE book. It's the source of silence as the stall rule, "usually" ranges, the Stop wording and the Stage grid. + - `docs/research/software-factory-console-trends.md` covers 2025–26 agent consoles. It's the source of the Inbox's grouping and the tab title's count. + - `docs/research/focus-theme-attention.md` covers alarm and HMI standards (ISA-18.2 and ISA-101, EEMUA 191), WCAG 2.2 and APCA. It's the source of the Focus theme. + ## Waiting on research -- **Q27, the look:** an agent on your laptop is building the variations from `/tmp/handoff-711-console-prototypes.md`. They are garden, plain, plain with a garden accent, and the press floor. +- Nothing. Q27 came back from your laptop on 2026-10-19. diff --git a/CONTEXT.md b/CONTEXT.md index 7f9dc9ea6..5e65634bd 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -232,7 +232,7 @@ One running record per repository of what the factory did there: a line when a * _Avoid_: cron log, pass log, history **Console**: -The web page a machine serves that shows every **Command** started on it, live ones first, with each one's child **Runs**, their stages and their logs, and from which a live Command can be stopped. Each machine serves its own, behind a sign-in. It does nothing the CLI can't do: every view and action it offers is also a command. +The web page a machine serves that shows every **Command** started on it, opening on its **Inbox**, with each one's child **Runs**, their stages and their logs, and from which a live Command can be stopped. Each machine serves its own, behind a sign-in. It does nothing the CLI can't do: every view and action it offers is also a command. _Avoid_: dashboard, floor, UI, web UI **Command record**: @@ -250,3 +250,27 @@ _Avoid_: user, login **Console log**: One running record per machine of what happened to its **Console accounts**: sign-ins, failed sign-ins, codes sent, passwords set and sign-outs, each naming the account. What people did to **Commands** goes in the **Activity log** instead, and what they only looked at is recorded nowhere. _Avoid_: audit log, access log + +**Inbox**: +The **Console**'s first page, and `thirdshift status`'s order: a machine's **Commands** grouped by what each asks of the **Day shift**. **Needs you** comes first. Ready for review holds Commands that ended ready, with a pull request waiting. Landing holds live Runs at CI watch or **Self-merge**. Working holds every other live Command. Done holds Commands that ended in the last day, and Resolved holds older ones with nothing waiting. Commands older still are only in the history. +_Avoid_: dashboard, feed, queue + +**Needs you**: +The **Inbox**'s first group: what won't come right unless the **Day shift** acts. Live problems come first, **Silent** then **Slow** Runs, and then the ended ones: a Command that died, one that failed, a **Stop** that left its issue `needs-triage`, and a **Security finding** waiting on a decision. An ended one leaves when a later Command on the same issue starts on the machine, or once it is older than the period the **User config** sets. Nothing else clears it, since the **Console** does nothing the CLI can't. +_Avoid_: alerts, attention, triage queue + +**Silent**: +A live **Run** whose **Session log** and **Command log** have both stopped growing for longer than the silent time the **User config** sets, 10 minutes unless set: it may be stuck. Stages that wait on something else, such as CI watch, write a line at intervals while they wait, so silence means the same thing in every stage. A stall is silence, not a long stage: a Run that is past its **Usual range** but still logging is **Slow**. +_Avoid_: stalled, stuck, hung + +**Slow**: +A live **Run** whose stage has gone past the top of that stage's **Usual range** while its logs keep growing. It is still working; it only needs a look, unlike a **Silent** one. +_Avoid_: late, overdue, stalled + +**Usual range**: +How long a stage usually takes in a repository: the middle half of that stage's times over the repository's recent **Command records** on the machine, shown only once there are enough of them. It is what makes a Run **Slow**. +_Avoid_: average, baseline, estimate + +**Theme**: +How the **Console** looks, its colours, fonts, shapes, effects and motion, over a layout that every Theme shares. thirdshift comes with some, and a user can make their own. Choosing one changes how the page looks, never what it shows. +_Avoid_: skin, style, variant diff --git a/docs/adr/0018-the-console-has-one-layout-and-themes.md b/docs/adr/0018-the-console-has-one-layout-and-themes.md new file mode 100644 index 000000000..2deca14dd --- /dev/null +++ b/docs/adr/0018-the-console-has-one-layout-and-themes.md @@ -0,0 +1,14 @@ +# The Console has one layout, and its looks are Themes made of tokens + +The #711 prototypes tried eighteen looks for the **Console**. Two layouts drew the most interest, and they were the same inbox under different looks: one plain, one in thirdshift.app's press style. So the Console has one layout, the **Inbox** and its pages, and every look is a **Theme**. A Theme is a set of tokens: colours, fonts, shape, effects and motion. It may not change what the page shows, its order, or where things are. The default is Focus, which follows the system's light or dark setting. Plain, Press, Signal, Garden and Factory ship beside it, and a user can make, export and import their own. + +## Considered Options + +- **Several layouts, one per look** (a garden bed, a press line, a grid). Rejected. Every layout would need its own tests, phone checks and keyboard model. A layout tied to the garden metaphor would also have to be redrawn whenever the metaphor moves. +- **One look and no Themes.** Rejected. The plain and press looks were each wanted for different moods, and a user with their own style would have no way to have it. + +## Consequences + +- Every built-in Theme is checked for AA text contrast, and Focus is also checked for APCA. A user's Theme is theirs to check. +- Motion belongs to the layout, not the Theme. It is reserved for thirdshift's activity: a Theme can change how a live Command moves, but it can't make anything else move. +- Once people have exported Themes, the token set becomes a format to keep: new tokens need defaults, so older Themes keep importing. diff --git a/docs/research/console-run-monitoring-ui.md b/docs/research/console-run-monitoring-ui.md new file mode 100644 index 000000000..91fff5c4d --- /dev/null +++ b/docs/research/console-run-monitoring-ui.md @@ -0,0 +1,225 @@ +# What a run-monitoring Console should show: lessons from CI, orchestrators, agent and trace UIs + +Research date: 2026-10-18, for issue #711 (the Console) and its Q27 UI prototypes in `.scratch/prototypes/711-console/` (kept on the branch `prototype/711-console`, commit `05b1b0a`). + +**Question.** The Console is one machine's page of its own **Commands**. It shows live **Runs** with their stage and how long they have been in it, a **Pickup run** → **Spec run** → **Tickets** nesting, outcomes, Commands whose process died, a Stop with a confirm step, **Session logs** with grouped tool calls, the **Command log**, and **Security findings**. The **Day shift** reads it, often on a phone. What do mature tools in neighbouring fields show about running and finished work, and why? Which of those features fit thirdshift's rules: the page does nothing the CLI can't; no Start buttons, charts or cross-machine view for now; phone first? Which should go into the prototypes, or into new variants? + +**Method.** + +- Read the first-party docs, product pages and changelogs of each tool, cited inline. Where a page gave nothing on a point, the point is marked **[unverified]** or left out. +- **CI/CD:** GitHub Actions (run graph, logs, workflow commands, cancellation, job summaries, timeouts), Buildkite (build page, log groups, annotations, waterfall) and GitLab pipelines. +- **Orchestrators:** Temporal Web UI and its Activity heartbeats, the Airflow UI, the Dagster webserver and Argo Workflows (`stop` against `terminate`). +- **Agent and LLM UIs:** Langfuse (timeline, agent graphs), LangSmith (trace tree, cost), the GitHub Copilot coding agent's session pages, Devin's session tools, Session Insights and usage, the Cursor agent and its Cloud Agents API, and Codex cloud. +- **Tracing:** Jaeger and Grafana's trace view (critical path, minimap). +- **Principles:** the Google SRE book's chapters on monitoring and on-call; Kubernetes' progress deadline as a primary source on detecting a stall. +- **UX:** Nielsen Norman Group on progressive disclosure, on dashboards and on status trackers; GOV.UK Design System tags and task lists; Android's list-detail layout. +- Mapped each finding onto the thirdshift vocabulary in [CONTEXT.md](../../CONTEXT.md) and onto the seven prototype variants: `garden`, `plain`, `accent`, `press`, `pixel`, `briefing` and `lanes`. + +**Out of scope.** Building any of it; the server, htmx and auth design; cross-machine views; anything that starts work. Apple's notification guidance was in scope, but its HIG page didn't render for the fetcher, so it isn't cited. + +## TL;DR + +- **Lead with what needs a human, not with what is running.** The SRE book says pages must be *actionable*, should *require intelligence*, and should be driven by symptoms ("what's broken") rather than causes ([SRE: Monitoring](https://sre.google/sre-book/monitoring-distributed-systems/), [SRE: Being on-call](https://sre.google/sre-book/being-on-call/)). Buildkite's build page can group steps by state, which puts failed steps and steps "Waiting for input" at the top, and the `f` key jumps to the next failure ([Buildkite build page](https://buildkite.com/docs/pipelines/build-page)). Every variant should open on a small "needs you" strip: died, stalled, failed, findings waiting. +- **"Stalled" should mean *no progress for a while*, not *a long time in one stage*.** + - Kubernetes reports a Deployment as stalled when it makes no progress within `progressDeadlineSeconds`. It "takes no action … other than to report a status condition" ([Kubernetes Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)). + - Temporal's Heartbeat Timeout is "the maximum time between Activity Heartbeats", and each heartbeat says the Worker "has not crashed" ([Temporal: detecting Activity failures](https://docs.temporal.io/encyclopedia/detecting-activity-failures)). + - The Session log is thirdshift's heartbeat. Show "last event 40 s ago" next to "review · 52 min", and flag a stall on the gap since the last event, not on stage age alone. +- **Compare against what is normal here.** Airflow shows task durations across recent runs so you can "spot recurring issues or performance trends at a glance" ([Airflow UI](https://airflow.apache.org/docs/apache-airflow/stable/ui.html)). NN/g's status-tracker guidance says to "state exactly what the wait time will be" where possible ([NN/g: status trackers](https://www.nngroup.com/articles/status-tracker-progress-update/)). Write "review · 52 min (usually 10–20)", taking the typical time from earlier Command logs. That is text, not a chart. +- **Open failures by default; fold the rest.** GitHub expands failed steps automatically ([GitHub: workflow run logs](https://docs.github.com/en/actions/how-tos/monitor-workflows/use-workflow-run-logs)). Buildkite has `^^^ +++` to reopen the group that failed ([Buildkite: log output](https://buildkite.com/docs/pipelines/configure/managing-log-output)). The prototypes now fold everything, so make an exception for the failing tool call and for where a died Run stopped. +- **No more than two disclosure levels.** NN/g: "designs that go beyond 2 disclosure levels typically have low usability because users often get lost" ([NN/g: progressive disclosure](https://www.nngroup.com/articles/progressive-disclosure/)). The drill-down added today goes Command → Spec run → Ticket → details: four levels. Flatten it by showing Tickets inline as status chips under the Command, so one unfold reaches the details. +- **Say what Stop keeps.** Copilot's Stop session "preserves any commits already pushed" ([GitHub Copilot: manage agents](https://docs.github.com/en/copilot/how-tos/copilot-on-github/use-copilot-agents/manage-and-track-agents)). Argo separates `stop`, which lets exit handlers run, from `terminate`, which doesn't ([argo stop](https://github.com/argoproj/argo-workflows/blob/main/docs/cli/argo_stop.md), [argo terminate](https://argo-workflows.readthedocs.io/en/latest/cli/argo_terminate/)). thirdshift's interruption is the gentle kind: Failed run salvage, confirmed Self-merge completion, Claim ending and Spec accounting still finish ([CONTEXT.md: Command](../../CONTEXT.md)). The confirm step should say so. +- **New variant concepts the research points to:** + - **Trace waterfall:** one Command as nested spans down to tool calls, with a critical path. + - **Stage grid:** the Airflow-style stages × recent Runs table of durations. + - **Parcel tracker:** one Run at a time as a plain-language, phone-first status tracker. + +## 1. CI/CD run views + +### 1.1 GitHub Actions + +- **Run graph.** Each run gets a "real-time" graph of its jobs, with lines for dependencies and a status icon for each job. Clicking a job opens its log ([GitHub: visualization graph](https://docs.github.com/en/actions/how-tos/monitor-workflows/use-the-visualization-graph)). + - *thirdshift:* the Pickup → Spec run → Ticket tree, with "waiting on #239" edges. The Spec run's Tickets checklist already holds the "blocked by" links. Fits the rules: it is read-only. +- **Logs.** + - "Any failed steps are automatically expanded." + - Each step shows how long it took. + - A line number gives a shareable link to that line. + - **Search logs** searches only expanded steps. + - **Download log archive.** + - The CLI equivalents are `gh run view --log` and `--log-failed`. + + Source: [GitHub: workflow run logs](https://docs.github.com/en/actions/how-tos/monitor-workflows/use-workflow-run-logs). + - *thirdshift:* auto-open what failed, give each Session log line an anchor, and add a search box. The page/CLI parity rule is met because the Session log files are on disk and grep-able. +- **Groups and annotations.** `::group::` "Creates an expandable group in the log." `::error` / `::warning` / `::notice` create annotations that can point at a file and line ([GitHub: workflow commands](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-commands)). Job summaries, Markdown written to `GITHUB_STEP_SUMMARY`, show on the run's summary page so that "someone viewing the result of a workflow run doesn't need to go into the logs to see important information" (same page). + - *thirdshift:* this is the case for a **Run summary** at the end of each Run: PR, outcome, cause, Unaddressed findings count, tokens. All of it is already in the Command log or the pull request body, so a Run summary is display only. +- **Cancel.** **Cancel workflow** is a single click with no confirm step, according to the docs ([GitHub: cancel a run](https://docs.github.com/en/actions/how-tos/manage-workflow-runs/cancel-a-workflow-run)). The cancellation sequence re-evaluates `if: always()` and `cancelled()` steps, sends SIGINT, then SIGTERM after 7500 ms, then kills the process tree after 2500 ms more. After a 5-minute timeout the server forces the rest ([GitHub: workflow cancellation](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-cancellation)). + - *thirdshift:* "Stopping…" is a real state that can take a while because salvage finishes. Show it, rather than flipping straight to interrupted. +- **Timeouts.** A job's `timeout-minutes` is "the maximum number of minutes to let a job run before GitHub automatically cancels it", 360 by default ([GitHub: workflow syntax](https://docs.github.com/actions/using-workflows/workflow-syntax-for-github-actions)). thirdshift has no automatic stall cancel, and the Console shouldn't add one, because the page does nothing the CLI can't. Showing a threshold is fine. + +### 1.2 Buildkite + +- **Log groups.** + - `---` makes a collapsed group, `+++` an expanded one, and `~~~` a de-emphasised one; consecutive de-emphasised groups "fold into expander rows". + - `^^^ +++` after a failing command reopens the previous group so the failure is visible. + - Search steps through matches, including matches inside folded groups. + - Each line carries a timestamp. + + Source: [Buildkite: managing log output](https://buildkite.com/docs/pipelines/configure/managing-log-output). + - *thirdshift:* the Session log should **de-emphasise** routine groups (reads, greps), not only collapse them, and **reopen the failing group**. Search must reach into folded groups. +- **Annotations.** Markdown blocks on the build page with styles `success`, `info`, `warning` and `error`. A `--context` key updates the same annotation in place, and a priority sets the order ([Buildkite: annotate](https://buildkite.com/docs/agent/v3/cli-annotate)). + - *thirdshift:* a Run's summary and its Security findings are annotations in this sense: one styled block per subject, updated in place. +- **Build page.** + - The sidebar is a hierarchical step list with collapsible groups. Selecting a step opens a docked step panel with **Logs**, **Artifacts** and **Environment** tabs. + - Skipped steps show their reason without opening a log, and retried steps get an attempt selector. + - **Group by state** puts failed steps and "Waiting for input" at the top. + - `f` jumps to the next failure and `j` follows active steps. + - The **Waterfall** view is for timing and "is hidden on mobile". + + Source: [Buildkite: build page](https://buildkite.com/docs/pipelines/build-page). + - *thirdshift:* show the skipped reason inline, as the Architect run already does. The Resume and each Repair are the attempts. Like Buildkite, the waterfall- or lanes-style timing view needn't be the phone view. +- **Waterfall.** Each bar splits into time waiting for an agent, time from assignment to start, and run time. Parallel steps nest under a parent row, and a canceled job is a blank row ([Buildkite: waterfall](https://buildkite.com/docs/pipelines/insights/waterfall)). + - *thirdshift:* the lanes variant is this view. Its bars should separate **waiting** (a Ticket blocked, or a Base fix awaited) from **working**. + +### 1.3 GitLab pipelines + +The pipeline page draws every job, grouped by stage or by `needs` dependencies, and lets you "cancel a running pipeline, retry failed jobs, or delete a pipeline" ([GitLab: pipelines](https://docs.gitlab.com/ci/pipelines/)). Its total running time leaves out queue time and the first runs of retried jobs (same page). For thirdshift, "how long" should be stated as one of two things: time working, or wall clock including waiting. + +## 2. Workflow orchestrators + +- **Temporal Web UI.** + - The Workflow page has history views: **Timeline** ("chronological or reverse-chronological order of events with a summary"), **All**, **Compact** ("a logical grouping of Activities, Signals and Timers") and **JSON**. + - **Pending Activities** gives a summary of active or pending Activity Executions. + - **Call stack** shows "each location where Workflow code is waiting". + - **Relationships** "displays the full hierarchy … with all parent and child nodes displayed in a tree". + - From the UI you can request Cancellation, or Reset and Terminate. + + Source: [Temporal Web UI](https://docs.temporal.io/web-ui). + - *thirdshift:* the **Compact** idea matches the folded tool-call groups. **Where it is waiting** matches "waiting on #239", or "waiting on CI for 4f1c2a9", or Resume. A **Relationships** tree is the Pickup → Spec run → Tickets → Base fix nesting. +- **Heartbeats as stall detection.** "An Activity Heartbeat is a ping from the Worker … Each ping informs the Temporal Service that the Activity Execution is making progress and the Worker has not crashed." "A Heartbeat Timeout is the maximum time between Activity Heartbeats" ([Temporal: detecting Activity failures](https://docs.temporal.io/encyclopedia/detecting-activity-failures)). + - *thirdshift:* the time since the Session log's last event, or the Command log's last line during CI watch, is the heartbeat. A Run whose log still moves is slow; a Run whose log has stopped is suspect; a Command with no process is "died at ". +- **Airflow.** + - The **Grid** view has a row per task and a column per run, coloured by state, with a sidebar of task durations across recent runs to "spot recurring issues or performance trends at a glance". + - **Graph** nodes show duration. + - The Task Instances tab has a "mini Gantt-style timeline" in each row. + - The Dag Run **Details** tab shows "Queued At" beside the start and end times. + + Source: [Airflow UI](https://airflow.apache.org/docs/apache-airflow/stable/ui.html). + - *thirdshift:* a **stage × recent Runs** grid of durations, as text cells, answers "is review always this slow on chart35?". It also gives the "usually" figure in the TL;DR. +- **Dagster.** The run page has a Gantt-style timeline of "how long each asset or op took", plus a log pane that switches between **structured event logs** ("enriched and categorized with metadata") and **raw compute logs** (stdout and stderr, downloadable) ([Dagster webserver](https://dagster.io/docs/guides/operate/webserver)). + - *thirdshift:* the same toggle on a Session log, between folded tool calls and raw JSONL. The Command log is already the raw stderr. +- **Argo Workflows.** `argo stop` stops "allowing all exit handlers to run". `argo terminate` will "immediately stop a workflow and do not run any exit handlers" ([argo stop](https://github.com/argoproj/argo-workflows/blob/main/docs/cli/argo_stop.md), [argo terminate](https://argo-workflows.readthedocs.io/en/latest/cli/argo_terminate/)). + - *thirdshift:* only the gentle stop exists, and the confirm should name what still runs: salvage, Claim ending and Spec accounting ([CONTEXT.md: Command, Failed run](../../CONTEXT.md)). + +## 3. Agent and LLM trace UIs + +- **GitHub Copilot coding agent.** + - The session log shows "Copilot's internal reasoning and the tools it used". + - The session overview lets you "monitor the agent's progress, token usage, and session length". + - **Stop session** "ends the GitHub Actions run and preserves any commits already pushed". + - You can steer mid-session from a prompt box. The steer applies "after it finishes its current tool call" and costs AI credits. + + Source: [GitHub: manage and track agents](https://docs.github.com/en/copilot/how-tos/copilot-on-github/use-copilot-agents/manage-and-track-agents). + - The CLI has `gh agent-task view --log --follow` to stream a session ([GitHub Enterprise: tracking sessions](https://docs.github.com/en/enterprise-cloud@latest/copilot/using-github-copilot/using-copilot-coding-agent-to-work-on-tasks/using-the-copilot-coding-agent-logs)). + - Each session has a 59-minute limit ([GitHub: troubleshoot cloud agent](https://docs.github.com/en/enterprise-cloud@latest/copilot/how-tos/use-copilot-agents/cloud-agent/troubleshoot-cloud-agent)). + - *thirdshift:* **tokens and session length per Session log** are expected. thirdshift already prints "session ended after 26m 2s: 7416316 input tokens (7285760 cached), 20664 output tokens" (as quoted on [thirdshift.app](../../site/index.html)), so the Console can show those numbers. Steering would break the "nothing the CLI can't" rule, since thirdshift has no command for it. Leave it out. +- **Cursor agents.** + - Status is `ACTIVE` ("a turn is running, waiting on background work, or about to start") or `IDLE` ("the last turn finished and follow-ups are accepted") ([Cursor Cloud Agents API](https://cursor.com/docs/cloud-agent/api/endpoints)). + - Stop "stops Agent mid-task" ([Cursor: Agent mode](https://cursor.com/help/ai-features/agent)). + - Stopping a subagent also stops its nested subagents ([Cursor release notes](https://cursor.com/docs/release-notes)). + - *thirdshift:* "waiting on background work" is exactly when a **Resume** is needed ([CONTEXT.md: Resume](../../CONTEXT.md)), so show background tasks still running in a session. Stopping the Pickup run stops its children, and the confirm step should list them. +- **Devin.** + - The Progress tab collects shell commands, edits and browser activity into one view, and any step opens to its details ([Devin session tools](https://docs.devin.ai/work-with-devin/devin-session-tools)). + - **Session Insights** draws a colour-coded timeline of "where Devin made progress, where it hit obstacles, and how it recovered" ([Devin Session Insights](https://docs.devin.ai/product-guides/session-insights)). + - Idle sessions sleep after 30 minutes by default ([Devin usage](https://docs.devin.ai/admin/billing/usage)). + - *thirdshift:* Repairs, Resumes, Check re-runs and upstream moves are the "obstacles and recoveries" of a Run. A history entry could list them in order: "CI red → Repair 1 → green". +- **Langfuse.** + - The **timeline** view helps "identify latency bottlenecks, visualize parallelism, and understand multi-step reasoning in deeply nested chains" ([Langfuse: timeline view](https://langfuse.com/changelog/2024-06-12-timeline-view)). A 2026 update fits any trace on one screen, with zoom, pan and focus ([Langfuse: responsive timeline](https://langfuse.com/changelog/2026-08-28-responsive-timeline)). + - **Agent graphs** come in two modes. **Aggregated** has one node per step name with a counter, "for grasping structure & complexity at a glance". **Expanded** has one node per call, "to walk through a single run" ([Langfuse: agent graphs](https://langfuse.com/docs/observability/features/agent-graphs)). + - *thirdshift:* the folded tool-call group is the Aggregated mode ("6 tool calls · Bash ×3, Read, Edit ×2"). Unfolding it is the Expanded mode. Show counts per tool in the summary. +- **LangSmith.** The trace tree shows token usage and cost for the whole trace, an aggregate for each parent run, and a breakdown for each child run ([LangSmith: cost tracking](https://docs.langchain.com/langsmith/cost-tracking)). The Details view shows inputs, outputs, timing, token counts and errors for one run ([LangSmith: view traces](https://docs.langchain.com/langsmith/view-traces)). + - *thirdshift:* add up tokens from Ticket Run to Spec run to Command. The Run notification already collects Model evidence per Command ([CONTEXT.md: Run notification](../../CONTEXT.md)). +- **Codex cloud.** When a task finishes it shows "its answer and a diff of any files it changed". `codex apply` applies the latest diff locally ([Codex Cloud (Legacy)](https://developers.openai.com/codex/cloud/environments)). Task cancelling was added in June 2025 ([Codex changelog](https://developers.openai.com/codex/changelog)). + - *thirdshift:* the Run summary could include a diffstat ("3 files, +14 −21"), which can be read from git. + +## 4. Trace timelines + +- **Critical path.** Jaeger highlights "which operations are on the critical path of the overall trace duration", on by default ([Jaeger UI](https://www.jaegertracing.io/docs/latest/frontend-ui/)). In Grafana, the darker segment of each span bar marks the critical path, and the switch "helps identify performance bottlenecks and their impact on overall latency" ([Grafana traces panel](https://grafana.com/docs/grafana/latest/panels-visualizations/visualizations/traces/), [Grafana trace view](https://grafana.com/docs/grafana/latest/explore/trace-integration/)). + - *thirdshift:* in a **Spec run**, the critical path is the chain of blocking Tickets that decides when the Spec PR can start: #239 → #240 → Spec review. Marking it answers "what is the Spec run waiting on?". +- **Minimap and collapse.** Grafana's trace view has a minimap you drag to zoom the timeline, and an **Expand children** control that "expands or collapses all the children spans of the selected span" ([Grafana trace view](https://grafana.com/docs/grafana/latest/explore/trace-integration/)). + - *thirdshift:* "Unfold all" and "Fold all" controls belong with the drill-down. + +## 5. Principles for what earns attention + +- **Symptoms first.** Monitoring answers "what's broken" (the symptom) and "why" (the cause). Paging should follow symptoms, and causes are mostly debugging aids ([SRE: Monitoring](https://sre.google/sre-book/monitoring-distributed-systems/)). For the Console, the symptoms are "a Run has been silent for 30 min", "a process died", "a Claim is waiting on the Day shift". The causes, such as a Repair or a flaky check, sit one fold down. +- **Actionable, not robotic.** "Every page should be actionable … If a page merely merits a robotic response, it shouldn't be a page." Dashboards "should answer basic questions about your service", and the chapter warns against too many alerts, metrics and dashboards (same chapter). Alert fatigue makes "serious alerts … treated with less attention than necessary", and the aim is close to one alert per incident ([SRE: Being on-call](https://sre.google/sre-book/being-on-call/)). + - *thirdshift:* one problem gets one "needs you" item. A failed Spec run with two failed Tickets is one item, not three. +- **Report a stall; don't act on it.** Kubernetes "takes no action on a stalled Deployment other than to report a status condition" ([Kubernetes Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)). Same for the Console: it marks a stall and offers Stop. It never stops anything by itself. + +## 6. UX guidance + +- **Progressive disclosure.** It "defers advanced or rarely used features to a secondary screen". What shows first signals importance. Beyond two levels, "users often get lost" ([NN/g: progressive disclosure](https://www.nngroup.com/articles/progressive-disclosure/)). +- **Dashboards.** They give "at-a-glance information on which users can act quickly". Position and length read best. Colour "should only be used to reinforce information that is already communicated in a different way" ([NN/g: dashboards](https://www.nngroup.com/articles/dashboards-preattentive/)). + - *thirdshift:* every coloured or drawn state needs words next to it. This bears on the garden and pixel sprites, and on lanes' amber and red. +- **Status trackers.** + - "Present the latest update prominently", in plain language, "free from jargon". + - Keep earlier updates with their dates. + - State expected waits. + - Long silences make users "think perhaps something went wrong". + + Source: [NN/g: status trackers](https://www.nngroup.com/articles/status-tracker-progress-update/). +- **Status tags.** + - Use adjectives, not verbs. + - "Do not use colour alone." + - "Do not make a tag interactive." + - Each extra status is harder to remember. + + Source: [GOV.UK tag](https://design-system.service.gov.uk/components/tag/). + - The GOV.UK task list adds **"Cannot start yet"**, in grey text with no link, for a task that depends on another ([GOV.UK: complete multiple tasks](https://design-system.service.gov.uk/patterns/complete-multiple-tasks/)). That is the "waiting on #239" Ticket. +- **List-detail on phones.** "In small windows, only one pane is visible at a time." Back returns to the list ([Android: list-detail](https://developer.android.com/develop/ui/compose/layouts/adaptive/list-detail)). The `accent` variant already works this way. + +## 7. Ranked features for the Console prototypes + +| # | Feature | Answers | Sources | Fits / contradicts | +|---|---|---|---|---| +| 1 | **"Needs you" strip above everything**: died, silent too long, failed with cause, findings waiting, needs-triage. One item per problem. | "Do I have to do anything?" | SRE monitoring and on-call; Buildkite group-by-state | `briefing` is built on it. Add a strip to `plain`, `accent`, `garden`, `press`, `pixel` and `lanes` without reordering the settled live-then-history body. | +| 2 | **Heartbeat age**: "last event 40 s ago" beside stage · age. Flag a stall on silence, not stage length. | "Slow or stuck?" | Temporal heartbeats; Kubernetes progress deadline | All variants. Changes the stall rule in `lanes`, `press`, `pixel`, `briefing` and `accent`, which today flag stage age past 45 min. | +| 3 | **"Usually" durations** from earlier Command logs: "review · 52 min (usually 10–20)". | "Is this abnormal for this repo?" | Airflow durations across runs; NN/g status trackers | Text only, so no chart. Fits all; best in `lanes` as a ghost bar and in `briefing` sentences. | +| 4 | **Failures open by default** in Session and Command logs: the failing tool call, the last group before a death, the error line. | "What went wrong?" without hunting | GitHub auto-expand; Buildkite `^^^ +++` | Amends today's "everything starts folded" in every variant. | +| 5 | **Two disclosure levels at most**: Tickets as inline chips (state + age) under their Command, so one unfold reaches details. | "Where is each Ticket?" at a glance | NN/g progressive disclosure | Flattens the four-level drill-down in `lanes`, `plain` and `garden`. | +| 6 | **Run summary card** for each ended Run: PR, outcome, cause, Unaddressed findings, Repairs/Resumes, diffstat, tokens. | "What came of it?" without logs | GitHub job summaries; Buildkite annotations; Codex diff | History in every variant; `press` proof cards and `garden` harvest log suit it best. | +| 7 | **Tokens and session length** per Session log, added up to Spec run and Command. Numbers, not charts. | "What did this cost?" | Copilot session overview; LangSmith trace tree | All. thirdshift already prints these at session end. | +| 8 | **Stop confirm says what continues**: pushed work kept; salvage, Claim ending and Spec accounting finish; child Runs listed; "Stopping…" state until the process ends. | "What happens if I press this?" | Copilot Stop; Argo stop vs terminate; GitHub cancellation; Cursor nested stop | All. Edit each confirm. | +| 9 | **Session log search, line anchors, structured/raw toggle.** | "Find the error; send someone the line" | GitHub logs; Buildkite search; Dagster toggle | All log views. A raw JSONL download is CLI parity. | +| 10 | **De-emphasised routine groups**: reads and greps quieter than edits, Bash failures and commits. Group summary counts per tool. | "What did it actually do?" | Buildkite `~~~`; Langfuse aggregated mode | All `.sl-*` styles. | +| 11 | **Follow live with a "N new lines ↓" pill** instead of silent auto-scroll. | "Is it still moving?" while reading old lines | Buildkite follow `j`; Copilot live logs | All log views. | +| 12 | **Critical path in a Spec run**: mark the blocking chain that gates the Spec PR. | "What is the Spec run waiting on?" | Jaeger and Grafana critical path; GitHub run graph | `lanes`, `press`, `accent`, `briefing`. | +| 13 | **Attempts and recoveries in order**: implement → CI red → Repair 1 → Check re-run → green. | "How hard was this Run?" | Devin Session Insights; Buildkite attempts | History in all variants; `lanes` and `press` as markers on the line. | +| 14 | **Waiting is not working**: draw or label blocked time (Ticket waiting, Base fix awaited, CI queue) apart from session time. | "Why did it take 3 h?" | Buildkite waterfall segments; GitLab running time | `lanes` (hatch exists), `press` (feeder). | +| 15 | **Words beside every colour and sprite.** Status tags are adjectives and not links; "Cannot start yet" for blocked Tickets. | Accessibility; glanceability | GOV.UK tag and task list; NN/g dashboards | Check `pixel`, `garden` and `lanes` (amber and red alone today). | + +## 8. New variant concepts the research points to + +1. **Trace waterfall: one Command, top to bottom.** Jaeger, Grafana, Langfuse and the Dagster run page all show a single execution as nested bars on a shared time axis. Choose a Command, and every **Session**, **Repair**, **Resume**, CI watch and **Base fix** becomes a span, with tool-call groups as child spans you can expand. A minimap scrubs the time range. The **critical path** is drawn darker, and silent gaps (no heartbeat) are hatched. `lanes` shows every Command against the wall clock; this shows one Command in depth, from Run down to tool call. It replaces the separate Session log panel with spans you can open in place. On a phone it degrades to the span list, without the bars, as Buildkite hides its waterfall on mobile. +2. **Stage grid: is this normal?** This is the Airflow Grid applied to thirdshift. Rows are the stages (implement, review, Delivery, CI watch, Repair, Self-merge, cleanup) and columns are the last 10–20 Runs on this machine, newest on the left. The live ones are pinned and outlined. Each cell is a coloured state with the duration as text ("14m"), so it stays a table, not a chart. Repairs and Resumes add a dot. A live cell more than twice its row's usual time is flagged. It answers "is review always slow on chart35?" and "did CI watch get slower this week?", questions no current variant can. Live-first holds because the live columns come first. On a phone the grid transposes into one Run per card, each card a list of stage durations. +3. **Parcel tracker: one Run, plain-language updates.** This follows NN/g's status-tracker guidance and GOV.UK's task list. Each Run is a tracking page: the latest update in a large sentence ("Reviewing its own change. Last activity 40 s ago; review usually takes 10–20 min here"), then a dated history of updates ("09:46 Tests passed · 09:31 Started review · 08:46 Started"), then what happens next ("Then Delivery: push, mark ready, watch CI"). Tickets that are blocked read "Cannot start yet: waiting on chart35#239". The home page is a short list of trackers, with "needs you" items first. It's built for the phone and one-handed reading, and differs from `briefing`, which summarises the whole machine rather than tracking one Run. + +## 9. Revisions to existing variants + +- **All variants.** + - Add the "needs you" strip (#1) and heartbeat ages (#2). + - Change the stall rule from stage age to silence. + - Open failures by default (#4). + - Show tokens and session length (#7). + - Extend the Stop confirm (#8). + - Add a "N new lines ↓" pill (#11). + - Make routine tool groups quieter (#10). +- **`lanes`.** + - Flatten the drill-down: Ticket chips on the Spec run lane (#5). + - Draw a "usually" ghost bar behind the current stage (#3). + - Mark the critical path (#12). + - Add Repair markers on bars (#13). + - On phones, consider showing the list instead of the axis, following Buildkite. +- **`plain`.** Show Tickets as inline chips under the Spec run row (#5). Add a Run summary line to each history row (#6). +- **`accent`.** Already list-detail, as Android recommends. Add tokens, attempts and the critical path to the detail pane (#7, #12, #13). Make the stepper show "usually" times (#3). +- **`garden` and `pixel`.** Pair every sprite state with words (#15). Base the stall bubble on silence (#2). Turn harvest or ledger entries into Run summary cards (#6). +- **`press`.** Make the misprint box show the last heartbeat and the last failing tool call open (#2, #4). Give the delivery pile's proof cards Run summaries (#6). Keep the feeder for waiting time (#14). +- **`briefing`.** Already closest to the SRE guidance. Add "usually" times and heartbeat ages to its sentences (#2, #3). Collapse a failed Spec run's Tickets into one item (one problem, one item). diff --git a/docs/research/focus-theme-attention.md b/docs/research/focus-theme-attention.md new file mode 100644 index 000000000..b937b209b --- /dev/null +++ b/docs/research/focus-theme-attention.md @@ -0,0 +1,161 @@ +# Improving the Focus theme: shaping attention to where it is most needed + +Research date: 2026-10-19, for issue #711 (the Console) and the themed `console` prototype in `.scratch/prototypes/711-console/` (kept on the branch `prototype/711-console`, commit `05b1b0a`). It builds on [console-run-monitoring-ui.md](console-run-monitoring-ui.md) (what earns attention; silence, not stage age, as the stall rule) and [software-factory-console-trends.md](software-factory-console-trends.md) (attention-state grouping), and doesn't repeat them. + +**Question.** The Focus theme (`themes.js`: `focusLight`, `focusDark`, `focusAuto`; `variants/console.css`: the `focus` effect block) sets visual weight by how much an item needs the Day shift: + +- urgent rows get a crimson 6px edge, a 9% tinted band and bold text; +- look rows get a 3px amber edge; +- healthy groups recede to the dim text colour; +- healthy timeline bars desaturate. + +How could it better steer attention to what needs a decision, in light and dark, while staying calm and accessible, and within the Console's rules? Those rules are: nothing the CLI can't do; motion only for thirdshift's activity; phone first; words beside colour. + +**Method.** + +- **Primary sources, cited inline:** + - Christopher Healey's pre-attentive processing survey (his own pages); + - the W3C's WCAG 2.2 Understanding documents; + - the APCA project's own documentation; + - Google's SRE book and Material dark-theme codelab; + - Nielsen Norman Group; + - PagerDuty, Grafana and Datadog docs. +- **Paywalled standards.** ISA-101 (high-performance HMI) and ISA-18.2 / EEMUA 191 (alarm management) are paywalled. I used the publisher's own overview, plus vendor summaries that name the standard: Emerson/Movicon for ISA-101, ABB for EEMUA 191. Figures found only in secondary write-ups are marked **[unverified]**. +- **Measured contrast.** Every current Focus colour pair was measured with both the WCAG 2 ratio and APCA Lc, using the APCA-W3 0.0.98G constants in a small script. The numbers are in §1. +- **Out of scope.** + - The page layout itself (the inbox structure is settled). + - Other themes, except where the `focus` effect is reused on them. + - Anything that writes to thirdshift: there is no acknowledge or shelve command in the CLI. + +## TL;DR + +- **Fix dark mode's inverted hierarchy first.** In Focus dark, receded "dim" text has *more* perceived contrast than urgent text: APCA Lc −50.6 against −48.8, because saturated red is dark ([APCA in a Nutshell](https://git.apcacontrast.com/documentation/APCA_in_a_Nutshell)). Saturated reds also "vibrate" on dark grounds ([Google codelab](https://codelabs.developers.google.com/codelabs/design-material-darktheme)). Lighten urgent text to a tint (#FFB0B5, Lc −70.9) and keep dim where it is. +- **Make the amber edge pass 1.4.11.** In Focus light, the look edge is #E08A00, which is 2.5:1 against the background. As a state indicator it needs 3:1 ([WCAG 1.4.11](https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html)). Use #B06800 (4.06:1). +- **Recede further in light.** Light dim reads at Lc 80.9, nearly level with urgent text (76.8). Darken urgent text to #9A1424 (Lc 82.3) and lighten dim to #6B6B70 (Lc 71.5, WCAG 4.94). Recede by colour plus weight, never by size or opacity ([NN/g](https://www.nngroup.com/articles/visual-hierarchy-ux-definition/)). +- **Take hue off healthy states.** Grey-scale the healthy states (working, landing, ready, done) in Focus. That leaves hue as the one feature urgent and look rows own, so they pop out pre-attentively rather than by search ([Healey](https://www.csc2.ncsu.edu/faculty/healey/PP/)). It's also what high-performance HMIs do: grey baseline, colour "to indicate the abnormal, rather than normal operations" ([Emerson/Movicon on ISA-101](https://resources.ipd.com.au/documents/white-papers/Best-practices-for-high-performance-HMI-design_White%20Paper_ENUS_2023.pdf)). +- **Add time without motion.** Two static escalation steps by silence or age, each with words: "silent 14 min" against "silent 45 min, past 30". This follows Grafana-style thresholds ([Grafana](https://grafana.com/docs/grafana/latest/panels-visualizations/configure-thresholds/)) and PagerDuty's raising of urgency when a condition persists ([PagerDuty](https://support.pagerduty.com/main/docs/configurable-service-settings)). +- **Plan for floods.** Past about seven Needs-you items, show a one-line summary by kind and fold the rest behind "N more". Alarm guidance treats floods as the failure mode, and keeps high priority rare: about 5% high, 15% medium, 80% low ([ABB summary of EEMUA 191](https://library.e.abb.com/public/3fe0e33c700746d0bcf700526ba81c62/3BDD017132_en_3BDD017132_EN_Alarmmanagement_Check.pdf)). +- **Stop pulses after a few cycles.** The silent alarm loops indefinitely, which WCAG 2.2.2 says needs a pause mechanism after 5 seconds ([WCAG 2.2.2](https://www.w3.org/WAI/WCAG22/Understanding/pause-stop-hide.html)). Run it 3 times when a row turns silent, then hold a strong static state. The activity motion (spinner, belt) also needs a visible pause; the theme editor's motion setting is too buried. +- **No shelving or acknowledging.** These need a write the CLI can't do. A per-viewer "new since you last looked" marker, read-only and kept in the browser, is legitimate. It should add emphasis to what's new, never hide what isn't. + +## 1. What Focus does today, measured + +Light bg #F7F7F5 and dark bg #121214. WCAG 2 contrast ratio and APCA Lc (APCA-W3 0.0.98G). APCA Lc is signed: negative for light text on a dark ground. + +| Pair | Light WCAG | Light Lc | Dark WCAG | Dark Lc | +|---|---|---|---|---| +| text | 16.53 | 99.7 | 15.29 | −92.4 | +| dim (receded rows) | 6.91 | **80.9** | 7.21 | **−50.6** | +| urgentText | 6.37 | 76.8 | 6.79 | **−48.8** | +| lookText | 6.70 | 79.7 | 10.60 | −70.0 | +| urgent edge/fill | 4.62 | 67.6 | 5.77 | −42.7 | +| look edge/fill | **2.51** | 46.9 | 10.23 | −68.1 | +| rule | 1.20 | 9.3 | 1.35 | ~0 | + +What the table shows: + +- **Every text pair passes WCAG 1.4.3.** But WCAG ratios aren't perceptually uniform: they overstate contrast for dark colours ([APCA in a Nutshell](https://git.apcacontrast.com/documentation/APCA_in_a_Nutshell)). In APCA terms the hierarchy is wrong in both modes: + - in dark, receded text out-contrasts urgent text (−50.6 against −48.8), and look text (−70) out-shouts urgent; + - in light, receded text (80.9) is a hair below urgent (76.8) and look (79.7). The difference rests on bold weight and the band alone. +- **The light look edge fails 1.4.11.** WCAG 1.4.11 needs 3:1 for "visual information necessary to indicate state" ([WCAG 1.4.11](https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html)). The amber look edge at 2.51:1 fails as the row's state cue. The word next to it saves 1.4.1, but not 1.4.11. +- **Rules fall below APCA's floor.** Rules are under Lc 15, which APCA treats as invisible ([APCA](https://git.apcacontrast.com/documentation/APCA_in_a_Nutshell)). That's fine for decoration, but don't rely on them to separate groups in Focus. Use spacing. + +## 2. Salience: what pops out without searching + +- **One unique feature pops out; combinations don't.** A target with one unique visual property "pop[s] out", while a target defined by a combination of features ("conjunction target") "normally cannot be detected preattentively" and needs serial search ([Healey, Perception in Visualization](https://www.csc2.ncsu.edu/faculty/healey/PP/)). Colour (hue) and intensity are both pre-attentive features (same source). +- **Hue dominates when others use it too.** The visual system "favours colour over shape" for boundary detection, and colour variation interferes with other features ([Healey](https://www.csc2.ncsu.edu/faculty/healey/PP/)). +- **Implication for Focus:** + - Urgent should be the only thing on screen with a saturated warm hue *and* a filled band. + - Look should be the only thing with a thin warm edge. + - Healthy rows should carry no hue at all. +- **Today's healthy colours compete.** Healthy rows still show slate (#6B7A8F) and sage (#5F7F6B) tags. Those are low-chroma hues, but hues nonetheless. They give the eye extra coloured targets, which weakens urgent's single-feature pop-out. +- **Change blindness.** Changes during an interruption or a glance away are missed, "not a failure to see because of limited visual acuity" ([Healey](https://www.csc2.ncsu.edu/faculty/healey/PP/)). When a row newly becomes urgent between visits, its arrival can go unseen. That's an argument for a "new since you last looked" marker (§7) rather than relying on the reader noticing. + +## 3. Alarm-management lessons: rare, ranked, floods handled + +- **Grey baseline, colour for the abnormal.** High-performance HMI practice, as summarised by a vendor citing ISA-101, says "the background color should be light gray". It says foreground colours are "used sparingly to indicate abnormal situations". It also says "color should be removed from graphics in favor of grayscale and then used to indicate the abnormal, rather than normal operations" ([Emerson/Movicon white paper on ISA-101](https://resources.ipd.com.au/documents/white-papers/Best-practices-for-high-performance-HMI-design_White%20Paper_ENUS_2023.pdf)). The same paper warns that "overuse of red or green in everyday graphics to indicate running/not running can make it hard to see abnormal events". It adds that alarms "should be shown in multiple ways, with different colors, shapes and text". ISA's own page for ISA-101 confirms only its scope ("human-centered design, effective display structures"), not these specifics ([ISA](https://www.isa.org/standards-and-publications/isa-standards/isa-101-standards)). +- **Keep high priority rare.** An ABB summary of EEMUA 191 gives "5% as high, 15% as medium, and 80% as low". It also says fewer than ten alarms should arrive "within the first 10 minutes of a major system failure" ([ABB](https://library.e.abb.com/public/3fe0e33c700746d0bcf700526ba81c62/3BDD017132_en_3BDD017132_EN_Alarmmanagement_Check.pdf)). The ISA-18.2 flood threshold of "more than 10 alarms in 10 minutes per operator" appears only in secondary write-ups, such as [TiPS](https://tipsweb.com/taming-alarm-floods/) **[unverified]**. +- **For thirdshift:** + - Focus should have three levels, no more: urgent (high), look (medium), and everything else (no alarm). + - The page should handle the case where Needs you grows long. On a bad night, a broken Base branch can fail every Pickup run. +- **Shelving doesn't fit.** Alarm systems let operators shelve a nuisance alarm, with a time-out and an audit trail. The Console can't, because the CLI has no such command. See §7 for what is legitimate. + +## 4. Attention economics + +- **Pages must be actionable.** Every page should be actionable, and "when pages occur too frequently, employees second-guess, skim, or even ignore incoming alerts" ([Google SRE, Monitoring Distributed Systems](https://sre.google/sre-book/monitoring-distributed-systems/)). Focus's urgent level should therefore be reserved for things only a human can resolve: died, silent, failed, and Security findings that wait. That's what `needsYou()` already marks urgent. Slow-but-moving stays "look". +- **Limit the levels of emphasis.** NN/g: "If everything is contrasted, then nothing stands out". Use "no more than 3 contrast variations for complex designs" and no more than three sizes. Hierarchy shouldn't rely on colour alone ([NN/g, Visual Hierarchy](https://www.nngroup.com/articles/visual-hierarchy-ux-definition/)). Focus today has four emphasis treatments (band, edge, bold, dim); keep it to three contrast steps. +- **Rank by urgency and fold the rest.** + - PagerDuty separates high urgency ("requires immediate attention") from low ("can wait"), with different notification behaviour for each. Services can "raise urgency of unacknowledged incidents to high when support hours start" ([PagerDuty: configurable service settings](https://support.pagerduty.com/main/docs/configurable-service-settings); [notification rules](https://support.pagerduty.com/main/docs/notification-rules)). + - Datadog gives monitors a priority from P1 to P5 that the monitor data carries ([Datadog DDSQL: monitor groups](https://docs.datadoghq.com/ddsql_reference/data_directory/dd/dd.monitor_groups.dataset/)). + - Grafana colours by discrete thresholds above a base value ([Grafana thresholds](https://grafana.com/docs/grafana/latest/panels-visualizations/configure-thresholds/)). + - The common pattern is a small, ranked set of levels, with a level that can rise as a condition persists. Nothing flickers. + +## 5. Dark mode + +- **The inversion.** The hierarchy inverts in dark (§1). Saturated colours "tend to visually 'vibrate' against darker backgrounds, making them harder to read", and lighter tonal variants keep the palette expressive ([Google: Design a dark theme with Material](https://codelabs.developers.google.com/codelabs/design-material-darktheme)). +- **The fix: raise urgent, keep receded where it is.** + + | Token | Now | Proposed | WCAG | Lc | + |---|---|---|---|---| + | urgentText | #FF6B78 | #FFB0B5 (a light tint) | 10.81 | −70.9 | + | urgent edge | — | keep saturated #FF6B78 | 6.79 | — | + | dim | #A0A0A8 | unchanged | — | −50.6 (≥ Lc 45, so receded rows stay readable) | + + Receding by darkening dim instead (#85858D, Lc −36.9) would push healthy text below APCA's Lc 45 floor for text ([APCA](https://git.apcacontrast.com/documentation/APCA_in_a_Nutshell)), so don't. +- **Band.** The 9% band on #121214 gives #27171B. Urgent text on it is fine (WCAG 6.2). A 12% band reads more clearly as a region in dark without vibrating, since it's a large low-chroma area **[unverified, judgement]**. +- **Surface.** Material uses #121212 as the base dark surface (same codelab), and Focus's #121214 already matches. + +## 6. Time without motion + +- **Static escalation steps.** Focus currently treats a 14-minute silence and a 3-hour silence the same. Add two static steps, Grafana-threshold style, each with words (WCAG 1.4.1 needs a non-colour cue ([WCAG 1.4.1](https://www.w3.org/WAI/WCAG22/Understanding/use-of-color.html))): + - **Silent:** 10–30 min is "silent N min"; over 30 min is "silent N min · past 30". The latter gets a doubled edge (6px to 10px), and its age in bold. + - **Look, slow:** over usual hi is "slower than usual". Over 2× usual it says "2× usual", and the age is bold. + - **Died:** it stays at the top level; age only orders it. + + It's the same idea as PagerDuty raising urgency when a condition persists, without a notification. +- **Order by escalation.** Within Needs you, sort urgent by escalation step, then by age, so the longest-silent item is first. +- **The alarm pulse.** WCAG 2.2.2 requires a way to pause, stop or hide motion that starts automatically and "lasts more than five seconds" ([WCAG 2.2.2](https://www.w3.org/WAI/WCAG22/Understanding/pause-stop-hide.html)). Today's silent pulse is infinite, so: + - set `animation-iteration-count: 3` when a row enters the silent state (keyed by a class added once, not on every render); + - then hold the static past-threshold treatment. +- **Activity motion.** The Working spinner, belt and heartbeat also auto-start and last beyond 5s. Add a visible one-click "Pause motion" control in the header, or move the theme editor's motion level onto the Theme button's panel. `prefers-reduced-motion` already covers the OS setting ([WCAG 2.3.3, technique C39](https://www.w3.org/WAI/WCAG22/Understanding/animation-from-interactions.html)). + +## 7. Floods, "seen", and what's legitimate + +- **Floods.** When Needs you has more than 7 items (the prototype has 7 today): + - Show a summary line under the heading, e.g. "4 failed · 2 silent · 1 died · 3 look". Each part is a filter chip. + - List urgent items first, up to 7 rows, then fold the rest behind "N more". + - Look items fold before urgent ones do. + - Group repeated causes: several Runs failing on the same Inherited failure collapse to one row, "CI red on clippy, also failing on main: 4 Runs". That's one problem, one item, as the SRE book argues for symptoms ([Google SRE](https://sre.google/sre-book/monitoring-distributed-systems/)). +- **Acknowledging and shelving are ruled out.** They change shared state, and the CLI has no such command, so the page can't do them. +- **A per-viewer "seen" marker is legitimate.** Keep a last-visit timestamp in the browser (like the theme choice) and mark rows that became urgent or look since then with a small "new" word and dot. It reads nothing thirdshift doesn't already show, writes nothing to thirdshift, and counters change blindness (§2). It must never hide or demote an item. A seen problem is still a problem until thirdshift's state says otherwise. + +## 8. Phone + +- **Needs you leads.** Keep it first and open, and wrap each urgent row's "why" line rather than truncating it. On a phone, the reason is the information. +- **Collapse healthy sections.** Turn them into one line of counts, "Ready 2 · Landing 1 · Working 1 · Done 2", each a tap target to unfold. That keeps the first screen for what needs you. +- **Keep the band and edge, drop the dimming.** On a small screen the band and edge carry well. Make the receded colour switch to normal text when the reader taps into a healthy section, since there's no hover on touch. + +## 9. What to remove + +- **Hue from healthy states in Focus:** working, landing, ready and done go to the grey ramp. Words and glyphs still distinguish them. +- **The glow tokens:** Focus doesn't use glows; leave them neutral to avoid accidental warm halos. +- **The light theme's amber edge colour (#E08A00):** replace it (§1). +- **Infinite alarm loops:** cap them (§6). +- **Any fourth emphasis level:** keep urgent band, look edge, and normal. Bold belongs to urgent only. + +## 10. Recommended changes + +| Change | Reason | Source | How to verify in the prototype | +|---|---|---|---| +| Focus dark `urgentText` #FF6B78 → #FFB0B5; keep the edge #FF6B78 | Urgent text currently has less perceived contrast than receded text (Lc −48.8 vs −50.6); saturated red vibrates on dark | [APCA](https://git.apcacontrast.com/documentation/APCA_in_a_Nutshell); [Google codelab](https://codelabs.developers.google.com/codelabs/design-material-darktheme) | Re-run the contrast script: urgentText Lc ≈ −71 < dim −50.6; squint test on Focus dark, where urgent rows read first | +| Focus light `look` (edge and fill) #E08A00 → #B06800 | State indicator must be ≥ 3:1 (now 2.51:1) | [WCAG 1.4.11](https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html) | Ratio of `--look` to bg ≥ 3:1; the editor's AA check shows ✓ | +| Focus light `urgentText` → #9A1424, `dim` → #6B6B70 | Widen the gap between urgent (Lc 82) and receded (Lc 71.5) while both pass AA | [APCA](https://git.apcacontrast.com/documentation/APCA_in_a_Nutshell); [WCAG 1.4.3](https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html) | Contrast script; receded rows visibly lighter than urgent at a squint | +| Healthy states (working, landing, ready, done) to the grey ramp in Focus only | Hue is the pop-out feature; reserve it for the abnormal | [Healey](https://www.csc2.ncsu.edu/faculty/healey/PP/); [Emerson/Movicon on ISA-101](https://resources.ipd.com.au/documents/white-papers/Best-practices-for-high-performance-HMI-design_White%20Paper_ENUS_2023.pdf) | Ready, Landing and Working rows show no hue; only Needs-you rows carry colour | +| Silent and slow escalate in two static steps with words ("past 30", "2× usual"), with a heavier edge and bold age at step 2 | Time context without motion; a persisting problem should rise | [Grafana thresholds](https://grafana.com/docs/grafana/latest/panels-visualizations/configure-thresholds/); [PagerDuty](https://support.pagerduty.com/main/docs/configurable-service-settings); [WCAG 1.4.1](https://www.w3.org/WAI/WCAG22/Understanding/use-of-color.html) | Set #702's `lastEvent` to `ago(45)` in data.js: its row says "past 30" and has the heavier edge | +| Sort Needs you: urgent by escalation step, then age; then look | The worst first, as alarm lists rank by priority | [ABB summary of EEMUA 191](https://library.e.abb.com/public/3fe0e33c700746d0bcf700526ba81c62/3BDD017132_en_3BDD017132_EN_Alarmmanagement_Check.pdf); [Datadog priority](https://docs.datadoghq.com/ddsql_reference/data_directory/dd/dd.monitor_groups.dataset/) | With the change above, #702 sorts above the 14-minute items | +| Alarm pulse runs 3 times on entering silent, then holds static | Auto-motion over 5s needs a pause | [WCAG 2.2.2](https://www.w3.org/WAI/WCAG22/Understanding/pause-stop-hide.html) | DevTools: `animation-iteration-count: 3` on `.w-silent .gl`; it doesn't restart on j/k | +| A visible "Pause motion" control (header or Theme panel) | Activity motion is also continuous | [WCAG 2.2.2](https://www.w3.org/WAI/WCAG22/Understanding/pause-stop-hide.html); [WCAG 2.3.3 / C39](https://www.w3.org/WAI/WCAG22/Understanding/animation-from-interactions.html) | Toggling it stops the spinner, belt and heartbeat; the choice persists per browser | +| Over 7 Needs-you items: a summary line by kind, then "N more"; group the same cause | Floods bury the important; one problem, one item | [ABB/EEMUA](https://library.e.abb.com/public/3fe0e33c700746d0bcf700526ba81c62/3BDD017132_en_3BDD017132_EN_Alarmmanagement_Check.pdf); [Google SRE](https://sre.google/sre-book/monitoring-distributed-systems/); ISA-18.2 flood threshold **[unverified]** | Add 10 failing Commands to data.js: 7 rows show, then "3 more" and a summary line | +| "New since you last looked" word and dot, per browser, never hiding | Counters change blindness without a write to thirdshift | [Healey on change blindness](https://www.csc2.ncsu.edu/faculty/healey/PP/) | Reload with a stored last-visit before c2's silence: #702 shows "new"; nothing is hidden | +| Phone: healthy sections as one count line; urgent "why" lines wrap | The first screen is for what needs you | [NN/g](https://www.nngroup.com/articles/visual-hierarchy-ux-definition/) | phone.html?only=console in Focus: Needs you is fully readable and healthy sections take one line | +| Keep three emphasis levels only (urgent band, look edge, normal); bold only on urgent | "If everything is contrasted, then nothing stands out" | [NN/g](https://www.nngroup.com/articles/visual-hierarchy-ux-definition/) | Audit the CSS: no bold outside urgent rows in Focus | diff --git a/docs/research/software-factory-console-trends.md b/docs/research/software-factory-console-trends.md new file mode 100644 index 000000000..66dfeba93 --- /dev/null +++ b/docs/research/software-factory-console-trends.md @@ -0,0 +1,246 @@ +# Trends in software-factory consoles: how 2025–2026 agent products show many agents at once + +Research date: 2026-10-18, for issue #711 (the Console) and its Q27 UI prototypes in `.scratch/prototypes/711-console/` (kept on the branch `prototype/711-console`, commit `05b1b0a`). It builds on [console-run-monitoring-ui.md](console-run-monitoring-ui.md), which covers CI, orchestrators, trace UIs and the SRE material. This note covers products that run many coding agents unattended. + +**Question.** Products that run many autonomous coding agents in parallel on issues and deliver pull requests now ship their own observation surfaces: mission controls, agent panels, agent views, task boards. In 2025–2026, how do they show many agents at once? How do they show what needs a human, hand work over for review, let you steer or stop it, show logs and transcripts, and report cost? Which trends fit thirdshift's Console? Its constraints: one machine; **Commands**, **Runs**, **Spec runs**, **Tickets** and **Passes**; the page does nothing the CLI can't; phone first; no Start buttons, charts or cross-machine view for now. + +**Method.** + +- Read each vendor's own docs, changelogs and launch posts, and READMEs for open-source tools, cited inline. A claim that rests only on a secondary source, or that no primary page confirmed, is marked **[unverified]**. +- **Vendors:** + - GitHub (Agent HQ, mission control, the Copilot agents panel and page); + - OpenAI (the Codex app, its review pane and automations inbox); + - Cursor (the Agents Window, 3.0 and 3.1); + - Google Jules; + - Devin (session status, Session Insights); + - Claude Code (cloud sessions, agent view, Projects); + - Amp (the Agents Panel); + - Linear (agent sessions, delegation, agent plans); + - Factory (Desktop app, Missions); + - Warp (Agent Management Panel, notifications); + - Replit (Agent task board). +- **Open source:** Vibe Kanban, Claude Squad, Conductor and Sculptor. +- Mapped each trend onto [CONTEXT.md](../../CONTEXT.md) vocabulary and onto the existing variants: `garden`, `plain`, `accent`, `press`, `pressplain`, `pixel`, `briefing`, `briefingwide`, `trace`, `grid`, `lanes`. + +**Out of scope.** + +- **Pricing, model quality and vendor comparison:** only how each product's observation UI is structured is covered. +- **Anything that starts work:** dispatch boxes, plan approval and auto-approve, which thirdshift's Console leaves to the CLI and the scheduler. +- **Two products:** Terragon (no primary docs found) and Sourcegraph's own Amp page (it only points to the manual). + +## TL;DR + +- **The common shape is a list grouped by attention state, not by process state.** Claude Code's agent view groups sessions as Pinned, Ready for review, Needs input, Working and Completed ([agent view](https://code.claude.com/docs/en/agent-view)). Its Projects Overview has Ready for review, Waiting on you, Working, Landing, Idle and Resolved ([Projects](https://code.claude.com/docs/en/claude-projects)). Warp, Devin, Linear and Replit all carry a "blocked on you" state alongside working, failed and done. thirdshift's "live first, then history" order is still a process view. A grouping by what the **Day shift** must do would match the field. +- **Each row is one line: what it's doing now, or the question it's asking.** You "peek" without opening it. Agent view rows show a one-line summary of current activity or the question, and `Space` opens a peek of the latest output ([agent view](https://code.claude.com/docs/en/agent-view)). Amp's `Space` expands a thread's last message ([Amp Agents Panel](https://ampcode.com/news/agents-panel)). +- **Review is the destination, and the row carries its size.** Claude Code shows `+42 -18` on each session ([cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web)). Codex's review pane and inbox, Conductor's review → PR → merge → archive, and Replit's Ready column all end at a diff. thirdshift can show the diffstat, checks and PR link; reviewing happens on GitHub. +- **Coordinator and workers, with milestones and checklists as the unit of progress.** + - Claude Code Projects: a coordinator conversation whose threads "report back". + - Factory Missions: an orchestrator, workers, milestones and validation criteria. + - Linear: agent plans with pending, inProgress, completed and canceled steps. + - Warp: parent and child runs. + + A **Pickup run** → **Spec run** → **Ticket** Runs is the same shape, and the **Tickets checklist** is thirdshift's plan. +- **Attention leaves the page.** Agent view puts "2 awaiting input" in the terminal tab title. Warp has toasts, a mailbox and an attention badge. The Projects Overview button shows a dot. The Codex inbox has unread indicators. A page title count and a favicon dot are read-only and fit; browser notifications are a later question. +- **Spend and session size sit on the row or the overview.** Copilot shows token usage and session length, Factory shows credits in the top bar, and Devin rates sessions XS–XL and flags L and XL as unhealthy ([Session Insights](https://docs.devin.ai/product-guides/session-insights)). +- **Steering mid-run is everywhere, but it's a write the thirdshift CLI doesn't have.** Copilot, Claude Code, Jules and Factory all let you steer a running session. It's ruled out for now; Stop stays the only write, with its CLI hint. +- **New variant:** `inbox`, a keyboard-first, attention-grouped list with a peek pane and tiled live logs. Its brief is in [§5](#5-a-new-variant-inbox). + +## 1. Vendors + +### 1.1 GitHub: Agent HQ, mission control, the agents panel + +- **Mission control:** announced as "a consistent interface across GitHub, VS Code, mobile, and the CLI" to direct, monitor and manage agent tasks. You pick agents, "assign work in parallel" and follow progress from any device. Third-party agents (Anthropic, OpenAI, Google, Cognition, xAI) arrive in the same place ([Agent HQ, 2025-10-28](https://github.blog/news-insights/company-news/welcome-home-agents/)). +- **The how-to post:** mission control is "a unified interface for managing GitHub Copilot coding agent tasks". It replaces "bouncing between pages", and "session logs show reasoning, not just actions". You can stop a drifting agent and restart it with refined instructions ([mission control, 2025-12-01](https://github.blog/ai-and-ml/github-copilot/how-to-orchestrate-agents-using-mission-control/)). +- **The agents panel:** available "from any page on GitHub". It lists your sessions and those others started; repositories have an "All sessions" tab. + - A session opens a log and overview with "progress, token usage, and session length". + - Steering is a prompt box under the log, applied "after it finishes its current tool call", and each steer costs credits. + - **Stop session** ends the run and keeps pushed commits. Sessions can be archived but not deleted. + - ([manage and track agents](https://docs.github.com/en/copilot/how-tos/copilot-on-github/use-copilot-agents/manage-and-track-agents), [track sessions](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/cloud-agent/track-copilot-sessions)) +- **Not documented:** no layout or status names for the list **[unverified]**. + +### 1.2 OpenAI: the Codex app + +- **Launch:** OpenAI framed the app as a command center for overseeing many agents at once, each in its own thread grouped by project, with worktrees isolating changes ([Introducing the Codex app](https://openai.com/index/introducing-the-codex-app/); the page returned 403 to the fetcher, so details are **[unverified]** beyond search snippets). +- **Review pane:** "reflects the state of your Git repository, not just what Codex edited". + - Scopes: Unstaged, Staged, Commit, Branch, Last turn. + - You can stage or revert per file and per hunk, and leave inline comments the agent then addresses. + - The PR sidebar has an inbox (Assigned to me / my team / Authored by me) and Summary and Changes panes, with **Fix** attaching failing checks to a chat ([Codex code review](https://learn.chatgpt.com/docs/code-review?surface=app)). +- **Automations:** "The Scheduled view acts as your inbox", and "an unread indicator shows when a run needs your attention" ([Codex automations](https://learn.chatgpt.com/docs/automations?surface=app)). + +### 1.3 Cursor: the Agents Window + +- **Agents Window:** the 3.0 release (2026-04-02) made it the headline feature, to "run many agents in parallel across repos and environments": local, worktree, cloud and SSH. Chats can be shown "side-by-side or in a grid" ([Cursor 3.0](https://cursor.com/changelog/3-0)). +- **Tiled panes:** 3.1 (2026-04-13) split the view into tiled panes to manage several agents at once ([Cursor 3.1](https://cursor.com/ko/changelog/3-1)). +- **Help page:** you manage every agent from the sidebar. Agents are reachable "from the web, mobile, Slack, GitHub, and Linear", and artifacts like screenshots and demo videos help review "so you don't have to read every line" ([multi-agent help](https://cursor.com/help/ai-features/multi-agent)). + +### 1.4 Google Jules + +- **Plan before code:** "Once the plan is approved, Jules will start coding." +- **Activity feed:** it updates per step with "inline explanations of each change" and "a mini diff preview for each file". **Pause** waits for new instructions ([running tasks](https://jules.google/docs/running-tasks/)). +- **Notifications:** for "when a plan is ready or a task completes" ([FAQ](https://jules.google/docs/faq/)). +- **Planning Critic:** a second agent reviews plans that are auto-approved, credited with "a 9.5% reduction in task failure rates" ([changelog, 2026-01-26](https://jules.google/docs/changelog/2026-01-26-1/)). + +### 1.5 Devin + +- **Session status:** + - `running` carries a `status_detail` of `working`, `waiting_for_user`, `waiting_for_approval` or `finished`. + - `suspended` carries a reason, such as `inactivity`, `usage_limit_exceeded` or `out_of_credits`. + - Sessions also list `pull_requests` with their state, `acus_consumed` and `child_session_ids` ([session API](https://docs.devin.ai/api-reference/v3/sessions/get-organizations-session.md)). +- **Session Insights:** after the fact, an Issue Timeline groups problems "by label and impact level". It also gives actionable feedback, including a rewritten prompt, and a size class XS–XL by ACUs, with L and XL "flagged as unhealthy" ([Session Insights](https://docs.devin.ai/product-guides/session-insights)). + +### 1.6 Claude Code: cloud sessions, agent view, Projects + +- **Cloud sessions:** they sit in the claude.ai/code sidebar. Each shows "a diff indicator with lines added and removed, like `+42 -18`", which opens a diff view with inline comments. + - Follow-ups can be queued from any CLI with `claude -p "…" --cloud `, and Auto-fix watches a PR's CI and review comments. + - Sessions are watched "from anywhere including the Claude mobile app" ([cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web)). +- **Agent view (`claude agents`, research preview):** "a grouped list, not a grid". + - **Groups:** Pinned, **Ready for review**, **Needs input**, **Working**, **Completed**. + - **Rows:** "a one-line summary of its current activity or question", plus its age. "Sessions that need you rise to the top", and the tab title shows "`2 awaiting input`". + - **Peek:** `Space` shows the latest output or the exact question, plus linked PRs, and you can reply in place. + - **Notifications:** sent when a session "needs input, finishes, or fails" ([agent view](https://code.claude.com/docs/en/agent-view)). +- **Projects (public beta):** a coordinator conversation starts parallel threads that "report back". + - The **Overview** pane groups threads as **Ready for review**, **Waiting on you** (including failed), **Working**, **Landing** (approved or queued to merge), **Idle** and **Resolved** (auto after "a week with no activity"). + - The Overview button "shows a dot when a thread is waiting on you" ([Projects](https://code.claude.com/docs/en/claude-projects)). +- **Overview of parallel work:** compares subagents, agent view, agent teams, workflows and projects. `/tasks` and `/workflows` list running work and its phase ([Run agents in parallel](https://code.claude.com/docs/en/agents)). + +### 1.7 Amp + +- **Agents Panel (2026-01-09):** lists all active threads, with `j`/`k` to move, `Space` to expand "its last message or tool result", and `e` to archive, so the panel "shows your current working set" ([Agents Panel](https://ampcode.com/news/agents-panel)). +- **Agent-to-agent:** agents spawn agents that report back to the main thread ([agent-to-agent](https://ampcode.com/docs/orbs/agent-to-agent)). + +### 1.8 Linear + +- **Delegation, not assignment:** assigning an issue to an agent makes it the **delegate**, "so humans maintain ownership while agents act on their behalf" ([agent interaction](https://linear.app/developers/agent-interaction)). +- **Session states:** `pending`, `active`, `error`, `awaitingInput`, `complete` and `stale`. They are derived "based on the last emitted activity", so state comes from the activity stream, not from the agent's say-so. +- **Activity types:** thought, action, elicitation, response and error. +- **Agent plans:** "a session-level checklist of tasks", each step pending, inProgress, completed or canceled, in technology preview (same page). +- **Delegate filter:** delegated issues stay in **My issues** and can be filtered by **Delegate** ([agents in Linear](https://linear.app/docs/agents-in-linear)). + +### 1.9 Factory + +- **Desktop app (2026-04-08):** "each session lives in the sidebar with its own context, progress, and history". Droid Computers get "status, logs, configuration, in one place" ([Factory Desktop](https://factory.com/news/factory-desktop)). +- **Missions:** + - **Top bar:** elapsed time and credits used. + - **Left sidebar:** workers. + - **Main view:** the active milestone, with each feature's validation criteria and commits. + - **Right sidebar:** a live progress log of "every worker and milestone" ([running in the app](https://docs.factory.com/missions/running-app.md)). + - **Human role:** "Missions are not fire-and-forget". You pause the orchestrator and re-plan, and a warning appears when a feature hits its retry limit ([Missions](https://docs.factory.com/missions/overview)). +- **Framing:** the "software factory" phrase isn't on these pages; Factory frames it as Droids across "every part of your software business". + +### 1.10 Warp + +- **Agent Management Panel and Oz Runs page (works on mobile):** + - **Statuses:** **Working**, **Blocked** ("waiting on user input or a required step"), Canceled, Failed and Success. + - **Filters:** by source (interactive, API, CLI, Slack or Linear, scheduled), day, creator and status. + - **Cloud runs:** show their duration. + - **Orchestrated runs:** appear as parent and child runs ([managing agents](https://docs.warp.dev/agents/using-agents/managing-agents)). +- **Notifications:** three kinds, **Complete**, **Request** ("blocked and needs your input") and **Error**. They arrive as toasts, at most two at once, and in a mailbox with All tabs, Unread and Errors filters. Tabs carry "an attention badge" ([agent notifications](https://docs.warp.dev/agents/capabilities/agent-notifications/)). + +### 1.11 Replit + +- **Agent task board columns:** + - **Drafts:** not started. + - **Active:** including Queued, when a task depends on another or hits the limit. + - **Ready:** waiting for your review. + - **Done:** applied, archived or cancelled. +- **Cards:** a status label with time, such as "Active • 12m". +- **Isolation:** each task works in its own copy, and "nothing changes in your main version until you apply the work" ([task board](https://docs.replit.com/references/agent/task-board)). + +### 1.12 Open-source orchestrators + +- **Vibe Kanban:** issues on "a kanban board". Each workspace gets "a branch, a terminal, and a dev server", and inline diff comments go back to the agent. The README now says the project is sunsetting ([BloopAI/vibe-kanban](https://github.com/BloopAI/vibe-kanban)). +- **Claude Squad:** one terminal lists instances. `tab` switches preview and diff; `c` commits and pauses, `r` resumes and `D` kills ([smtg-ai/claude-squad](https://github.com/smtg-ai/claude-squad)). +- **Conductor:** one workspace per task, each its own branch and worktree. You "archive, merge, or discard each result independently" ([Conductor parallel agents](https://www.conductor.build/docs/core/parallel-agents)). The sidebar's status model isn't documented **[unverified]**. +- **Sculptor:** "Every active agent is visible in Sculptor". Each agent has its own diff, branch and terminal, with Pairing Mode to sync one into your IDE ([Sculptor](https://www.imbue.com/product/sculptor), [docs](https://docs.imbue.com)). + +## 2. Trends across tools + +| # | Trend | Shown by | Why it matters | +|---|---|---|---| +| T1 | **Group by attention state.** Ready for review, needs you, working, landing, done. | Claude Code agent view and Projects; Warp; Devin `waiting_for_user`; Linear `awaitingInput`; Replit Ready | Many agents only stay manageable when the list sorts itself by what the human must do next. | +| T2 | **One-line now-line plus peek.** Each row says what it is doing or asking, and a peek shows the latest output without opening it. | Agent view summary and peek; Amp `Space`; Linear ephemeral activities | Reading many rows beats opening many transcripts. | +| T3 | **Review is the destination, sized on the row.** Diffstat, checks, PR state; review panes; a Ready column. | Claude Code `+42 -18`; Codex review pane and inbox; Conductor; Replit; Vibe Kanban | The human's job is review, so the row says how big the review is. | +| T4 | **Coordinator, workers and a plan.** Parent/child sessions, milestones, validation criteria, checklists. | Claude Code Projects; Factory Missions; Linear agent plans; Warp parent/child; Devin `child_session_ids`; Jules plans | Progress reads as steps done out of steps planned, not as log volume. | +| T5 | **State derived from activity.** "Stale" or "inactivity" comes from the event stream. | Linear (state from last activity; `stale`); Devin `suspended: inactivity`; agent view idle sessions | It agrees with [console-run-monitoring-ui.md](console-run-monitoring-ui.md) §2 and the `health()` rule: silence is the stall. | +| T6 | **Attention leaves the page.** Tab-title counts, dots, badges, toasts, mailbox, OS notifications. | Agent view tab title; Projects dot; Warp toasts, mailbox and badge; Codex unread; Jules notifications | Nobody watches the page; the page has to call. | +| T7 | **Spend and size per session.** Tokens, session length, credits, XS–XL. | Copilot overview; Factory top bar; Devin ACUs and size class; Warp usage | Cost and "this was too big" are review signals. | +| T8 | **Keyboard and tiles for the desk; the same list on the phone.** `j`/`k`, `Space`, `Enter`; side-by-side tiles; mobile surfaces. | Agent view; Amp; Claude Squad; Cursor 3.0/3.1 grid and tiles; mission control "any device"; Warp Runs on mobile | Power users scan with keys and watch several live logs at once; phones get the list. | +| T9 | **Steer mid-run.** Follow-up box, pause, refine, restart. | Copilot; Claude Code; Jules pause; Factory pause and re-plan; Claude Squad pause and resume | Saves a failed Run, but needs a write path. | +| T10 | **Working set by archiving or resolving.** | Amp `e`; Copilot archive; Projects auto-Resolved after a week; Conductor archive | Keeps "now" short. | + +## 3. Fit with thirdshift's rules + +| Trend | Fits? | How, or why not | +|---|---|---| +| T1 attention groups | **Yes** | Read-only regrouping of the same Commands. Map: **Needs you** = died, silent, failed, `needs-triage`, Security finding waiting (`needsYou()`); **Ready for review** = outcome `ready` with an open PR; **Working** = live and healthy; **Landing** = a live **Merge run** at CI watch or **Self-merge**; **Done** = merged, skipped, plus history. The settled "live first" order survives inside Working. | +| T2 now-line + peek | **Yes** | The now-line is the latest event (or the question, cause or silence); the peek shows the last few Session log entries via `mountLog`. A reply box doesn't fit (T9). | +| T3 review destination | **Partly** | Show diffstat (`summaryText`), checks and a PR link. Reviewing, staging, commenting and merging stay on GitHub, because the CLI can't do them. | +| T4 coordinator/workers/plan | **Yes** | Pickup run → Spec run → Ticket Runs is the hierarchy. Show a Spec run's Tickets as a plan checklist (merged / running / waiting on / not started), which is the **Tickets checklist** the Spec PR already carries. | +| T5 state from activity | **Yes** | It's already the `health()` rule (silence ≥ `SILENT_MIN` = possibly stuck). | +| T6 attention leaves the page | **Yes, read-only** | Put the count in the page title ("2 need you · thirdshift Console") and a dot on the favicon. OS or browser notifications need a permission prompt and are better left to the existing **Run notification** email for now. | +| T7 spend and size | **Yes** | `usageText()` per session and Command. A size class could come from session length against `usual()`. Text only, no charts. | +| T8 keyboard, tiles, phone | **Yes** | Keys and tiles are view-only. On the phone it's the same list with the peek as a sheet. | +| T9 steer | **No, for now** | There is no `thirdshift` command to message or pause a running session. Stop stays the only write: `thirdshift stop ` (shown as a hint; "requeue instead" is `thirdshift stop --requeue `, which shipped with #773). A future `thirdshift resume`/`steer` would be a CLI decision first. | +| T10 archive/resolve | **Partly** | Manual archive is a write, so it's ruled out. An automatic "Resolved" fold works, as in Projects: ended Commands with nothing waiting fold away after a day. | + +## 4. What this adds to the earlier note + +[console-run-monitoring-ui.md](console-run-monitoring-ui.md) argued for a "needs you" strip, silence as the stall rule, usual ranges, at most two fold levels, and what Stop keeps. Agent products agree on all of that. They add four things: + +- **Group the whole page by attention state** (T1), not just a strip above a process-ordered body. +- **The row's now-line is the question when there is one** (T2): for thirdshift, the cause, the silence, or what a Ticket waits on. +- **A "Landing" state** between Ready for review and Done (T1, Projects): a Merge run that is green and merging. +- **Attention outside the page** (T6) via the title and favicon. + +## 5. A new variant: `inbox` + +**Idea.** An agent-view-style console: one keyboard-first list grouped by what the Day shift must do, a peek pane that shows the newest lines without opening anything, and tiles that show several live Session logs side by side. It sits closest to `accent` (list and detail) and `briefing` (needs first). It differs from both in three ways: the groups are attention states rather than live and history; the detail is a light *peek* (now-line, last entries, PR, Stop) with the full log one key away; and live logs can tile. + +**Sections, top to bottom.** Each section has an `h2`, so it folds like the rest: + +1. **Header:** host name, the stephens Console link, sign out. A small key legend (`j k` move · `space` peek · `enter` open · `t` tile). +2. **Needs you** (from `needsYou()`), urgent first. The now-line is the problem in words: "no output for 14 min at CI watch", "died at implement 2 h 51 min ago", the `cause`, or "low Security finding waits". +3. **Ready for review:** Commands with outcome `ready`. The now-line is "PR chart35#227 · +112 −15 in 7 files · 2 Unaddressed findings" (`summaryText`). +4. **Landing:** live Merge runs at CI watch or Self-merge. The now-line is the CI state, with `heartbeat()`. +5. **Working:** live and healthy Runs, live first. The now-line is the latest event, then stage · age, `usualText`, `heartbeat`. A Spec run shows its Tickets as a plan checklist under the row (✓ merged, ▸ running with stage · age, ⏸ waiting on #239, ○ not started). Each Ticket is a row of its own, so two levels at most. +6. **Done:** merged, interrupted and skipped Commands from the last day, one line each with `summaryText`. Older ones fold into **Resolved**, closed by default. + +**Rows.** Each row has: +- a state glyph and a state word; +- the kind, then the issue and title (`chart35#239 Queue edits made while offline`); +- the now-line, kept to one line; +- the age on the right; +- for live Commands, a quiet **Stop**, shown only when `canStop`. + +`data-latest` stays on the now-line of the running Run, so it updates live. + +**Peek pane.** Desktop puts it on the right, about 40%; on a phone it is a bottom sheet over the list. `Space`, a tap or a click opens it on the selected row. It shows: +- the row's title and state; +- health in words (`health()`), stage · age with `usualText`, and `heartbeat`; +- `usageText` for the row's sessions; +- the PR and `summaryText`; +- the cause, for a failure; +- the **last 8 entries** of the open Session log (a compact `mountLog` with folds closed), plus links to the full Session logs and the Command log; +- the Stop confirm with `stopEffectsHTML(c)`, the needs-triage sentence, "Requeue instead", Cancel, and `stopHint` and `requeueHint`. + +`Enter` opens the full log in the pane. + +**Tiles.** `t` pins the selected live Run's Session log as a tile. Up to four tiles sit in a 2 × 2 grid under the list on wide screens, with each tile's heartbeat in its bar, as in Cursor's tiled Agents Window. Tiles don't show on phones. + +**Attention outside the page.** The document title becomes "‹n› need you · thirdshift Console", and the favicon gets a dot while `needsYou()` has urgent items, as agent view does in the tab title. + +**Tone and look.** Quiet and dense, close to a terminal UI but in the browser: a monospace now-line, a sans-serif title, and one accent per state with a word beside every colour. Light and dark. + +**Keyboard.** `j`/`k` or arrows move, `space` peeks, `enter` opens, `t` tiles, `esc` closes the peek, and `g` then `n`/`r`/`w` jumps to Needs you, Ready or Working. Keys never fire inside the search box or the Stop confirm. The prototype bar's ← and → keep cycling variants, so the inbox uses `j`/`k`, not the arrows. + +**Phone (390 px).** One column: the groups in order, rows of two lines (title; now-line and age), and a bottom sheet for the peek. No tiles and no page-level horizontal scroll. + +**Shared helpers.** `needsYou`, `health`, `usualText`, `heartbeat`, `usageText`/`sessionsOf`, `summaryText`, `canStop`, `status` (for "stopping…"), `stopEffectsHTML`, `stopHint`/`requeueHint`, `mountLog`, `commandLogText`, `openSession`/`openCommandLog`, and `data-fold`/`data-fold-default="open"` for the plan checklist and Resolved. + +## 6. Small revisions the trends support + +- **All variants, in `app.js`:** put the "‹n› need you" count in the document title and a dot on the favicon (T6). It's read-only and works whatever the variant. +- **All variants:** add a **Ready for review** group or strip for `ready` Commands with diffstat (T3). Today they only appear in history, and `briefing` alone lists them. +- **`lanes`, `press`, `pressplain`, `accent`:** mark a live Merge run at CI watch or Self-merge as **Landing**, not just "live" (T1). +- **`plain`, `accent`, `garden`:** show a Spec run's Tickets as a plan checklist with ✓ / ▸ / ⏸ / ○ and words, as Linear agent plans and Factory milestones do (T4). +- **History in every variant:** fold Commands that ended more than a day ago, with nothing waiting, into a closed **Resolved** group (T10), rather than adding an archive action. From 927ed930b72af772c2b28463171ea2a7120b9441 Mon Sep 17 00:00:00 2001 From: Jacob Stephens Date: Mon, 19 Oct 2026 12:31:27 -0400 Subject: [PATCH 2/2] Grill #711 Round 7: settings, the page's own look, user Themes Record Round 7: the inbox.* and logs.* settings, the page writing only its own look under [console], user Themes and fonts in a themes folder, and #776 covering all seven pages. Amend ADR 0016 for the page setting its own look. Co-Authored-By: Claude Opus 5.5 --- .scratch/grill-with-docs/711-live-runs.md | 19 ++++++++++++++----- ...16-the-console-is-a-long-running-reader.md | 5 +++-- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/.scratch/grill-with-docs/711-live-runs.md b/.scratch/grill-with-docs/711-live-runs.md index d2ff18412..1908e93be 100644 --- a/.scratch/grill-with-docs/711-live-runs.md +++ b/.scratch/grill-with-docs/711-live-runs.md @@ -514,7 +514,7 @@ Silence as the stall rule goes in Silent's definition. "Motion only for thirdshi *Checked:* Read as (b), two Specs, since `/to-tickets` runs "for each spec". The ADR is written: [ADR 0016](../../docs/adr/0016-the-console-is-a-long-running-reader.md). -## Round 7 (open) +## Round 7 (answered) **Q45 - The new settings: names, and what they govern.** Q37 and Q38 add three settings to the User config. `thirdshift status` reads them too, so they belong outside `[console]`. The options: - (a) **`inbox.days = 7`** sets how long an ended problem stays in Needs you, and how far back Resolved reaches. Done stays at one day. **`inbox.silent_minutes = 10`** sets when a Run is Silent; it escalates at three times that. **`logs.waiting_line_minutes = 5`** sets how often a waiting stage, such as CI watch or Self-merge, writes a line. If the waiting line doesn't come more often than the silent time, `status`, the page and Setup warn, and thirdshift uses half the silent time instead, so a waiting stage never reads as Silent. @@ -522,7 +522,7 @@ Silence as the stall rule goes in Silent's definition. "Motion only for thirdshi *Recommended:* (a). Your answer named one period, and with one number Needs you and Resolved never disagree about what happened this week. Clamping the waiting line keeps a typo from turning every CI watch red. -*Answer:* +*Answer:* agree **Q46 - What the page may write.** You'd like settings on this host to live in the User config, so a Theme follows you from browser to browser, and the page can change them. The options: - (a) **The page writes only the Console's look, under `[console]`: the chosen Theme and the hidden sections.** It never writes the allowlist, the addresses, the thresholds, or any other section. Every write is also a CLI command: `thirdshift console theme ` and `thirdshift console sections`. Each one keeps the file's comments, as Setup does, and goes in the Console log naming the account. The setting is per machine, so every account on that Console sees the same Theme. "New since you last looked", Pause motion, what's folded, and the peek stay in the browser. ADR 0016 is amended: the page reads, Stops, and sets its own look. @@ -531,7 +531,7 @@ Silence as the stall rule goes in Silent's definition. "Motion only for thirdshi *Recommended:* (a). One place for settings is what you asked for, and a signed-in phone that can change only the look can't widen who signs in. (b) is worth doing only once a machine has more than one person. -*Answer:* +*Answer:* agree **Q47 - Your own Themes and fonts.** The options: - (a) **A folder, `~/.thirdshift/console/themes/`, holds one `.json` per Theme you made, and a `fonts/` folder of `woff2`, `woff`, `otf` or `ttf` files.** The Console serves those fonts from its own address, so nothing comes from another site. A Theme names a font in one of three ways: a built-in family, a system stack, or a file in `fonts/`. The page's editor saves Themes into the folder. Fonts are added by copying files in, not by uploading them through the page. The CLI has `thirdshift console theme list`, `import ` and `export `. @@ -540,7 +540,7 @@ Silence as the stall rule goes in Silent's definition. "Motion only for thirdshi *Recommended:* (a). Copying a font file in is one `scp` for whoever runs the machine. An upload form would be the page's first way of putting arbitrary files on the server, for little gain. -*Answer:* +*Answer:* agree **Q48 - How the Console's Specs are cut, and the charts.** Q40 put all seven pages in, with scope managed through `/to-spec` and `/to-tickets`. The options: - (a) **Rewrite #776 to cover all seven pages, Themes and the settings.** `/to-tickets` puts the Waterfall's Tickets last, including matching tool calls to the Command log's times. Charts get an issue of their own (`needs-triage`), to be grilled later, since nothing yet says what they'd show. Candidates are Commands per day by outcome, each stage's time week by week, and tokens per day. @@ -548,7 +548,7 @@ Silence as the stall rule goes in Silent's definition. "Motion only for thirdshi *Recommended:* (a). The Waterfall is settled enough to cut Tickets for, and the charts aren't. Putting the charts in a Spec now would hold the Waterfall up behind questions nobody has asked yet. -*Answer:* +*Answer:* agree ## Settled by earlier answers (shout if any is wrong) @@ -610,6 +610,15 @@ Silence as the stall rule goes in Silent's definition. "Motion only for thirdshi - **The built-in Themes' fonts are embedded,** as Latin-subset woff2 files at the weights they use (Q42 a). Users' own fonts are Q47. - **`CONTEXT.md` has Inbox, Needs you, Silent, Slow, Usual range and Theme,** and [ADR 0018](../../docs/adr/0018-the-console-has-one-layout-and-themes.md) records one layout with Themes made of tokens (Q43). "Motion only for thirdshift's activity" and "visual calm" go in #776 as rules. - **The research notes are on `web-ui`, the prototype stays on its branch, and the verdict is on #776** (Q44 a). +- **Three new User config settings** (Q45 a): + - `inbox.days = 7`: how long an ended problem stays in Needs you, and how far back Resolved reaches. Done is one day. + - `inbox.silent_minutes = 10`: when a Run is Silent. It escalates at three times that. + - `logs.waiting_line_minutes = 5`: how often a waiting stage writes a line. + + If the waiting line doesn't come more often than the silent time, `status`, the page and Setup warn, and thirdshift uses half the silent time. +- **The page writes only its own look, under `[console]`: the chosen Theme and the hidden sections** (Q46 a). Each write is also a CLI command (`thirdshift console theme `, `thirdshift console sections`). It keeps the file's comments and goes in the Console log naming the account. The look is per machine, the same for every account. "New since you last looked", Pause motion, what's folded and the peek stay in the browser. ADR 0016 is amended to say the page reads, Stops and sets its own look. +- **Your own Themes are files in `~/.thirdshift/console/themes/`, with a `fonts/` folder** (Q47 a). The Console serves those fonts from its own address. A Theme names a built-in family, a system stack or a file in `fonts/`. The page's editor saves Themes there. Fonts are copied in, never uploaded through the page. The CLI has `console theme list`, `import ` and `export `. +- **#776 is rewritten to cover all seven pages, Themes and the settings,** with the Waterfall's Tickets last (Q48 a). Charts get an issue of their own, `needs-triage`, to be grilled later. - **The confirm step's "requeue instead" is `thirdshift stop --requeue`,** which shipped with #773 and #774. The laptop agent thought the flag was invented; it was settled in Q12. - **The page borrows** nested child Runs, each stage with its age, a one-line latest event, and Stop only while the process is alive, with a confirm step on the page. Session logs get folded tool calls, collapsed thinking, a renderer per tool over a plain fallback, and appends rather than redraws (Q16 a). diff --git a/docs/adr/0016-the-console-is-a-long-running-reader.md b/docs/adr/0016-the-console-is-a-long-running-reader.md index 45671410d..75bca719d 100644 --- a/docs/adr/0016-the-console-is-a-long-running-reader.md +++ b/docs/adr/0016-the-console-is-a-long-running-reader.md @@ -1,7 +1,7 @@ # The Console runs all the time, but only reads and does what the CLI does ADR 0009 rejected a long-running `thirdshift watch`: it has to be kept alive, it keeps running the old binary after `thirdshift update`, and when it hangs nobody notices. The **Console** needs something listening, so `thirdshift console` runs all the time, on 127.0.0.1, behind the machine's own Caddy or Apache. It stays within the spirit of ADR 0009 for three reasons: -- **It never starts work.** Every Command is still started by the operating system's scheduler or by a person, and the Console's only action, **Stop**, is the CLI's `thirdshift stop`. +- **It never starts work.** Every Command is still started by the operating system's scheduler or by a person. The Console's actions are **Stop**, which is the CLI's `thirdshift stop`, and setting its own look, which is `thirdshift console theme` and `thirdshift console sections` (amended 2026-10-19, #711 Q46). - **It survives updates.** It re-executes itself when `thirdshift update` replaces the binary. - **A hang costs no work.** A Console that hangs loses no Run; the next request shows it's down. @@ -18,5 +18,6 @@ It reads what each Command writes about itself, its **Command record** and its l ## Consequences - `console install` writes a system unit that runs as the user, the same way other long-running apps are kept on both machines today. It prints a script for `sudo` that writes the unit and the proxy's site file. -- Every view and action on the page is also a CLI command with `--json`, and a test pairs them. Agents use the CLI, not the page, and no HTTP API is promised to anyone. +- Every view and action on the page is also a CLI command with `--json`, and a test pairs them. +- The only part of the User config the page writes is its own look, under `[console]`: the chosen **Theme** and the hidden sections. It never writes the allowlist, the addresses or any other section, so a signed-in browser can't change who may sign in. Agents use the CLI, not the page, and no HTTP API is promised to anyone. - Async code (axum on tokio) lives only inside the Console. The rest of thirdshift stays blocking.