Skip to content

Commit 7dcd2ba

Browse files
committed
Install SDD: next slice of per-file specs
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CSM4FVUbnP4PJJ9sawMfLb
1 parent dfa5d84 commit 7dcd2ba

25 files changed

Lines changed: 942 additions & 1 deletion

packages/the-framework/dashboard/components/AgentHistory.SPEC.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ The user needs to know which view they are looking at.
6262

6363
#### Business logic
6464

65-
Overview leads home and carries the count of items in the user's interventions list as a badge, with a tooltip spelling it out. Tickets opens the cross-project ticket view, and is offered only where there is a ticket view to route to. Projects expands in place into an indented list of every registered project — selecting one navigates into it — and ends with an "Add project" item that opens the add-project dialog. Each project carries a dot: red when the daemon has recorded errors for it, with the errors named on hover and read out to assistive technology; filled when the project is activated; muted when it is not.
65+
Overview leads home and carries the count of items in the user's interventions list as a badge, with a tooltip spelling it out ("N items in your Human Queue"). Tickets opens the cross-project ticket view, and is offered only where there is a ticket view to route to. Projects expands in place into an indented list of every registered project — selecting one navigates into it — and ends with an "Add project" item that opens the add-project dialog. Each project carries a dot: red when the daemon has recorded errors for it, with the errors named on hover and read out to assistive technology; filled when the project is activated; muted when it is not.
6666

