Skip to content

Releases: cristianonescu/dashd

v0.1.12

Choose a tag to compare

@cristianonescu cristianonescu released this 23 May 16:53

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's PerformanceStatistics dict, 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-gpu CSV — 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

Choose a tag to compare

@cristianonescu cristianonescu released this 23 May 16:07

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

Choose a tag to compare

@cristianonescu cristianonescu released this 23 May 14:37

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 / auto from 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_started ACK 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 (littlefs label for v0.1.2+ flashes, falls back to spiffs for 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/usage endpoint 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_reset projection. Token held in memory only, never logged or persisted; macOS Keychain integration via bundled keyring.
  • 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_count events; 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.bin or -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 via esp_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-hint tooltip; 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 brokenkeyring library 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 infoRun 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.bin

Or 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.