switchboard
AGENTS.md215 starsChanged 2 months agoMITView on GitHub
Delete buttons delete immediately. No confirm(), no window.confirm(), no modal showWarningMessage, no two-click patterns, no "Are you sure?". The user has demanded this repeatedly. Buttons are deliberately hard to misclick. Also a hard technical reason: window.confirm() is a silent no-op in VS Code webviews (sandboxed iframe without allow-modals — it always returns false). Any confirm gate added to src/webview/planning.js, src/webview/kanban.html, etc. makes the button do literally nothing. This exact bug broke the kanban delete-plan button (fixed 2026-06-11). If you find…
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,774 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository19 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- improve-featureSkill
- improve-planSkill
- external-team-leadSkill
- improve-featureSkill
- kanban-operationsSkill
- manage-featuresSkill
- query-kanbanSkill
- switchboard-orchestrationSkill
- worktree-cleanupSkill
- kanban-operationsSkill
- manage-featuresSkill
- query-kanbanSkill
- switchboard-cloudSkill
- switchboard-memoSkill
- switchboard-remoteSkill
- switchboardSkill
- worktree-cleanupSkill
The file
We split this AGENTS.md into the rules it gives an agent
6 rules. About 0 are common, 3 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 5
Delete buttons delete immediately.
- Distinctive: line 9
If you find a confirm gate in this codebase, it is a bug — remove it.
- Distinctive: line 30
Do not describe this product as a VS Code extension.
- Very specific: line 47
Precedent (2026-08): All four PlanIngestionEngine queue seams — setQueueHeadResolver, setQueuePacingResolver, setQueueTeamMembersResolver, …
- Very specific: line 87
Treat
src/as the source of truth for review: Do NOT audit, check, or flag dist/ staleness during reviews or verification — a stale dist/ … - Distinctive: line 96
When unsure whether something shipped, assume it did and migrate — a no-op migration costs nothing.
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Switchboard — agent rules
NEVER add confirmation dialogs. NO EXCEPTIONS.
Delete buttons delete immediately. No confirm(), no window.confirm(), no modal showWarningMessage, no two-click patterns, no "Are you sure?". The user has demanded this repeatedly. Buttons are deliberately hard to misclick.
Also a hard technical reason: window.confirm() is a silent no-op in VS Code webviews (sandboxed iframe without allow-modals — it always returns false). Any confirm gate added to src/webview/planning.js, src/webview/kanban.html, etc. makes the button do literally nothing. This exact bug broke the kanban delete-plan button (fixed 2026-06-11).
If you find a confirm gate in this codebase, it is a bug — remove it. Multi-choice decision dialogs (e.g. 3-way conflict resolution) are allowed; plain confirm gates are not.
What this product is
A Raspberry Pi product. Switchboard is being rebuilt as an appliance: a board host running on a small box, with agent seats running on other machines. That is the shape every decision should serve.
- The standalone host is primary.
src/standalone/bootstrap.ts— theswitchboard/npx CLI — is what actually runs on the Pi, on :7777, and is what a board deployment means. Measured: 182 MB RSS on a Pi 400 with no seats, so board-only fits 1 GB; board plus local agents wants 2 GB minimum, 4 GB comfortable. - One store, one host. One better-sqlite3 database owned by that host. Not libSQL (rejected), not a git-carried board (rejected). Other machines never open the database — they reach it over HTTP.
- Multi-machine means seats, not stores. A seat's startup command carries an
ssh/moshtransport prefix; the pty stays local and the agent process runs on the other box. - The VS Code extension (
src/extension.ts) is the legacy host. It still ships and still has to work, but it is no longer the thing being designed for. Do not describe this product as a VS Code extension.
Standalone and the extension MUST NOT diverge. NO EXCEPTIONS.
Both composition roots exist, so every feature must land in both. If you are planning a feature, the plan names both composition roots and its verification covers both. If you are implementing one, the diff touches both. "Extension first, standalone later" is not a plan — it is a divergence, and no gate catches it.
The trap is not verbs. bootstrap.ts's default: arm delegates every
unmatched verb to the provider, so verb-reachability audits always come back
green. The trap is composition-root wiring: service seams
(engine.setX(...)), options objects handed to shared services, and
Promise<void> callbacks where "never wired" and "working" are the same value.
Diff the two roots by hand. The seams each host wires are the audit — not the
verbs each host answers.
Precedent (2026-08). All four PlanIngestionEngine queue seams —
setQueueHeadResolver, setQueuePacingResolver, setQueueTeamMembersResolver,
setQueueEscalationRecorder — were wired in extension.ts only, a month after
standalone shipped. Consequently no queue watch was ever armed in the
standalone host: seat pacing was unreachable, dead seats were never re-staged,
and the queue stall backstop did not exist. Every gate stayed green, because
npm run standalone-parity:check is scoped to the browser read-back path, not
the composition root. The two roots had also drifted the other way — standalone
wires two seams the extension does not.
A fallback must never be indistinguishable from a real value.
On any read of configuration, identity, routing, or membership, a default that behaves exactly like a configured value turns a loud failure into a quiet wrong answer. No gate catches this: a fallback is a positive line of code that passes lint, compile and review while looking like care. It is the single largest source of reported bugs in this codebase.
Shipped examples, every one of which became a bug report: 'unknown' CLI family silently borrowing
Claude's 8000ms readiness ceiling instead of Devin's 20000ms, so every fix to the Devin timing was
invisible to the seat that needed it; || '/static/icons/nav-jet.svg', which made "no team has an
icon" look identical to "every team picked the same one"; catch { return {} } on a config load,
which reads a corrupt file as an unconfigured one; and a four-level startup-command lookup where
a stale value from a retired store wins and nothing records which store answered.
This is not a ban on defaults. On those four kinds of read, either:
- Tag it — return the source alongside the value (
{ value, source }), and log the source where it is used. "Which store answered?" must be answerable after the fact. - Fail loudly — surface the missing or corrupt config instead of substituting a plausible one.
Where a default is truly unavoidable, choose the value whose failure is visible or safe, never the one that is merely quiet — an unrecognised CLI waits on the longest boot ceiling, because guessing short breaks delivery and guessing long costs seconds.
Fallbacks on presentation paths (a label, a placeholder, an avatar) are fine. The test is whether a wrong value silently changes behaviour.
Build
- This deployment's board is served with
switchboard tailnet, notswitchboard local. Restarting it withlocalbrings up the wrong posture — the operator's board serves the tailnet (<host>.ts.net:7777, plus IPv4/IPv6 listeners on the tailnet IP) as well as loopback. If the host must be restarted, useswitchboard tailnet. - Treat
src/as the source of truth for review. Do NOT audit, check, or flagdist/staleness during reviews or verification — a staledist/is never the finding. dist/is not inert, though. The standalone host runs from it (node dist/standalone/cli.js, and theswitchboardCLI binary underdist/<platform>/), andtest:contract:pty-host-blackboxspawns the Go pty host from it. So "nothing is served fromdist/" is false — it is simply not what you review.- Contract suites run against
out/, notdist/: runnpm run compile-testsbefore anytest:contract:*script or you are testing the previous build.
Users & migrations
- The dividing line is whether the state shipped in a released version:
- State/files/settings that exist in any released version MUST be migrated on change: import before deleting, archive legacy files as
*.migrated.bakrather than unlinking, preserve unknown/legacy keys instead of dropping them, and never assume a prior migration "already ran" for the install base. - Features that have only ever existed in unreleased dev work can take clean breaks — no migrations, no compat shims.
- State/files/settings that exist in any released version MUST be migrated on change: import before deleting, archive legacy files as
- When unsure whether something shipped, assume it did and migrate — a no-op migration costs nothing; a missing one destroys user data.
- The install base is not recorded here, deliberately. This section used to open with "Published extension, ~4,000 installs", which is a marketplace fact about the legacy host and was being cited to justify migration work on a product that is being rebuilt as a Pi appliance. The rule above does not need a number: it turns on shipped versus unreleased, which is checkable from git. If you need the real install base for a sizing decision, ask — do not infer it from this file.
<!-- switchboard:agents-protocol:start -->- Plans reach the board on their own: a
.mdfile written to a designated plans directory is imported automatically by a watcher. Committing is irrelevant — untracked files import too. Never import a plan yourself. - Memo capture mode: while active, append each user message verbatim — do not
analyse, plan, or write code. Begin every reply with
[MEMO CAPTURE ACTIVE]. - Kanban questions: use the
query-kanbanskill. Displayed column labels differ from the stored IDs, so hand-written SQL silently returns nothing. - Writing a plan? Read plan-authoring-protocol.md.
<!-- switchboard:agents-protocol:end -->Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

