Releases: cristianonescu/dashd
Release list
v0.1.12
New feature
Dedicated CPU / Memory / GPU / Network pages. The catch-all
"System" page is gone; each resource now has its own focused screen
with the full picture, no overlap. The Electron Live tab gets matching
cards.
CPU page
Per-core utilization bars + average headline, load average (1 / 5 /
15 min), current vs max frequency, CPU temperature, top 3
CPU-consuming processes, battery (when present).
Memory page
Memory-pressure bar (the cache-excluded "would-this-swap?" metric),
used / total GB, swap usage, breakdown by active / inactive / cached,
top 3 RAM-consuming processes, primary disk usage.
GPU page (new)
Cross-platform best-effort detection:
- macOS (Apple Silicon + Intel) via
ioreg -a -r -c IOAccelerator
— IOAccelerator'sPerformanceStatisticsdict, parsed with
plistlib. No sudo required. Apple Silicon has unified memory, so
we show the currently allocated MB with no fixed total. - NVIDIA (any OS) via
nvidia-smi --query-gpuCSV — util, VRAM,
temperature, power. - Linux AMD via
/sys/class/drm/card*/device/gpu_busy_percent+
mem_info_vram_*.
When no GPU is detectable, the page renders a friendly "GPU stats not
available" with a user-facing reason ("NVIDIA driver tools are not
installed", "macOS did not expose GPU statistics", etc.) — not
jargon.
Network page (new)
Active outbound interface (discovered via the kernel route table),
current down / up throughput, per-interface table with cumulative
totals since the OS counters last reset (typically boot).
Wire-protocol additions
system.* gains cpu_freq_mhz, cpu_freq_max_mhz, load_1m/5m/15m,
ram_swap_*, ram_active/inactive/cached_gb, and an ifaces[] array
of the top-3 interfaces. New top-level gpu block with
{available, vendor, name, util_pct, vram_used_mb, vram_total_mb, temp_c, power_w, count}. Full schema example in docs/protocol.md.
Migration
The firmware page enum bumped from 8 → 12 IDs. PAGE_SYSTEM (id 1) is
kept as a reserved/deprecated slot and masked from display, so the
v0.1.11 pages_enabled_mask / pages_order blobs in NVS remain valid
across the upgrade — bit 1 is silently stripped at restore time, the
8-byte porder blob is detected and falls back to defaults. No
manual reset is needed; just update the firmware via Settings →
Updates.
Upgrading
- Pages live in firmware — flash via Settings → Updates →
"Update firmware". - GPU collector + cards live in the agent + UI — updating the
Electron app brings both.
After flashing, the device immediately picks up the 4 new pages. Use
Settings → Pages to reorder them and the auto-advance setting
from v0.1.9+ still cycles through whatever you've enabled.
Other notes
No removals — the system.* field shape stays backwards compatible
(legacy cpu_pct, ram_pct, net_up/down_kbps continue to be
emitted alongside the new fields). Old v0.1.11 firmware on a v0.1.12
agent keeps rendering the same metrics it always did.
Diagnosed and reviewed across multiple rounds with the codex agent —
including the implementation pass that caught the deprecated-page
counting bug, the sparse-id "all enabled" sentinel, line-scraping
ioreg fragility, and jargon error strings. All 3 firmware envs
compile clean. 176/176 agent tests pass (11 new GPU tests).
v0.1.11
Bug fixes
Two related bugs that only surface when you have some pages disabled
in Settings → Pages.
Bug A: footer "X/Y" counter was wrong with pages hidden
The page indicator at the bottom of the screen used the raw 8-slot
total as the denominator and the slot index as the numerator. So a
user with 5 pages enabled would see e.g. "6/8" instead of "3/5".
Fix: two new helpers in firmware/src/main.cpp —
enabled_page_count() and enabled_ordinal_for_slot(slot) — count
and locate the current slot among enabled pages. The footer now reads
correctly regardless of which pages you've disabled.
Bug B: title and content disagreed during/after page transitions
When you reordered pages or disabled some of them, the transition
animation's final frame indexed kPages[s_to_slot] treating a slot
index as a page id. With a non-identity page order, the wrong page's
title and renderer ran during the transition.
Reported symptom: title says "Calendar" but the content shows the
System page's "TOP CPU" rows + a leftover Tips "SUGGESTIONS" header —
three pages worth of stuff overlapping on one screen.
Fix: removed the inline final-frame draw in both wipe and
home-zoom transitions. The transition now just clears the content
band and hands off to the main loop's draw_all(), which already
does the correct slot→page-id resolution via page_id_at_slot() and
uses the fixed footer helpers. Eliminates the entire class of
"draw differently in transition vs. steady-state" bug.
Upgrading
The fixes live in firmware. Update via Settings → Updates → "Update
firmware". Your existing pages config, auto-advance preference,
theme, thresholds — all preserved.
After flashing, disable a few pages from Settings → Pages and watch
the footer counter update correctly + page transitions land on the
right page.
Other notes
No protocol changes, no Electron UI changes, no agent changes. Pet
install, auto-advance, Anthropic OAuth — everything from v0.1.10
continues to work identically.
Diagnosed jointly with the codex agent. All 3 firmware envs compile
clean. 165/165 agent tests pass.
v0.1.10
dashd v0.1.10
Desk widget for developers. A Python agent on your computer collects developer-relevant metrics and streams them to an ESP32-C3 driving a 240×320 ST7789V display — over USB-CDC, Bluetooth LE, or auto-switching between the two. A single tactile button cycles pages.
This is the consolidated v0.1.10 release: everything that landed across v0.1.1 → v0.1.10 in a single coherent description, with the latest binaries attached.
Downloads
Desktop app
| Asset | Platform |
|---|---|
dashd-0.1.10-arm64.dmg |
macOS (Apple Silicon) |
dashd-0.1.10-x64.dmg |
macOS (Intel) |
dashd-0.1.10-x64.exe |
Windows (x64) |
dashd-0.1.10-x86_64.AppImage |
Linux (any distro, portable) |
dashd-0.1.10-amd64.deb |
Linux (Debian / Ubuntu) |
Firmware (ESP32-C3)
| Asset | Description |
|---|---|
dashd-firmware-v0.1.10-ble.bin |
Full build: USB-CDC + Bluetooth LE |
dashd-firmware-v0.1.10-usb.bin |
USB-only build (smaller, no BLE) |
Auto-update metadata
latest-mac.yml, latest-linux.yml, latest.yml, and the .blockmap files are consumed by electron-updater — you don't need to download them manually.
Highlights
Connectivity
- Bluetooth LE transport — cable-free, 6-digit code pairing shown on the device, trusted-device list, auto-reconnect, log/event forwarding identical to USB. Pick
cable/bluetooth/autofrom Settings → Connection. - USB-CDC at 460800 baud — point-to-point, no driver needed (native USB Serial/JTAG on the ESP32-C3 SuperMini).
- Sticky agent_status replay — the Electron app sees the device immediately on launch even when it was already plugged in (fixed in v0.1.7).
Display
- 8 firmware pages — Home, System, AI Spend, Dev Flow, GitHub, Calendar, Messages, Tips. Reorderable, individually enable-able, persisted in NVS.
- Auto-advance page cycling (default ON, 8 s sequential) — the device cycles through enabled pages on a timer. Toggle, change interval (3–60 s), or switch to randomized Fisher-Yates order from Settings → Pages → Auto-advance. A button press or host page jump resets the countdown so you always get the full interval to read whatever you just selected.
- Animated pet overlay — Claw'd by default, reacts to commits / meetings / CI / system load. Install new pets from the on-device codexpets.net catalog.
- Pet install end-to-end working — agent awaits the device's
pet_install_startedACK before streaming chunks; CDC RX buffer sized for the 8-chunk burst; LittleFS partition probed at runtime so installs work on every flash-vintage device (littlefslabel for v0.1.2+ flashes, falls back tospiffsfor v0.1.1 flashes that have been OTA-updating since).
AI usage accuracy
- Anthropic OAuth Usage API (opt-in, Settings → Privacy) — when enabled, dashd reads your local Claude Code OAuth token and calls Anthropic's
/api/oauth/usageendpoint every 60 s. Session %, Weekly %, Sonnet %, Extra Usage all match Claude.ai exactly because they ARE Claude.ai's numbers. Pace metric ("on track / behind / far behind"),will_last_to_resetprojection. Token held in memory only, never logged or persisted; macOS Keychain integration via bundledkeyring. - JSONL-derived usage (always on, fallback) — ccusage-style 5h block segmentation, deduplication by
(message_id, request_id), LiteLLM-backed per-model pricing with daily refresh. - Tray popover + Usage tab — at-a-glance gauges in a frameless tray panel, deep-dive in the main window. Burn-rate projection, top projects by token count, weekly totals.
- Codex tokens via cumulative-delta diffing — per-session deltas computed from
token_countevents; persisted state in~/.config/dashd/codex_state.json.
Auto-update
- Electron app self-updates via
electron-updater(6-hour periodic check + manual via tray menu + Settings → Updates). DMG + ZIP for mac, NSIS for Windows, AppImage + .deb for Linux. - Device firmware updates from the same release page — agent downloads the matching
-ble.binor-usb.bin, streams it over the active transport, the device flashes the inactive OTA slot, verifies SHA256, flips the boot pointer, and reboots. Fullscreen progress overlay on the device. Auto-rollback if the new image fails to come up cleanly viaesp_ota_mark_app_valid_cancel_rollback(). - Dual-slot OTA partition layout — two 1.5 MB app slots + 0.8 MB LittleFS for pet bundles + NVS for prefs + coredump for panics.
Electron UI
- Live view + Usage tab + full Settings — drag-to-reorder pages, color-zone editor, text-size sliders per role, threshold sliders, brightness, title-bar + footer visibility, screen rotation.
- VSCode-style dockable logs panel — bottom-right toggle, overlays any tab, filterable by level. Captures both agent logs and device firmware logs.
- Contextual hint layer — every control has a
data-hinttooltip; hover anywhere in Settings to see what it does and what it persists. - Menu-bar / system-tray icon — restart, reload config, reset device prefs, autostart toggle, dynamic update controls. Tray-popover shows current usage at a glance without opening the main window.
Collectors
8 active + 3 stubs:
- System — CPU per-core, RAM (pct + pressure), disk, network, battery, temp, top processes by RAM/CPU.
- Claude Code — tokens today, cost today, 5h block progress (elapsed + budget %), burn rate, projected cap-hit time, per-model breakdown, weekly totals, top projects.
- Codex — tokens today, block %, reset time, session active.
- Git — branch, commits today (filtered by user email), LOC added/removed, minutes since last commit.
- GitHub — PRs awaiting review, CI failures (24 h), unread notifications. Needs
GITHUB_TOKEN. - Microsoft Calendar (Graph API) — next event, time-to-next, today's remaining events.
- Email (IMAP) — unread count from Gmail or any IMAP host. Needs
DASHD_EMAIL_PASSWORD. - iMessage (macOS only) — unread count from the chat DB. Needs Full Disk Access.
- Stubs — Slack, Teams, WhatsApp (always return null today).
Notable bug fixes addressed in this consolidated release
- Pet install broken across all v0.1.2+ devices — LittleFS partition label mismatch silently failed every mount call. Now probed at runtime; works on both v0.1.1 and v0.1.2+ partition layouts.
- CDC RX buffer overflow — 8 KB buffer overflowed mid pet-install burst; bumped to 32 KB.
- Anthropic OAuth Keychain path silently broken —
keyringlibrary and backends missing from the packaged binary; now bundled. - Device shows disconnected at launch — sticky agent_status event replay on IPC subscribe; UI sees the link state immediately.
- 5h block elapsed stuck at 100 % — ccusage-style block segmentation walks all timestamps in the last 24 h.
- JSONL re-read dedup — fallback chain
msg.id → uuid → requestId → (timestamp,in_tokens,out_tokens)prevents double-counting.
First-launch notes
- Unsigned binaries — macOS Gatekeeper / Windows SmartScreen will warn the first time:
- macOS: right-click the app → Open → confirm.
- Windows: SmartScreen → More info → Run anyway.
- macOS prompts for Bluetooth permission the first time you scan — required for BLE.
- macOS prompts for Full Disk Access for iMessage — required by the chat DB on modern macOS.
- Set
GITHUB_TOKEN+DASHD_EMAIL_PASSWORD(and optionally Microsoft Graph creds) to wake the network collectors. See README → Network collector setup.
Flashing firmware (first time)
esptool.py --chip esp32c3 write_flash 0x10000 dashd-firmware-v0.1.10-ble.binOr with PlatformIO: cd firmware && pio run -e dashd_ble -t upload.
After the first USB flash, all subsequent firmware updates can happen OTA from Settings → Updates → Device firmware → Update firmware.
Full build, wiring, BLE-pairing, and auto-update documentation in the README.