6767
Exactly one of these carries the active highlight: New while a project's start screen is open, Overview while the Overview is, Tickets while the ticket view is, and the corresponding row while an agent is selected. While the user follows a just-started agent whose id is not known yet, the highlight sits on the newest running row rather than on New.
6868

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
The dashboard's one prompt box, used everywhere the user types at an agent: the launcher, the chat inside an agent, and the navbar's quick launch. It holds the editor plus the controls that decide how the work runs, and hands the composed text to whoever hosts it.
2+
3+
## User story
4+
5+
- The user writes a task and starts an agent on it.
6+
- The user talks to an agent that is already running, or resumes one that has ended.
7+
- The user starts something from the navbar without leaving the page they are on.
8+
- The user picks a canned prompt instead of writing one, and saves their own.
9+
- The user chooses which coding-agent CLI, which model, and where the work runs.
10+
11+
## Business logic — TL;DR
12+
13+
- **One box, three hosts** - the launcher, the in-agent chat and the navbar quick launch all get the same editor, the same data and the same controls; only what happens on submit differs.
14+
- **A preset prefills and then runs verbatim** - loading a preset fills the box with its rendered prompt and marks the work as a canned prompt; emptying the box turns it back into an ordinary task.
15+
- **A preset can insist on its own agent** - some presets must open a new agent rather than talk to the one the user is sitting in.
16+
- **Driver and model are picked together** - each driver lists only its own models, so an impossible pair cannot be chosen, and not choosing a model stays a state rather than pretending the first one was picked.
17+
- **The options gear follows what the next action can still change** - the launcher's full option table, nothing while an agent is live, and just the options that shape a resume once it has ended.
18+
- **An offline device blocks starting and says so** - with no silent fallback to another target.
19+
- **The submit slot holds one control at a time** - an empty box shows Stop or Resume where the host provides one, and typing swaps in the send arrow.
20+
- **A double submit cannot start two agents** - a second press while the first is still in flight is ignored.
21+
- **A carried-in draft is restored** - a draft handed over from another device or from the click that navigated here seeds the box.
22+
23+
## Business logic
24+
25+
### One box, three hosts
26+
27+
#### User story
28+
29+
The user types at an agent from the launcher, from inside an agent, or from the navbar.
30+
31+
#### Business logic
32+
33+
The composer is the editor — with its `/`, `<`, `@` and `#` triggers for presets, files and project mentions — plus a control row holding the presets menu, the driver and model choice, the options gear and the submit control. The host owns what submitting does: the launcher starts an agent with the collected options, the in-agent chat sends a message.
34+
35+
Mentions feed the agent's context: mentioning a project or a file adds its path, and removing that mention from the box drops it again. The list of registered projects for the `@` picker is the composer's own concern, so it loads that list itself instead of every host passing the same list down.
36+
37+
The compact form, used by the navbar's quick launch, is a single row — the editor, the driver and model choice, the options gear and the submit control — deliberately kept to one line so the header never grows taller. It carries no presets menu and no preset-creation panel, but the `/`, `<`, `@` and `#` triggers still work, and the driver, model and options it uses are the same shared preferences the launcher writes.
38+
39+
#### Rationale
40+
41+
The driver and model choice and the options gear were the compact form's one real omission: an agent started from the navbar used the stored driver, model and options with nothing on screen saying which.
42+
43+
### A preset prefills and then runs verbatim
44+
45+
#### User story
46+
47+
The user picks a canned prompt instead of writing one.
48+
49+
#### Business logic
50+
51+
Loading a preset — from the `/` menu or from the presets menu — puts its rendered prompt into the box and marks what will be run as a canned prompt, sent verbatim. Emptying the box is a fresh start: the work goes back to being an ordinary task, and any rule the preset carried is dropped with it.
52+
53+
Presets render against the agent they are launched from: an agent's page passes its own session name, so a preset launched there targets that agent by default, while the launcher passes none and the preset falls through to the whole codebase.
54+
55+
The presets menu offers loading, creating and deleting in one place, for the framework's own presets, the user's saved presets, and the presets committed in the open project's repo. Deleting removes it from whichever of those two lists it belongs to. Creating one saves it either to the user's own presets or, when a project is open, into that project's repo.
56+
57+
#### Rationale
58+
59+
The list of presets, their order and each preset's label live with the presets themselves, so a preset's identity and the button that starts it cannot drift apart.
60+
61+
### A preset can insist on its own agent
62+
63+
#### User story
64+
65+
The user launches a preset from inside an agent, but that preset describes work that must not join the current conversation.
66+
67+
#### Business logic
68+
69+
A preset can declare that it needs an agent of its own. When such a preset is loaded, the two hosts that sit inside an agent start a new agent instead of sending into the agent they are in. Emptying the box drops the preset and this rule with it.
70+
71+
### Driver and model are picked together
72+
73+
#### User story
74+
75+
The user chooses which coding-agent CLI does the work, and on which model.
76+
77+
#### Business logic
78+
79+
Driver and model are chosen from one menu in which each driver lists only its own models, since the model choice passes straight through to that CLI. Picking a model inside a driver's submenu sets both at once, so an incompatible pair cannot be chosen. Every entry is a real model; not having chosen a model is still a state, but no longer something to pick, and the control says so rather than naming the first model as if it had been chosen.
80+
81+
The choice is hidden inside an agent: an agent is bound to the driver it started with, so the control would only ever rewrite the next agent's default. It is made at the launcher instead.
82+
83+
#### Rationale
84+
85+
A "Default" entry used to head each model list, and picking it stored nothing — so the menu's own answer to "which model?" was "we do not know".
86+
87+
### The options gear follows what the next action can still change
88+
89+
#### User story
90+
91+
The user opens the gear inside a running agent and finds nothing they can usefully change.
92+
93+
#### Business logic
94+
95+
At the launcher the gear holds the full table of the user's options, plus the choice of where the work runs — this device, a GitHub Actions runner, or a saved device — and the saved-devices section for connecting to, adding and removing devices. Selecting a device makes it the target for the next agent in place, with no navigation.
96+
97+
Inside an agent the gear behaves according to what the next action can still affect. While the agent is live, every option was baked in when it was spawned, so the gear is dropped entirely rather than opening empty. Once the agent has ended, the next message is a resume — a new leg that resolves the current preferences when it starts — so the gear comes back, labelled as resume options and holding only the options that shape that leg. Where the work runs stays a launcher-only choice, for the same reason the driver choice is.
98+
99+
The "In play" row, which shows how each option was resolved and which layer decided it, is shown at the launcher only. Inside an agent it described the user's global options rather than that agent's, and the compact row has no space for it.
100+
101+
### An offline device blocks starting and says so
102+
103+
#### User story
104+
105+
The user picks a device to run on, and that device is not reachable.
106+
107+
#### Business logic
108+
109+
When the selected device is known to be offline, submitting is blocked — by button and by keyboard alike — and a message names the device and points back at the "Run on" choice to pick another target. There is no automatic fallback to another target. A device whose status is unknown does not block anything. Removing a saved device that was the selected target also clears that selection.
110+
111+
### The submit slot holds one control at a time
112+
113+
#### User story
114+
115+
The user looks at one place for Start, Stop, Resume and Send.
116+
117+
#### Business logic
118+
119+
Submitting is a single arrow button that appears only once the box has text — an empty launcher has nothing to send. Where the host supplies an idle control, that control occupies the same slot while the box is empty: Stop while the agent is live, Resume once it has stopped. Typing swaps it for the send arrow, so start, stop, resume and send are one slot. Without an idle control the slot simply collapses when empty.
120+
121+
The submit control names what it will do and states its keyboard shortcut: Enter to send, Shift+Enter for a new line. While the work is in flight it shows itself as busy.
122+
123+
### A double submit cannot start two agents
124+
125+
#### User story
126+
127+
The user presses the send shortcut twice in quick succession.
128+
129+
#### Business logic
130+
131+
A submit is refused while another is still in flight, independently of the busy state the host reports. Otherwise two fast presses both saw the composer as idle, fired two starts, and the second surfaced a spurious "already active" error.
132+
133+
### A carried-in draft is restored
134+
135+
#### User story
136+
137+
The user starts typing on one device, or clicks something that hands a prompt to the launcher, and expects the text to be there.
138+
139+
#### Business logic
140+
141+
At the launcher, a draft carried in — from another device, or from the click that navigated here — seeds the box. It is taken once and cleared, and it stays an ordinary task rather than becoming a canned prompt.
142+
143+
## Before modifying/creating SPEC.md files
144+
145+
You must always read and respect https://raw.githubusercontent.com/brillout/sdd/refs/heads/main/sdd.md
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
What the tests cover: pipe tables render as real tables with headers and cells, rows of pipes lacking the header separator stay prose instead of becoming a mangled table, and a row with fewer cells than the header leaves the missing cells empty rather than collapsing a column.
2+
3+
Links: `[text](url)` and bare web addresses become links that open without leaking the referrer; a `javascript:` target stays plain text and produces no link at all; and a URL inside backticks stays literal code.
4+
5+
Compact mode: the body and its headings render a notch smaller than their full-size counterparts.
6+
7+
## Before modifying/creating SPEC.md files
8+
9+
You must always read and respect https://raw.githubusercontent.com/brillout/sdd/refs/heads/main/sdd.md
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
What the dashboard shows when a bookmarked or pasted link no longer resolves — an agent whose worktree is gone, a project dropped from the registry: a headline naming what is missing, a sentence explaining why, and one button offering the way back.
2+
3+
## Business logic — TL;DR
4+
5+
- **Say it, don't redirect** - a dead link is stated as a dead link. A silent redirect would look like the link worked and the user clicked the wrong thing.
6+
- **Always a way out** - the page never dead-ends; it always carries a single labelled action back to somewhere that exists.
7+
8+
## Before modifying/creating SPEC.md files
9+
10+
You must always read and respect https://raw.githubusercontent.com/brillout/sdd/refs/heads/main/sdd.md
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
The dashboard's right sidebar beside an agent or the launcher: a small set of tabbed panels — the project's files, the documents the agent published during its work, its browser preview, and the workspace's PLAN/TODO documents — where every tab has to be earned by having something to show.
2+
3+
## User story
4+
5+
- The user wants the project's files at hand while writing a prompt, so files can be picked into the next agent's context without leaving the page.
6+
- The user wants a document the agent published mid-work (a plan, a summary, a writeup) to surface by itself, rather than having to go looking for it.
7+
- The user does not want a sidebar full of tabs that only say "nothing yet", and does not want the tab they are currently reading yanked away.
8+
9+
## Business logic — TL;DR
10+
11+
- **Every tab is earned by content** - Files appears only when the project has files, Views only when the agent published at least one document, Browser only when the agent is actually serving a preview, Docs only when the workspace has PLAN/TODO documents. With no tab left, the sidebar itself is not shown; with no project selected, neither is it.
12+
- **The first published document pulls focus, nothing else does** - the rail jumps to Views the moment the agent publishes its first document. After the user picks a tab by hand, nothing overrides that pick again.
13+
- **A sensible default until then** - with no published document, the rail sits on Files when the project has files, otherwise on Docs.
14+
- **A tab that loses its content is not left empty** - if the active tab's content disappears, the rail falls back to the first tab that still has content.
15+
- **Counts on the tabs** - Views carries the number of published documents; Files carries how many individual files are currently picked into the agent context.
16+
- **Documents are read for the whole rail** - the workspace's PLAN/TODO documents are polled for the selected project, since the rail must know whether they exist before it can decide whether to offer the tab at all.
17+
18+
## Business logic
19+
20+
### Every tab is earned by content
21+
22+
#### User story
23+
24+
See `## User story`.
25+
26+
#### Business logic
27+
28+
The tabs, in this order: Files, Views, Browser, Docs. Files appears when the project reported any files. Views appears when the agent published at least one document. Browser appears only when the selected agent was started with the browser preview on and does not run on a GitHub Actions runner, where there is no browser to stream. Docs appears when the workspace has PLAN/TODO documents.
29+
30+
Each tab carries a hover explanation of what it holds: Files is the project's files, click one to add it to the next agent's context; Views is documents the agent pushed up during its work; Browser is a live view of the browser the agent is driving; Docs is the PLAN/TODO markdown files at the workspace root.
31+
32+
If no tab qualifies, the sidebar is not rendered; nor is it rendered when no project is selected.
33+
34+
#### Rationale
35+
36+
A tab that can only say "nothing yet" teaches the user that the feature is broken. This is why the browser tab is withheld unless the agent genuinely has a preview to show.
37+
38+
### The first published document pulls focus, nothing else does
39+
40+
#### User story
41+
42+
See `## User story`.
43+
44+
#### Business logic
45+
46+
The rail switches itself to Views the first time the agent has published a document. A second document does not switch it again, and neither does the project's file list appearing. Once the user has picked a tab by hand, the automatic default stops applying entirely — only that first-document jump can still move the rail.
47+
48+
Until a document has been published and while the user has not picked a tab, the rail sits on Files if the project has files and on Docs otherwise.
49+
50+
#### Rationale
51+
52+
Gates used to have a tab of their own here and a new one pulled focus; gates are now answered inline in the transcript where they were asked, so the rail has no panel for them. A committed re-narration of the agent's history had a tab too; the agents themselves are that history now.
53+
54+
### Counts on the tabs
55+
56+
#### User story
57+
58+
The user picks files into an agent's context from the file tree, then scrolls away. The count on the Files tab is how they check what is still selected.
59+
60+
#### Business logic
61+
62+
The Views tab shows how many documents the agent has published. The Files tab shows how many of the project's individual files are currently in the agent context; whole-repository entries that also live in that context are not counted, since they are not files in the tree.
63+
64+
### Documents are read for the whole rail
65+
66+
#### User story
67+
68+
See `## User story`.
69+
70+
#### Business logic
71+
72+
The workspace's PLAN/TODO documents are read for the selected project and refreshed every few seconds. The Docs tab is withheld only once the read has come back empty — while the first read is still out the tab stays, so switching projects does not blink the sidebar out and back in.
73+
74+
When the launcher already shows those documents in its main column, the rail withholds the Docs tab outright and skips the read, so the same panel is never shown twice at once.
75+
76+
### Scope of the panels
77+
78+
#### User story
79+
80+
See `## User story`.
81+
82+
#### Business logic
83+
84+
The file tree is scoped to the selected agent's own worktree, and clicking a file toggles it in the agent context shared with the launcher's start form. The browser preview is keyed to the selected agent.
85+
86+
## Before modifying/creating SPEC.md files
87+
88+
You must always read and respect https://raw.githubusercontent.com/brillout/sdd/refs/heads/main/sdd.md
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
What the tests cover: the transcript view asks for the dashboard's own scrollbar treatment — a thin toned bar, a reserved scrollbar lane, a faded bottom edge, and a dimmed bar while the view is chasing the live edge — and every one of those looks it asks for is actually defined by the dashboard's stylesheet, so the styling cannot silently go missing.
2+
3+
## Before modifying/creating SPEC.md files
4+
5+
You must always read and respect https://raw.githubusercontent.com/brillout/sdd/refs/heads/main/sdd.md
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
A menu entry's name with one line of explanatory text beneath it, in smaller muted type — the description is dropped when there is none. The options, notifications, and preset menus all use it, so an explained choice reads the same wherever the user meets one.
2+
3+
## Before modifying/creating SPEC.md files
4+
5+
You must always read and respect https://raw.githubusercontent.com/brillout/sdd/refs/heads/main/sdd.md
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
A floating panel anchored to the button that opened it, for content richer than a list of menu entries — a set of checkboxes with a preview beside them, for instance. It shares the dropdown menu's look and manners: the button stays lit while the panel is open, and a panel taller than the space left on screen scrolls inside itself using the dashboard's own thin overlay scrollbar.
2+
3+
## Before modifying/creating SPEC.md files
4+
5+
You must always read and respect https://raw.githubusercontent.com/brillout/sdd/refs/heads/main/sdd.md

0 commit comments

Comments
 (0)