AI Agent Dashboard

A real-time desktop widget that tracks what your AI coding agents are doing.

View on GitHub
Home Claude Code HTTP API Development

Setup

Prerequisites

Install

git clone git@github.com:AnotherSava/tauri-dashboard.git
cd tauri-dashboard
npm install

Run from source

npm run tauri dev

Compiles the Rust backend, starts Vite on localhost:1420, and launches the native window. Frontend edits hot-reload; Rust edits trigger a rebuild on save.

Commands

Architecture

The app pairs a Rust backend (Tauri v2) with a Svelte 5 + Vite frontend rendered in a native WebView2 window. The Rust side owns all state and external I/O; the frontend is a pure view that subscribes to Tauri events and issues invoke-style commands for window control. External tools integrate via an embedded axum HTTP server on 127.0.0.1:9077, bypassing the frontend entirely.

The source-of-truth AgentSession state lives behind a Mutex in Rust. Three paths mutate it — the HTTP server, the per-session transcript watcher, and Tauri commands invoked from the Svelte UI — and every mutation funnels through state::apply_set or state::apply_clear so the sticky-label state machine is enforced in exactly one place.

Project structure

tauri-dashboard/
├── src/                                Svelte frontend (Vite)
│   ├── App.svelte                       top-level layout, subscribes to Tauri events
│   ├── main.ts                          mount entry point
│   └── lib/
│       ├── types.ts                     shared TS types and display helpers
│       ├── mockSessions.ts              dev-only fixtures (unused in release)
│       ├── api.ts                       invoke / listen wrappers
│       └── components/
│           ├── SessionList.svelte       list container, empty-state
│           ├── SessionItem.svelte       per-row rendering (pill, timer, tokens, label)
│           └── LimitBar.svelte          header 5h / 7d usage bar (segmented fill, percent + timer caps)
├── src-tauri/
│   ├── Cargo.toml                       Rust deps: tauri, axum, notify, tracing, serde, reqwest, chrono, open
│   ├── tauri.conf.json                  NSIS target, WebView2 bootstrapper, window config
│   ├── capabilities/default.json        capability-based permissions for the main window
│   └── src/
│       ├── main.rs                      entry; calls lib::run()
│       ├── lib.rs                       Builder: plugins, state, commands, setup hook
│       ├── state.rs                     AgentSession struct, apply_set sticky-label machine
│       ├── config.rs                    Config struct, load/save, ConfigState wrapper
│       ├── config_watcher.rs            notify watcher for config.json hot-reload
│       ├── commands.rs                  Tauri commands + event emitters
│       ├── http_server.rs               axum routes for POST /api/event
│       ├── log_watcher.rs               per-session transcript tailing + infer_state
│       ├── tray.rs                      TrayIconBuilder, menu handlers, autostart
│       ├── notifications.rs             1s-tick reconciler + Notifier trait
│       ├── telegram.rs                  reqwest-based Telegram Bot API client
│       ├── usage_limits.rs              Anthropic OAuth usage poller + refresh (5h / 7d buckets)
│       ├── auto_resize.rs               Up/Down content-fit window + Win32 resize lock + dark class brush
│       ├── label_policy.rs              shared (label, original_prompt) decision used by adapters
│       ├── adapters.rs                  adapter dispatch for /api/event payloads
│       ├── adapters/
│       │   └── claude.rs                Claude Code lifecycle classifier + chat-id derivation
│       └── logging.rs                   tracing subscriber → widget.jsonl + FrontendLogger for IPC log lines
├── integrations/
│   └── claude_hook.py                   thin Claude Code hook — forwards stdin payload to /api/event
├── docs/                                this site
└── .github/workflows/release.yml        CI: build NSIS installer on tag push

Where state lives at runtime

Architecture reference

Testing

Rust tests live inline in #[cfg(test)] modules next to the code they cover:

CI (.github/workflows/release.yml) runs Rust tests before bundling on every tag push, so a broken state machine can’t ship a release.