Skip to content

Commit c18404d

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 4fb00a0 commit c18404d

7 files changed

Lines changed: 418 additions & 0 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
What the tests cover: the gear marks that options are on with a dot rather than a number, and names the count only on hover; toggling an option writes its new value through; a row that cannot be switched is greyed, states its reason in place, and writes nothing when clicked.
2+
3+
The "Run on" list: it is one flat list — the three run targets, then the saved devices, then "Add a device…" — with no section header and no separate duplicate row for the local machine; it is absent entirely where no run target can be chosen (a composer inside a running agent), and its device half is absent when no saved devices are available. "Claude web" is a real, selectable target.
4+
5+
The single checkmark: it follows the chosen run target while no device is selected; selecting a device moves it onto that device and quiets the run-target rows; being connected to a remote daemon puts it on that daemon's device. Choosing any run target also clears a selected device, so the mark never appears twice.
6+
7+
Device rows: clicking one selects it as the run target without navigating anywhere and without writing a preference; its remove control drops the saved device without also selecting it; an unreachable device is dimmed and its address annotated "offline", while a reachable one shows its status dot and is not dimmed; "Add a device…" opens the add flow.
8+
9+
"This machine": on the local daemon it writes the run target and clears any selected device; while connected to a remote daemon it instead returns to the local daemon and writes no run target.
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: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
The dashboard's Settings page: every one of the user's own preferences in one place, grouped into sections, plus the onboarding checklist. Its subtitle states the page's own scope — "Your defaults, everywhere. A repo can override them in its own the-framework.yml."
2+
3+
## User story
4+
5+
- The user wants to find a setting by looking for it, rather than remembering which menu in the header it was hidden behind.
6+
- The user wants the page to tell the truth about what will actually happen: a notification the browser has blocked, an option another option overrides, a Discord channel that has no webhook yet.
7+
- A user part-way through onboarding wants to pick it back up from here.
8+
9+
## Business logic — TL;DR
10+
11+
- **Only the user's own settings are writable here** - a repo-shaped value belongs in that repo's committed `the-framework.yml`, edited in the repo, so everything this page writes is a default that a repo may override.
12+
- **Onboarding lives here** - the checklist sits at the top of the page and cannot be dismissed, since this is where the Overview sends a user who wants to resume it.
13+
- **Appearance** - theme (follow the system, or pin light or dark) and which editor "Open in editor" launches, chosen from the editors detected on the machine or left on auto-detect.
14+
- **Agent** - which coding-agent CLI does the work, which model to pass through to it, and where an agent executes: this machine, a fresh GitHub Actions runner, or a Claude Code cloud session. The saved devices this daemon can run on are listed right after, since a device is the other place an agent can run.
15+
- **Run options** - the same option table the launcher's gear shows, with the same rules already applied, so a rule cannot hold in one place and not the other.
16+
- **A rule-disabled row is shown, not hidden** - an option another option overrides stays in place, greyed, and its description is replaced by the reason it cannot be changed.
17+
- **Notifications** - browser and Discord as the delivery channels, and the two categories that can be sent: an agent awaiting an answer or a pull request ready to review, and agents starting and finishing.
18+
- **A toggle never promises delivery it cannot make** - a channel the browser or the daemon cannot deliver on says so instead, and the Discord row carries the button that supplies what it is missing.
19+
- **Automation** - whether Auto PM starts queued work on its own, and how far from the quota boundary unattended work is allowed to sit.
20+
- **Claude web** - the browser bridge switch and its settings, introduced by why the bridge exists at all.
21+
22+
## Business logic
23+
24+
### Only the user's own settings are writable here
25+
26+
#### User story
27+
28+
See `## User story`.
29+
30+
#### Business logic
31+
32+
Every control on the page writes the user's own preferences. The page never edits a repo's committed configuration; a value that belongs to a repo is edited in that repo, so a settings page can only ever mean "the default". The page says exactly that under its title.
33+
34+
### Appearance
35+
36+
#### User story
37+
38+
See `## User story`.
39+
40+
#### Business logic
41+
42+
Theme follows the system by default and can be pinned to light or dark. The editor setting decides which editor "Open in editor" launches: auto-detect, or one of the editors detected on this machine.
43+
44+
### Agent
45+
46+
#### User story
47+
48+
See `## User story`.
49+
50+
#### Business logic
51+
52+
The driver setting picks which coding-agent CLI runs the work. The model is passed through to that CLI, and left empty means the CLI's own default. The run target picks where an agent executes: this machine, a fresh GitHub Actions runner, or a Claude Code cloud session.
53+
54+
Immediately after, the saved devices this daemon can run an agent on are listed and managed, since a device is the other answer to "where does this run".
55+
56+
### Run options
57+
58+
#### User story
59+
60+
The user comes here to check what a new agent will start with, and needs the answer to match what the launcher would do.
61+
62+
#### Business logic
63+
64+
The section renders the same option table the launcher's gear does, with the same interactions between options already resolved, so the effective value of every option reads identically in both places. Its own description says as much, and adds that an agent's own action bar can still change how that agent ends.
65+
66+
A row that the rules have turned off keeps its place, greyed, and shows the reason it is off in place of its usual description, rather than disappearing.
67+
68+
#### Rationale
69+
70+
Hiding a disabled row defeats the point of the page: this is where a user comes to look for a setting, and a setting that vanishes reads as a missing feature rather than as an override.
71+
72+
### Notifications
73+
74+
#### User story
75+
76+
See `## User story`.
77+
78+
#### Business logic
79+
80+
Two channels and two categories. The browser channel sends desktop notifications while the dashboard is open; when the browser has blocked notifications, the row is greyed, reads as off whatever the stored preference says, and its description says it is blocked in the browser's settings. The Discord channel delivers where no dashboard needs to be open; without a webhook configured on the daemon, it says it is not configured, and the row carries a button that opens the webhook setup — labelled "Set up" when there is none and "Webhook" once there is. Saving a credential there settles every surface that shows the channel's state at once.
81+
82+
The categories: "Human Queue" covers an agent awaiting the user's answer or a pull request ready to review, and is on by default; "New activity" additionally pings when an agent starts or finishes, and is off by default.
83+
84+
### Automation
85+
86+
#### User story
87+
88+
See `## User story`.
89+
90+
#### Business logic
91+
92+
The Auto PM switch decides whether queued work is started on its own while quota is left in the week. The spend offset is how far unattended work sits from the quota boundary, in percentage points: negative holds it back, positive lets it borrow from the days ahead. It is bounded to the same range the usage bar's handle and the daemon's own sanitizer use, and a typed value is held to that range as it is entered.
93+
94+
With no offset saved, the box shows the default actually in force rather than zero, rounded to one decimal.
95+
96+
#### Rationale
97+
98+
The box used to keep displaying a typed 9999 while the saved value had been clamped, and used to show 0 for an unset preference the daemon was not using. Both made the page disagree with what the daemon does.
99+
100+
### Claude web
101+
102+
#### User story
103+
104+
See `## User story`.
105+
106+
#### Business logic
107+
108+
The section explains why the bridge exists: a Claude web agent hands off and ends, so the questions its cloud session asks never reach this dashboard, and the browser bridge carries them back. Its switch opens one route on this daemon that a browser extension can reach, guarded by the token shown with the bridge's own settings below it.
109+
110+
### Controls that cannot be operated are not rendered
111+
112+
#### User story
113+
114+
See `## User story`.
115+
116+
#### Business logic
117+
118+
A setting picked from a list with no options to pick renders nothing at all, rather than an empty picker that reads as broken.
119+
120+
## Before modifying/creating SPEC.md files
121+
122+
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: on a machine with no stored preferences, no saved devices and no editors detected, the Settings page renders its controls and none of its pickers is empty — an empty picker can be opened but not used, which reads as broken. In particular the Editor row, whose choices are the only ones assembled at run time, stays usable with nothing detected, offering auto-detect as a real choice rather than a placeholder.
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: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
One project's `tickets/` backlog as a list of one-line rows, scannable without opening anything, with three agent-starting actions on it: work a ticket, plan a ticket, and bring the whole backlog up to date with GitHub.
2+
3+
## User story
4+
5+
The user wants to read a project's backlog at a glance — what each ticket is, how urgent, whether it is already planned or already being worked, how old — and to put an agent on any of it in one click. On a project with no tickets yet, they want the backlog filled from the repo's GitHub issues rather than a dead end.
6+
7+
## Business logic — TL;DR
8+
9+
- **A ticket is one row** - title, project (in the cross-project list), topics, claim, effort, uncertainty, priority, age, plan, and the GitHub item behind it, all on one line; the row opens the ticket's detail page.
10+
- **Start work from the row** - a play control on the row's left edge starts an unattended agent on that one ticket and nothing else, with the ticket named on the agent.
11+
- **The plan column is either a plan or an offer to write one** - a planned ticket links to its plan; an unplanned one offers to start an agent that writes it.
12+
- **Claimed rows say who holds them** - a ticket an agent has claimed shows a hammer and the holder's name, meaning an agent is planning or implementing it.
13+
- **Update from GitHub** - one action brings `tickets/` up to date with the repo's issues; on a project with no import on record it brings everything open across. It runs unattended, as the same routine does when the daemon starts it.
14+
- **Empty is not the same as filtered** - a backlog filtered down to nothing says how many tickets the filters hide and offers to clear them; only a genuinely empty `tickets/` offers the GitHub update.
15+
16+
## Glossary
17+
18+
- **start column** - the row's left-edge control that starts an agent working that ticket.
19+
- **plan column** - the row's control that either opens the ticket's plan or starts an agent to write it.
20+
21+
## Business logic
22+
23+
### A ticket is one row
24+
25+
#### User story
26+
27+
See `## User story`.
28+
29+
#### Business logic
30+
31+
Every ticket occupies a single line. The title takes whatever width the row has to spare and truncates when it runs out; clicking it opens the ticket's detail page. In the flat cross-project list the row also names its project, since there is no section heading saying it. The rest of the line, from left to right: the ticket's topics, its claim, its effort and uncertainty estimates, its priority — coloured by how urgent it is, and spelled out as "Priority: 8" — and its age, with the exact date and time on hover. Priority, age and the plan column keep fixed widths, and a ticket with no GitHub item still reserves that column's width, so the columns line up down the whole list regardless of what any one ticket carries.
32+
33+
Where the surrounding page supports filtering, a row's topics and its claim marker are clickable: a topic filters the page to that topic, the claim marker filters to claimed tickets. Where the page has no filters, they are plain labels.
34+
35+
### Start work from the row
36+
37+
#### User story
38+
39+
The user reads the backlog, sees the ticket that should be done next, and wants an agent on it immediately.
40+
41+
#### Business logic
42+
43+
The start column asks an agent to work `tickets/<file>` and to start no other ticket. The agent runs unattended — ending when it settles and firing its armed handoff — because one agent on one ticket is exactly the work the queue-draining routine starts, and it should run the same way. The ticket is named on the agent itself, so the agent's record says which ticket it implements.
44+
45+
### The plan column
46+
47+
#### User story
48+
49+
Before committing an agent to a big ticket, the user wants a plan written for it, and afterwards wants to read that plan.
50+
51+
#### Business logic
52+
53+
A planned ticket's plan column links to the rendered plan, marked prominently so planned rows are scannable at a glance. An unplanned ticket's plan column instead starts an agent asked to create the ticket's plan file beside the ticket, and is drawn quietly — an action still available rather than something already there.
54+
55+
The planning agent runs attended, unlike the work agent and the GitHub update: a plan is written for a human to read and act on, so it stays a conversation the user can land in and steer.
56+
57+
### Claimed rows say who holds them
58+
59+
#### User story
60+
61+
The user needs to know a ticket is already being worked before starting a second agent on it.
62+
63+
#### Business logic
64+
65+
A ticket an agent has claimed shows a hammer and the holder's name inline, truncated to keep the row aligned, with the full holder and the explanation on hover: an agent is working on this ticket, planning it or implementing it. Where filtering is available, the hover also says the marker leads to all claimed tickets.
66+
67+
#### Rationale
68+
69+
The holder is named on the row rather than only in the tooltip: a control that only reveals itself after a second of hovering is one nobody discovers.
70+
71+
### Update from GitHub
72+
73+
#### User story
74+
75+
The user's real backlog lives in the repo's GitHub issues and they want `tickets/` to reflect it — the first time, and every time since.
76+
77+
#### Business logic
78+
79+
A bar above the list says when `tickets/` last caught up with GitHub, or that there is no record of an import yet, with the update action beside it. The action asks for `tickets/` to be brought up to date with the issues and comments changed since the last import; with no import on record, everything open comes across instead. It runs unattended, since an update fired by a button is routine work rather than a conversation.
80+
81+
The same instruction sits behind the same label everywhere it is offered, including the onboarding checklist, so one label always means one instruction.
82+
83+
### Starting anything hands the user to the agent
84+
85+
#### User story
86+
87+
The user presses a button and wants to watch the work, not stare at a list that has not changed yet.
88+
89+
#### Business logic
90+
91+
Whenever any of the three actions starts an agent, the dashboard shell is told, so the user lands on the agent doing the work rather than on a panel showing stale rows until files land. Every action is blocked while another start is in flight, and a failed start leaves its reason in the panel: the update, the planning agent, or the work agent could not be started.
92+
93+
### Empty is not the same as filtered
94+
95+
#### User story
96+
97+
See `## User story`.
98+
99+
#### Business logic
100+
101+
A panel whose tickets were all hidden by the surrounding page's filters says how many are hidden and, where the page allows it, clears the filters from right there. It never offers the GitHub update in that state.
102+
103+
A genuinely empty backlog explains that tickets live in `tickets/` and are what the agent plans from, and offers the GitHub update as the way to fill it. Until the project's tickets have been read, the panel says it is loading.
104+
105+
#### Rationale
106+
107+
Offering an import to a user who has merely filtered their backlog away would ask for work that has already been done.
108+
109+
## Before modifying/creating SPEC.md files
110+
111+
You must always read and respect https://raw.githubusercontent.com/brillout/sdd/refs/heads/main/sdd.md

0 commit comments

Comments
 (0)