Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Add a monitoring dashboard to NanoClaw. Installs @nanoco/nanoclaw-dashboard and a pusher that sends periodic JSON snapshots.
.claude/skills/nanocoai-add-dashboard/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-07 | ✗→✓ | ▲ Improved | -4% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 10% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 28% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 72% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 24% | 0% |
Adds a local monitoring dashboard showing agent groups, sessions, channels, users, token usage, context windows, message activity, and real-time logs.
NanoClaw (pusher) Dashboard (npm package)
┌──────────┐ POST JSON ┌──────────────┐
│ collects │ ────────────────→ │ /api/ingest │
│ DB data │ every 60s │ in-memory │
│ tails │ ────────────────→ │ /api/logs/ │
│ log file │ every 2s │ push │
└──────────┘ │ serves UI │
└──────────────┘bashpnpm install @nanoco/nanoclaw-dashboard
Copy all three resource files into src/. The tests ship with the skill and run against the composed project — they're how you confirm the skill works and is wired in correctly.
.claude/skills/add-dashboard/resources/dashboard-pusher.ts → src/dashboard-pusher.ts
.claude/skills/add-dashboard/resources/dashboard-pusher.test.ts → src/dashboard-pusher.test.ts
.claude/skills/add-dashboard/resources/dashboard-wiring.test.ts → src/dashboard-wiring.test.tsdashboard-pusher.test.ts — behavior: starts the pusher, posts a real snapshot to a fake dashboard.dashboard-wiring.test.ts — the code edit in step 3: asserts (via the TS AST) that index.ts dynamically imports ./dashboard-pusher.js and awaits startDashboard() as colocated statements of main(), after DB init and before the boot-complete log. Delete or misplace the edit and this goes red.This is the skill's one integration point, and it's deliberately minimal and self-contained: all the startup logic lives in dashboard-pusher.ts, and the import is colocated with the call so the whole edit is a single block in one place — there's no separate top-of-file import to add (or to remember to remove).
Add this block inside main(), just before the log.info('NanoClaw running') line:
typescript// Dashboard (optional; no-ops without DASHBOARD_SECRET) const { startDashboard } = await import('./dashboard-pusher.js'); await startDashboard();
startDashboard() reads DASHBOARD_SECRET/DASHBOARD_PORT itself and no-ops if the secret is unset, so nothing else in core needs to change.
DASHBOARD_SECRET=<generate-a-random-secret>
DASHBOARD_PORT=3100Generate the secret: node -e "console.log('nc-' + require('crypto').randomBytes(16).toString('hex'))"
Run from your NanoClaw project root:
bashpnpm run build pnpm exec vitest run src/dashboard-pusher.test.ts src/dashboard-wiring.test.ts # behavior + wiring source setup/lib/install-slug.sh systemctl --user restart $(systemd_unit) # Linux # or: launchctl kickstart -k gui/$(id -u)/$(launchd_label) # macOS
Run build before the tests: it's what guards the @nanoco/nanoclaw-dashboard dependency. dashboard-pusher.ts reaches the package through await import('@nanoco/nanoclaw-dashboard'), so if step 4 was skipped, pnpm run build fails with TS2307: Cannot find module. The behavior test deliberately mocks that package — its startDashboard binds a real dashboard port, a side effect we don't want in a test — so the test alone would pass with the dependency missing. Build is therefore the leg that verifies the dependency is installed; keep it ahead of the tests in the validate step.
Once the service is restarted, confirm the dashboard is live:
bashcurl -s http://localhost:3100/api/status curl -s -H "Authorization: Bearer <secret>" http://localhost:3100/api/overview
Open http://localhost:3100/dashboard in a browser.
| Page | Shows | |------|-------| | Overview | Stats, token usage + cache hit rate, context windows, activity chart | | Agent Groups | Sessions, wirings, destinations, members, admins | | Sessions | Status, container state, context window usage bars | | Channels | Live/offline status, messaging groups, sender policies | | Messages | Per-session inbound/outbound messages | | Users | Privilege hierarchy: owner > admin > member | | Logs | Real-time log streaming with level filter |
DASHBOARD_SECRET matches in .envDASHBOARD_PORT in .envlogs/nanoclaw.log existsReverse the apply steps. Safe to re-run even if some pieces are already gone.
bashrm -f src/dashboard-pusher.ts src/dashboard-pusher.test.ts src/dashboard-wiring.test.ts pnpm uninstall @nanoco/nanoclaw-dashboard 2>/dev/null || true
Then, by hand, remove the single dashboard block the skill added to main() in src/index.ts (the // Dashboard (optional…) comment, the await import('./dashboard-pusher.js') line, and the await startDashboard(); call), and remove DASHBOARD_SECRET and DASHBOARD_PORT from .env.
bashpnpm run build
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 3,900 | 3,642 | -7% | 1 | 1 | 0% | 260 | 2,031 | +681% | 0 | 0 | — |
case-02 | fail→fail | 15,378 | 6,049 | -61% | 1 | 1 | 0% | 3,265 | 1,925 | -41% | 0 | 0 | — |
case-03 | fail→fail | 8,892 | 6,456 | -27% | 1 | 1 | 0% | 1,731 | 1,991 | +15% | 0 | 0 | — |
case-04 | pass→pass | 13,240 | 13,494 | +2% | 1 | 1 | 0% | 2,732 | 4,473 | +64% | 0 | 0 | — |
case-05 | pass→pass | 13,527 | 13,767 | +2% | 1 | 1 | 0% | 2,648 | 4,172 | +58% | 0 | 0 | — |
case-06 | pass→pass | 13,711 | 13,214 | -4% | 1 | 1 | 0% | 2,955 | 4,468 | +51% | 0 | 0 | — |
case-07 | fail→pass | 10,053 | 1,343 | -87% | 1 | 1 | 0% | 1,714 | 1,638 | -4% | 0 | 0 | — |
case-08 | pass→pass | 7,789 | 1,864 | -76% | 1 | 1 | 0% | 1,293 | 1,716 | +33% | 0 | 0 | — |
case-09 | fail→pass | 9,302 | 1,797 | -81% | 1 | 1 | 0% | 1,640 | 1,802 | +10% | 0 | 0 | — |
case-10 | fail→pass | 10,325 | 4,785 | -54% | 1 | 1 | 0% | 1,864 | 2,385 | +28% | 0 | 0 | — |
case-11 | fail→pass | 5,612 | 1,907 | -66% | 1 | 1 | 0% | 1,046 | 1,796 | +72% | 0 | 0 | — |
case-12 | fail→pass | 10,861 | 4,389 | -60% | 1 | 1 | 0% | 1,891 | 2,350 | +24% | 0 | 0 | — |
case-13 | fail→pass | 7,468 | 1,491 | -80% | 1 | 1 | 0% | 1,243 | 1,696 | +36% | 0 | 0 | — |
case-14 | fail→pass | 6,850 | 1,889 | -72% | 1 | 1 | 0% | 1,168 | 1,710 | +46% | 0 | 0 | — |
case-15 | pass→pass | 8,249 | 5,468 | -34% | 1 | 1 | 0% | 1,540 | 2,464 | +60% | 0 | 0 | — |
case-16 | fail→pass | 7,693 | 2,806 | -64% | 1 | 1 | 0% | 1,608 | 1,929 | +20% | 0 | 0 | — |
case-17 | fail→pass | 10,074 | 1,994 | -80% | 1 | 1 | 0% | 1,872 | 1,769 | -6% | 0 | 0 | — |
case-18 | fail→pass | 9,031 | 1,829 | -80% | 1 | 1 | 0% | 1,496 | 1,708 | +14% | 0 | 0 | — |
case-19 | pass→pass | 3,823 | 1,688 | -56% | 1 | 1 | 0% | 729 | 1,692 | +132% | 0 | 0 | — |
case-20 | fail→pass | 9,134 | 2,251 | -75% | 1 | 1 | 0% | 1,588 | 1,817 | +14% | 0 | 0 | — |
case-21 | fail→pass | 10,152 | 1,779 | -82% | 1 | 1 | 0% | 1,753 | 1,713 | -2% | 0 | 0 | — |
case-22 | fail→pass | 10,033 | 2,545 | -75% | 1 | 1 | 0% | 1,608 | 1,864 | +16% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 20 counted toward the lift figure. The other 2 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +59 percentage points is the difference between those two pass rates over the 20 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.