Skip to content

Commit 1d20c38

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 3fa5c5c commit 1d20c38

12 files changed

Lines changed: 336 additions & 0 deletions
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
What the tests cover: with nothing parked the hub renders no section and no headline at all; a parked agent's question appears with its agent name, its project, and the "Waiting on you" count, and picking an option answers that agent's gate. Questions from several projects sit side by side and each is answered against its own agent. The card header opens the agent that asked, carrying its project along. An agent that never named itself is labelled by the first line of what it was asked to do.
2+
3+
Autopilot: the automatic-acceptance countdown never runs in the hub, even when the user has autopilot switched on.
4+
5+
The jump list: absent for a single question, present once there are several — one entry per card labelled by agent name, and selecting one scrolls its card into view.
6+
7+
Answering: an accepted pick collapses the card to a single line in place, drops it from the open count, and keeps the question visible; expanding that line shows all the options with the pick marked and still offers the way into the agent, and collapsing hides them again. A pick that fails to post does not collapse — the error is shown and the gate stays open and counted.
8+
9+
## Before modifying/creating SPEC.md files
10+
11+
You must always read and respect https://raw.githubusercontent.com/brillout/sdd/refs/heads/main/sdd.md
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
What the tests cover: the "Routine work" card's rows, its Run now paths, and the settings at its foot.
2+
3+
**The rows.** Every routine the daemon runs gets a row, named by its own label, with a second line only for the routines that describe themselves. With no project registered the card says to add one and offers no Run now.
4+
5+
**Run now, plain start.** For a routine that is a single start, the click sends the routine's prompt verbatim, in the picked project, unattended, and then moves to the agent it started. A start that reports no agent identifier still hands over the project, so the dashboard can adopt the running agent when it surfaces. A failed start neither navigates nor leaves the button stuck on "Starting…", and shows the failure. A start already in flight disables every Run now.
6+
7+
**Run now, sweep-backed.** The drain's click asks the daemon for a drain-only sweep across every project, sending no project and starting nothing directly, and does not navigate. The planning routine's click asks for planning in the picked project only. A routine pinned to a branch is asked for by its branch, never by its name, and scoped to the picked project. A dashboard that does not run the sweep says there is nothing to trigger rather than failing silently.
8+
9+
**What Run now promises.** The hover states the routine's own sentence, the model and run target the start would use — read from the preferences, saying "the CLI's own default" when no model is pinned and ignoring a model pinned for the other driver — and how many agents the click starts: one agent for a plain start, up to the configured number one per open ticket for the fan-out routine, and for the drain, every project the daemon watches, up to that number each. A concurrency of one is worded as one agent. The drain's hover says each project's own settings decide its model and location instead of promising these ones.
10+
11+
**Configure first, then run.** The chevron's menu entry opens the picked project's launcher with the routine's prompt carried over, starting neither an agent nor a sweep, and stays available while a start is in flight. Its wording says "one agent, not the fan-out" for the routines whose Run now fans out, and otherwise promises that the model and run target can be set.
12+
13+
**The picked project.** Several projects get a "Run in" picker; one project gets none. The pick is stored as a user preference, read back on the next render and honoured by Run now and by Configure first; a stored pick naming a project that no longer exists falls back to the first.
14+
15+
**The schedule switch.** It is the one global preference, shown with a countdown to the next sweep when the schedule is on and the daemon has reported one, and as plain "Auto-run" otherwise. Every routine starts ticked; unticking one records only that routine, and re-ticking it leaves the other opt-outs intact. Run now ignores the tick state entirely. Auto-run on with every routine unticked warns that the schedule has nothing to run, and the warning goes as soon as one routine is back on.
16+
17+
**Trigger routine now.** It fires the sweep instead of waiting out the countdown, and stays available with the schedule off, where its hover says auto-run stays off. Its answer is reported: a single project's message plainly, several projects' messages each prefixed by folder name, and "not running the sweep" for a dashboard without one. The sweep-backed Run now clicks report their outcome the same way.
18+
19+
**Concurrent agents.** The box shows the daemon's default until it is set, up to the allowed maximum; typing writes the value clamped to that maximum and to a minimum of one, and emptying the box writes nothing. The sentence under it follows the number rather than promising an idle machine.
20+
21+
## Before modifying/creating SPEC.md files
22+
23+
You must always read and respect https://raw.githubusercontent.com/brillout/sdd/refs/heads/main/sdd.md
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
What the tests cover: the page reads every registered project's tickets and lists each project's under its own heading; opening a row identifies the ticket by its project and filename; a project with no tickets still offers its own "Update from GitHub" rather than being a dead end; with no project registered the page says so; and an import or update started inside one project's section reports that project as the one the agent runs in.
2+
3+
Sorting: the page keeps the order the tickets arrive in by default (newest first), sorting by priority puts the highest first and lands in the address, and a priority tie falls back to newest first rather than an arbitrary order.
4+
5+
Filtering: searching narrows the rows, updates the shown/total tally beside the page title, and writes the search into the address; mounting under an address that carries a filter starts filtered; clicking a row's topic adds that topic filter; clicking a row's claim marker narrows to claimed tickets. When filters hide everything, the page says how many tickets are hidden and clears them from right there — and does not offer the GitHub update, because those tickets exist and are merely filtered.
6+
7+
Grouping: the flat mode renders one cross-project list ordered across projects, with each row naming its project and no per-project update controls; opening a flat row still identifies its own project and file; and a flat row's start button runs the work agent in that row's own project, unattended, with the ticket named on it.
8+
9+
## Before modifying/creating SPEC.md files
10+
11+
You must always read and respect https://raw.githubusercontent.com/brillout/sdd/refs/heads/main/sdd.md
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Records when each of a running agent's events reached the dashboard, so the live feed can show arrival times for events that carry no timestamp of their own.
2+
3+
Only events that actually arrived live are stamped: an event read back from a past agent's record has no arrival time, so that agent's feed shows no times rather than wrong ones.
4+
5+
## Before modifying/creating SPEC.md files
6+
7+
You must always read and respect https://raw.githubusercontent.com/brillout/sdd/refs/heads/main/sdd.md
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Makes the browser tab's icon say whether any agent is currently working: the plain product mark while nothing runs, an animated colour variant of the same mark while an agent is working.
2+
3+
The icon is only re-pointed when the state actually changes, because re-setting the same icon restarts the animation in some browsers.
4+
5+
## Before modifying/creating SPEC.md files
6+
7+
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 tab icon switches to the animated mark while an agent is working and back to the plain mark when nothing runs; the page's existing icon is repointed rather than a second one added; a page that starts with no icon gets 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: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
Resolves the settings in force wherever the user is in the dashboard: their own preferences, with the open project's committed `the-framework.yml` layered on top. It keeps one shared answer that every part of the dashboard reads, decides what a change writes and where, and answers what each individual setting resolves to — the theme, whether browser or Discord delivery is on, and which notification categories are on.
2+
3+
## Glossary
4+
5+
- **tier** - one of the two layers a setting can come from: the user's own **preferences**, and the open project's committed `the-framework.yml`.
6+
- **provenance** - which tier a resolved setting actually came from, so a value inherited from the repo can be shown as not the user's own choice.
7+
8+
## Business logic — TL;DR
9+
10+
- **Two tiers, nearest wins** - the open project's committed `the-framework.yml` overrides the user's own preferences, key by key.
11+
- **One writable destination** - only the user's own preferences can be changed from the dashboard; a repo-shaped setting is edited in the repo.
12+
- **Provenance per setting** - each resolved setting reports which tier set it, so the launcher can show an inherited value as not the user's own.
13+
- **One shared answer** - every part of the dashboard reads the same resolved settings and moves together on a change.
14+
- **A write sends only what changed** - and never lets a stale answer overwrite the value the user just chose.
15+
- **Re-read when the user comes back** - returning to the window or the tab re-reads both tiers, so a tab left open stops showing values someone changed elsewhere.
16+
- **Shared project presets** - the open project's custom presets are read from and written back to the repo, so everyone who clones it gets them.
17+
- **Named readers for individual settings** - the theme in force, browser and Discord delivery, and the "new activity" and "needs you" categories.
18+
19+
## Business logic
20+
21+
### Two tiers, nearest wins
22+
23+
#### User story
24+
25+
A user has their own dashboard settings. A project can also commit settings in its `the-framework.yml`, which everyone who clones the repo gets.
26+
27+
#### Business logic
28+
29+
The settings in force are the user's own preferences with the open project's committed `the-framework.yml` layered over them, key by key: the nearer tier wins. With no project open, or with a project that commits nothing, the user's own preferences stand alone. Every project's committed file is read in one go from the project list, and the daemon re-reads the file itself on each request.
30+
31+
#### Rationale
32+
33+
A third tier once existed — the user's own per-project overrides — duplicating for one machine what the committed file already states for everyone. It cost a split write path, per-tier write bookkeeping and a three-way provenance union, and was removed so that everything writable goes to exactly one place.
34+
35+
### One writable destination
36+
37+
#### User story
38+
39+
The user toggles a setting in the dashboard.
40+
41+
#### Business logic
42+
43+
Only the user's own preferences are writable from the dashboard; the repo's committed file is edited in the repo. Every change therefore has a single destination and there is no split to get wrong. A change is applied to the shared answer immediately so the interface responds at once, then persisted daemon-side; a failed save is not surfaced, since it is not worth an error over a checkbox.
44+
45+
### Provenance per setting
46+
47+
#### User story
48+
49+
Looking at the launcher, the user needs to tell a value they chose from one the project's committed file handed them.
50+
51+
#### Business logic
52+
53+
Alongside the resolved settings, each key reports which tier set it — the user's own preferences or the repo — with no answer at all for a key nobody set. The nearer tier's claim wins, matching how the value itself resolves.
54+
55+
### One shared answer
56+
57+
#### User story
58+
59+
Several parts of the dashboard show the same settings at once — for instance the Start form's toggles and a gate's autopilot countdown.
60+
61+
#### Business logic
62+
63+
The resolved settings are held once and every reader is subscribed, so a change moves all of them together. Each tier is read from the daemon once rather than per reader. While the dashboard is being pre-rendered there is no daemon, so the answer starts empty and the real values arrive in the browser.
64+
65+
### A write sends only what changed
66+
67+
#### User story
68+
69+
Two dashboard tabs are open, or one has been sitting in the background for a while, and settings change in the other.
70+
71+
#### Business logic
72+
73+
A change sends only the keys it actually changed, and adopts the settings the daemon reports back, so the tab stops being stale about anything changed elsewhere. If a newer change went out in the meantime, the older reply is ignored — the newer answer is the more recent truth and is about to arrive. A re-read is likewise skipped while any change is still in flight, in either order, because until the daemon has stored those keys no read can answer with them.
74+
75+
#### Rationale
76+
77+
Sending the whole cached set of settings meant a tab replayed every value it happened to be holding, so a tab open since before someone else's change reverted it on its next write — most visibly the theme.
78+
79+
Similarly, if the very first load of the user's preferences is still in flight when the user toggles something, the arriving load must not overwrite the value that toggle already stored.
80+
81+
### Re-read when the user comes back
82+
83+
#### User story
84+
85+
Someone edits a project's `the-framework.yml` in their editor, or changes a setting in another tab, then looks at the dashboard again.
86+
87+
#### Business logic
88+
89+
Both tiers are re-read whenever the window regains focus and whenever a tab becomes visible again. The second case matters on its own: switching back to a tab inside an already-focused window announces no focus change, and that is exactly when a tab is showing values someone changed elsewhere.
90+
91+
### Shared project presets
92+
93+
#### User story
94+
95+
A team wants its custom presets to travel with the repo, so everyone who clones it gets them.
96+
97+
#### Business logic
98+
99+
The open project's shared custom presets are read from the repo once per project, and replacing them writes through immediately and then persists back into the repo. With no project open there are no shared presets and nothing to save, since there is no repo to commit them to. A failed save is not surfaced, as with any other preference write.
100+
101+
### Named readers for individual settings
102+
103+
#### User story
104+
105+
Components ask about one setting at a time: which theme to paint, whether to raise a browser notification, whether to post to Discord, and which categories of event are worth notifying about at all.
106+
107+
#### Business logic
108+
109+
The theme in force is the user's choice, or following the operating system when they have not chosen; the dark palette applies when they chose dark, or when they follow the operating system and it is dark.
110+
111+
Notification delivery is asked per method — browser delivery, where the browser's own permission remains the real gate, and Discord delivery, where the daemon's webhook is the other gate — and per category: "new activity", which pings on an agent starting or finishing, and "needs you", which pings when an agent is awaiting an answer or a PR needs review. A method and a category compose: both must be on.
112+
113+
#### Rationale
114+
115+
The defaults for these settings belong to the framework rather than the dashboard, because the daemon acts on the same values and the polarities are not uniform. A second copy of the defaults here is how the two sides would drift.
116+
117+
## Before modifying/creating SPEC.md files
118+
119+
You must always read and respect https://raw.githubusercontent.com/brillout/sdd/refs/heads/main/sdd.md
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
What the tests cover: how the dashboard resolves and changes the settings in force.
2+
3+
- **Loading** - the first read of the user's own preferences populates the shared answer; a toggle made while that read is still in flight survives it, rather than being overwritten by the pre-toggle value.
4+
- **Two tiers** - the open project's committed `the-framework.yml` overrides the user's own preferences key by key, contributes its own keys, and leaves keys it says nothing about to the user's tier; a project that commits nothing changes nothing.
5+
- **Provenance** - each resolved setting reports whether the repo or the user's own preferences set it.
6+
- **One writable destination** - a toggle only ever writes the user's own tier, while the repo's committed keys keep winning over it.
7+
- **Re-reading the repo tier** - an edit to a project's `the-framework.yml` is picked up on the next re-read, and a deleted file stops contributing altogether instead of lingering; a failed project read is swallowed, leaves the other tier intact, and does not stop the next re-read from working.
8+
- **Stale-tab protection** - a change sends only the keys it changed rather than replaying everything the tab happens to hold; it adopts the settings the daemon reports back, so a stale tab converges on what another tab changed; an older change's reply arriving after a newer one does not undo the newer one; a re-read fired while a change is still in flight does not overwrite it; and a rejected change leaves the value the user chose on screen.
9+
- **Theme** - no chosen theme means following the operating system; a fixed choice ignores the operating system, while following it tracks whether it is dark.
10+
11+
## Before modifying/creating SPEC.md files
12+
13+
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: a dashboard action that succeeds hands its result back, shows no error, and stops reporting itself as busy; the daemon answering that the action did not succeed surfaces the daemon's own reason and tells the caller it failed; an action that fails outright surfaces the failure's message, or the wording the control chose when the failure carries none; an action that returns nothing still counts as success; and the shown error can be dismissed.
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)