Repository navigation
feat(signals-dashboard): discover desks in *-desks group folders 🤖🤖🤖 - #6302
Conversation
Desks can now live in any top-level folder whose name ends in "-desks" (for example team-desks/), alongside desks/ and the legacy classroom/. Cairn scans every desk root in a stable order (desks, classroom, then group folders by name) and identifies each desk as "<group>/<desk>", so two groups can each hold a desk with the same name. - Stash/restore entries are keyed by desk id. Existing entries that hold only a desk name keep meaning desks/<name>. - When desks come from more than one root, the board pins escalations from every group in a section at the top, then shows a header per folder ordered by latest activity (folders without signals follow in scan order). A workshop that only uses desks/ renders as before. - Actions accept a deskId or a plain desk name; refresh, open_desk, and get_desk_path return each desk's group and deskId. - The Workshop TA and the desk-open, desk-journal, bench-read, signal-write, and workshop-create skills document group folders. - Bump signals-dashboard to 0.3.2 and the-workshop to 0.1.2. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a3e3bdc9-f091-4246-8b0f-3d3442cd59f2
…first signal Desks without a signal yet have no honestyGap or outcomeRating fields, and the summary bar filtered with !== null, so undefined slipped through: the average honesty gap became NaN and the badge title overcounted outcome signals. Only average finite gaps and count outcomes that are present. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a3e3bdc9-f091-4246-8b0f-3d3442cd59f2
🔒 PR Risk Scan ResultsScanned 13 changed file(s).
|
🚦 Submission status: 🛠️ Requires submitter fixesRisk tier: Why this tier
Automated checks
Action needed
Review
Commands
Updated for |
🧩 Canvas smoke test✅ Passed · 0 error(s), 3 warning(s)
Plugin
|
| Field | Value |
|---|---|
| Description | Real-time Workshop dashboard with agent signals, honesty calibration, cost-aware desk profiles, and fail-closed Local Delegation. |
| Author | jennyf19 — https://github.com/jennyf19 |
| License | — |
| Keywords | agent-signals, dashboard, multi-agent, coordination, canvas, local-delegation |
| Extensions | signals-dashboard |
| Materialize | ✅ |
| Install | ✅ |
Changed plugin files
plugins/signals-dashboard/plugin.json
Plugin the-workshop v0.1.2
| Field | Value |
|---|---|
| Description | Stop being the switchboard between your AI agents — direct a team. The Workshop puts long-running AI agents (desks) in the same room, on the same work, each with its own memory and history, sharing one workspace so you direct the work instead of relaying it. |
| Author | jennyf19 |
| License | MIT |
| Keywords | multi-agent, coordination, desks, persistent-memory, agent-signals, developer-experience |
| Extensions | signals-dashboard |
| Materialize | ✅ |
| Install | ✅ |
Changed plugin files
plugins/the-workshop/plugin.json
Extension signals-dashboard
| Field | Value |
|---|---|
| Registered by | signals-dashboard, the-workshop |
| Package | signals-dashboard 0.3.2 |
| Preview | 1024×1024, 31.7 KB |
| Modules | 5 (3 reachable from extension.mjs) |
| Files | 8 |
Permissions and capabilities (static analysis of modules reachable from extension.mjs)
- Spawns processes (node:child_process)
- File system access (node:fs)
- Network sockets / local server (node:http, node:net, ...)
- Host information (node:os)
- Outbound HTTP requests (fetch)
- Reads environment variables (process.env)
Warnings
- launch-profile.test.mjs: non-literal dynamic import cannot be analyzed safely (module is not reachable from extension.mjs)
- launch-profile.test.mjs: import "node:test" is not a Node.js builtin, host-provided package, or declared dependency (module is not reachable from extension.mjs)
- local-delegation.test.mjs: import "node:test" is not a Node.js builtin, host-provided package, or declared dependency (module is not reachable from extension.mjs)
Changed extension files
extensions/signals-dashboard/README.mdextensions/signals-dashboard/extension.mjsextensions/signals-dashboard/launch-profile.test.mjsextensions/signals-dashboard/package.json
Static checks compile modules without executing them. Minimum preview size is configurable with CANVAS_PREVIEW_MIN_WIDTH/CANVAS_PREVIEW_MIN_HEIGHT. Workflow run
🔍 Vally Lint Results
Summary
Full linter output |
There was a problem hiding this comment.
🟡 Changes recommended
Legacy name-only stash entries are incorrectly migrated only to desks/, causing unexpired stashed classroom desks to reappear as active after upgrading.
1 open issue
What changed in this PR
Extends Cairn’s workshop dashboard to discover desks in top-level *-desks/ folders alongside desks/ and classroom/, supporting grouped workstreams and same-named desks.
Changes:
- Adds group-qualified desk IDs, grouped rendering, pinned escalations, and group-aware actions and stash handling.
- Fixes the summary’s
NaNhonesty gap and adds regression tests. - Updates workshop guidance and bumps dashboard and workshop package versions.
| File | Description |
|---|---|
skills/workshop-create/SKILL.md |
Recognizes group folders during workshop setup. |
skills/signal-write/SKILL.md |
Documents signal paths for grouped desks. |
skills/desk-open/SKILL.md |
Explains group selection and ambiguous desk names. |
skills/desk-journal/SKILL.md |
Adds journal paths for grouped desks. |
skills/bench-read/SKILL.md |
Includes grouped desks in artifact discovery. |
plugins/the-workshop/plugin.json |
Bumps version to 0.1.2. |
plugins/signals-dashboard/plugin.json |
Bumps version to 0.3.2. |
extensions/signals-dashboard/README.md |
Documents discovery, grouping, IDs, and stash behavior. |
extensions/signals-dashboard/package.json |
Aligns extension version with the plugin. |
extensions/signals-dashboard/launch-profile.test.mjs |
Tests discovery, stash isolation, rendering, ordering, and gap calculation. |
extensions/signals-dashboard/extension.mjs |
Implements grouped desks and corrects summary calculations. |
agents/workshop-ta.agent.md |
Adds grouped-desk guidance for the Workshop TA. |
.github/plugin/marketplace.json |
Updates published plugin version metadata. |
Review effort: Balanced (auto)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a3e3bdc9-f091-4246-8b0f-3d3442cd59f2
…sk groups Stash entries written before desk groups hold only a desk name, and the old dashboard hid the desk of that name in desks/ and in classroom/. The migration mapped every such entry to desks/<name>, so a stashed classroom desk reappeared after upgrading. Map each one to every built-in root that holds the desk, falling back to desks/<name>. Entries that already carry a desk id are unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a3e3bdc9-f091-4246-8b0f-3d3442cd59f2
aaronpowell
left a comment
There was a problem hiding this comment.
The group-folder support and compatibility work are useful, but I found two issues to fix in extensions/signals-dashboard/extension.mjs. First, isDeskGroupName accepts names containing ;; the resulting full path reaches Windows Terminal's wt -d argument without the launch-safe validation used for desk names. Please apply the safe-name check to group roots or reject unsafe paths in the shared launcher. Second, readStash can write a snapshot after awaiting filesystem checks without holding withStashLock, so a concurrent page refresh can overwrite a restore. Please make reads side-effect-free and persist normalization only under the lock, with focused regression tests for both cases.
…indows Terminal Windows Terminal reads every ';' on its command line as a command separator, even inside an argument (microsoft/terminal#13264). Group folder names only pass the path-traversal check, so a desk under a folder such as a;b-desks/ could make `wt -d <path>` start a second command. The shared launcher now refuses to launch when any Windows Terminal argument holds ';', which also covers a workshop path with one, and the caller falls back to copying the path, as it already does for unsafe desk names. Discovery is unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 23af3266-c56b-4f37-a967-a13587283c2b
…t restore Page loads and the refresh action read the stash outside withStashLock, but readStash wrote its normalized list back after awaiting filesystem checks. A refresh that overlapped a restore could write its older snapshot last and stash the restored desk again. Reads no longer write: each read still drops expired entries and normalizes name-only ones, and only the locked stash and restore paths persist the list. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 23af3266-c56b-4f37-a967-a13587283c2b
|
@aaronpowell thanks, both are fixed, one commit each with a regression test that fails without it:
Mirrored in jennyf19/the-workshop#23. |
|
/rerun-checks |
|
🔁 No failed or incomplete checks to re-run.
The status comment updates when the checks finish. |
aaronpowell
left a comment
There was a problem hiding this comment.
Thanks for addressing the two requested fixes. The Windows Terminal launcher now refuses arguments containing ;, and stash reads no longer write back while refresh is in progress; the PR also adds focused regression tests for both. The group-qualified desk IDs, legacy stash handling, and updated Workshop guidance make the new folder layout usable without losing the existing workflow.



Pull Request Checklist
npm startand verified thatREADME.mdis up to date.mainbranch for this pull request.Description
Lets a workshop group its desks into top-level folders whose names end in
-desks(for exampleteam-desks/), next todesks/and the legacyclassroom/. Teams that keep several workstreams in one workshop can group them without losing them from Cairn.What changes:
desks/,classroom/and every top-level*-desks/folder, and identifies each desk as<group>/<desk>, so two groups can each have a desk with the same name.desks/looks and behaves as before.desks/andclassroom/.open_desk,get_desk_path,stashandrestoreaccept a desk id or a plain name.refreshandget_desk_pathreturn each desk's group and id.A separate commit fixes "gap NaN" in the summary bar. It appeared whenever a desk was still waiting for its first signal, because those desks have no gap value; the bar now averages only desks that have one.
Two review follow-ups, one commit each: the launcher refuses desk paths that hold
;, which Windows Terminal splits commands on, and stash reads no longer write, so a page refresh can't undo a concurrent restore.Testing
npm testinextensions/signals-dashboard: 38 passed, 1 skipped (a macOS-only test, run on Windows). The new tests cover discovery across folders, ignoring other folders, same-named desks in two groups, stash entries from before desk groups, grouped rendering, pinned escalations, activity order, the NaN fix, refusing a desk path with;(Windows-only) and a refresh that overlaps a restore, and each fails without its change.get_desk_path,stashandrestorework with desk ids and plain names.The same change is in the plugin's source repo: jennyf19/the-workshop#21, plus the stash fix in jennyf19/the-workshop#22 and the review fixes in jennyf19/the-workshop#23.
Type of Contribution