[ Wiki ]

Byte

Claude Code, Codex, OpenCode and Superset each leave a different trail. Byte 2.2.5 keeps their identities and capabilities distinct, then brings live activity, history, cost, decisions and outcomes into one workspace. The numbers drive the pictures, and every chart keeps its exact records available.

Local-first · Organisation-ready · No background inference

Node.js ≥ 20 Express 4 React 18.3 TypeScript 5.7 D3 7 SQLite (WAL) WebSocket Vite 6 Four integrations MCP · 30 tools VS Code Docker Helm Azure Bicep Prometheus OpenAPI 3.0 Python statusline Proprietary

[ 01 · Start here ]

How it works

Byte uses one adapter contract for detection, capabilities, collection, history, configuration, usage and supported execution. Claude Code uses hooks and transcripts; Codex uses trusted lifecycle hooks and supported App Server methods; OpenCode uses a Byte-owned plugin and server SDK; Superset uses its supported CLI and underlying agent adapters. Reconciliation preserves native identity and prevents duplicate sessions.

How one event reaches the screen A supported coding agent emits a native event. Its Byte adapter normalises the event before the server writes it to SQLite and pushes it to the browser over a WebSocket. Persisted native history is reconciled separately to recover activity that the live path did not report. Native agent Server The screen Native history four adapters Express + SQLite React + D3 on disk Byte adapter native event POST normalised activity push over /ws persisted sessions, messages and usage missed by the live path
Native events carry the live path. Reconciliation fills in what that path never saw.

Claude Code's eight hooks

npm run install-hooks writes eight entries into ~/.claude/settings.json. Five take a "*" matcher: PreToolUse, PostToolUse, Stop, SubagentStop, Notification. Three take none: SessionStart, SessionEnd, UserPromptSubmit. The merge is idempotent: an existing Byte entry is replaced in place, and the file is only rewritten when the bytes would actually change.

What Claude Code's hooks miss

Some things emit no hook at all: /compact, and the tools a subagent runs inside itself. Those are recovered by reading the session transcripts under ~/.claude/projects, so the charts are drawn from what happened rather than from what was reported. Live rows and imported rows are written through the same turn key, backed by a unique index, so an overlap is a no-op instead of a duplicate. An Esc cancel is caught separately, by a watchdog that reads the interrupt marker Claude Code leaves in the transcript.

[ 02 · Start here ]

The screens

Six primary destinations organise the workspace: Home, Work, Sessions, Insights, Library and Settings. Existing detailed routes and shortcuts remain available. People, devices and administration appear only for authorised organisation roles.

The session mark

One session, one line. It is the same drawing in a table row, on a card and at full width, and it is the thing to learn first, because it appears everywhere else.

The session mark and what each channel means A horizontal line stands for one session. Its length is how long the session ran and its thickness is how many tokens went through it. Shorter lines stacked underneath show how many agents were alive at the same time. A small tick out of the top edge marks a compaction, and a vertical bar through the whole mark marks an interruption. Thickness, tokens Notch, a compaction Bar, an interruption Strands, agents alive at once 1h 12m Length, how long it ran
The five channels of the session mark. A key on screen names every one in a plain sentence.

Both scales are logarithmic over fixed absolute domains, so the same session draws at the same size no matter what you have filtered to. Length runs from one second to thirty days. Thickness runs from a thousand tokens to a hundred billion. Eight decades, chosen by measurement: across ten real sessions on a 2 to 14 pixel stroke, a linear scale resolved 2 of 10 distinct weights, square root 5 of 10, and log 9 of 10.

The mark never claims more at a large size than it can support at a small one. In a table row, where twenty-one strands will not fit in twenty pixels, the stack collapses into a single stepped envelope rather than drawing eight strands and calling them twenty-one, and the envelope is stepped, never smoothed, because a curve between two buckets would draw agent counts that never existed. At full size the stack draws at most twelve rows and letters the rest (up to 61 agents at once, 12 drawn). Sessions with no tools and no subagents, most sessions in a real database, all draw as one short identical tick, because that is what they are.

The time spine

A ribbon pinned under the status bar, on every screen. It shows where your events sit in time, and dragging it moves the whole app. Arrow keys pan, up and down zoom, Home shows everything, End goes live. It goes inert, dimmed and unfocusable, on Settings, Agent Config and Run, where a time window means nothing, but it stays mounted so the page geometry never jumps.

Its axis is warped on purpose. Most minutes hold nothing: measured against the live database on 8 August 2026, 2,501 of 11,677 minutes held any event at all, 21%, so a linear axis would spend four fifths of its travel on dead air. Empty stretches collapse instead, the way a stock chart skips weekends. Nothing is ever stretched, only capped, so a dataset with no long gaps gets an exactly linear axis and the warp costs nothing. Each collapsed stretch is drawn as a dashed rule and lettered with the time it stands for, and the live density figure sits in the rail beside it.

/

Overview

The home screen is a board you arrange. Tiles are dragged on a twelve-column grid; the layout is pure CSS, so nothing is measured until you pick a tile up. It ships already arranged, and the empty canvas that sinks every build-your-own dashboard is only reachable by deleting every tile, at which point the screen offers the default back. The fixed arrangement it replaced is still there at /overview, with twelve lenses covering the fleet and system health.

/kanban

Agent Board

Two views behind a toggle that remembers your choice. Agents has four columns: working, waiting, completed, error. Sessions has five, adding abandoned. Each column scrolls on its own and pages ten at a time. The yellow waiting column is the useful one: it flags what is sitting on you rather than on the machine. Live refresh is coalesced at 300 ms, because three quarters of hook events land closer together than that.

/sessions

Sessions

Every recorded session, paginated on the server so each page fetches only its slice. Free-text search, a searchable multi-select directory filter, sort by time, duration or price, and status chips. The columns are Session, Shape, Status, Last active, Duration, Agents, Cost and Directory, Shape being the session mark at its inline size, so you can read a page of sessions as a page of drawings.

/sessions/:id

Session

Four tabs, and the open one lives in the query string so any view is a link. Agents leads with the mark at full width, then counts, the agent tree with subagents expanded or collapsed, and a cost breakdown. Conversation is the transcript. Timeline is the paged event list. Replay plays the session back. A banner appears when the session is waiting on you in the terminal.

/activity

Activity

The event stream as it arrives. Server-driven filters, and a fixed column grid: time, status, origin, tool, age, link, so a long tool name cannot shift the columns right of it. Click a row to expand its payload. Pause is real: incoming frames are buffered and counted rather than repainting under you, and every hold is written to an attention log you can read later in Settings.

/analytics

Cost & Usage

Five readouts sharing one rail, a 52-week activity heatmap sized so the year fills its panel exactly, and a 30-day column chart beside it. Below, five tabs: token analytics, cost analytics (the default: daily trends, cost by model, cost by weekday, and the priced-feature breakdown), workflow intelligence, productivity, and operations. While the data loads the chart region shows skeletons shaped like the charts, so the page never flashes a zeroed axis.

/workflows

Orchestration

Ten charts of what your agents did to each other, six headline figures above them, a runs panel beside them and a per-session drill-in below. One status filter (active, completed or all) applies to every chart at once, and the whole set exports as JSON. Every chart carries an info popover: what it shows, how to read it, why it matters. The full list is in the table below.

/run

Run

Start or resume a session from the browser and watch it stream. Two modes, conversation or one-shot. You choose the prompt (with @-file completion), working directory, model, permission mode and thinking effort. Output renders as a chat stream with collapsible tool calls, a live context meter, and cost and duration in the footer. An active-runs switcher attaches to anything already in flight. Built-in slash commands stay in the terminal: they mutate CLI-only state.

/cc-config

Agent Config

Twelve tabs over what Claude Code has actually got on disk: skills, subagents, slash commands, memory, plugins, marketplaces, MCP servers, hooks, keybindings, settings and output styles, filtered by scope. Each entry names the exact file it came from, and secrets in MCP URLs and headers are redacted. You can edit the low-risk text artifacts, and every write takes a timestamped backup first. Plugins, MCP servers and settings stay read-only, because the running CLI writes them concurrently.

/record

The Record

What you asked for, what it cost, what it produced, one user turn at a time. Every other screen is a control room answering "what is happening now". This one answers "what did I build", so it is laid out as a document you read: the ask is the headline, in your own words, and the telemetry is the subtitle under it.

/compare

Compare

Two sessions read as a difference rather than as two sets of totals. The first is the baseline and the only column showing raw totals; every other column is value, delta and ratio, because a reader comparing two costs is doing arithmetic the page should have done. The selection lives in the query string, so any comparison is a link.

The ten orchestration charts

Chart What it draws
Orchestration DAG Which agent spawned which, as a four-column directed graph. Edge width scales with how many times that spawn happened. The agent-type column is split in two so recursion draws as a forward edge instead of a loop.
Tool execution flow A Sankey diagram of tool-to-tool transitions. A tool that appears on both sides is split into a source node and a target node, because a Sankey collapses self-loops.
Agent collaboration network A force-directed graph of agent types that run in sequence. Node radius is the square root of that type's total runs; edge width and its Nx label are how often the pair co-occurred.
Model delegation flow Which model handed work to which, main models on the left and subagent models on the right, grouped by family. Edges are uniform width on purpose: the only domain available would be the three counts on screen. One model degrades to four figures rather than a one-bar bar chart.
Concurrency timeline A lane per agent type, where the track is the session's own duration and the bar spans where in it that type typically runs. Fill opacity carries sample size. Below it, how much real time ran with exactly N subagents alive.
Session complexity scatter Duration against agent count, both axes logarithmic, bubble area proportional to tokens, colour by outcome. Log because most sessions have exactly one agent and a linear axis draws every one of them on the same line. Click a bubble to drill in.
Subagent effectiveness A card per subagent type: a success ring, the type's sessions and average duration, and a seven-column weekday sparkline.
Error propagation map Where errors cluster by depth in the agent hierarchy, and which agent types are error-prone. Depth is an ordinal severity ramp, so a session-root error is the loudest mark and a deeply nested one the quietest. Nothing errored gives you a green all-clear, not an empty chart.
Compaction impact A histogram: how many sessions compacted exactly k times. One series, so one gradient rather than categorical hues.
Workflow patterns Agent sequences that repeat, ranked by how often. Expanding one gives a rule-derived description, deterministic, so the page can never state something the data does not support.

Above them sit six figures: average agent depth, average subagents per session, agent success rate, most common flow, average compactions and average duration. Beside them, a runs panel for the fleets spawned by the Workflow tool. Those emit no hooks, so they are reconstructed from the run journals left on disk.

[ 03 · Start here ]

Settings

Eleven panels behind a sticky "jump to" rail that follows your scroll, at /settings.

Panel What it controls
Appearance Theme (system, light, dark), accent colour, density
Model pricing Pricing rules matched by glob pattern: input and output rates, cache-write at five minutes and one hour, fast input and output, and introductory rates with an end date. Unpriced models are called out. Reset to defaults is one button
Hook configuration Whether the eight hooks are installed and complete, and a reinstall action
Session data directory Where transcripts are read from
Import history Four ways in: rescan ~/.claude/projects, scan any absolute folder, upload JSONL or an archive, or restore a backup export
Remote data sources A global data scope (all machines, local only, or a chosen set) and the SSH sources themselves: add, test, sync, enable, and delete with a choice of purging the imported data or keeping it
Cody Show or hide the corner companion
Notifications Browser permission, a test notification, and per-event toggles for new session, session complete, session error and subagent spawned
Alerts Rules, channels (webhook targets with a setup guide per provider) and activity, plus the attention log the Activity screen writes to
Data management Database size and counts, session cleanup with abandon-after and purge-after thresholds, and a danger zone behind an explicit confirmation
About Version, UI build, uptime, Node.js version, platform, connected clients

Export sits in the page header: it is the counterpart the backup-restore import mode reads. Every write reports through a toast with a pending state.

Remote data sources

A remote source is another machine you can read over SSH. Byte mirrors that machine's projects tree into a per-source staging directory with scp, then runs the same importer it uses for local history, so remote sessions line up with local ones exactly. Authentication defers entirely to your own SSH stack: ~/.ssh/config, your agent, your keys, your known_hosts. Byte stores no secrets; a host is an ssh destination and nothing more. External commands run with an argument array and no shell, and an unknown host key fails the sync.

[ 04 · Run it ]

Quick start

Byte 2.2.5 and upgrading

Download Byte 2.2.5 desktop applications and SHA256 checksums from the 2.2.5 release page . Windows has an installer and a portable build, macOS has separate Apple Silicon and Intel disk images, and Linux has a deb package and an AppImage. Choose the package for your machine.

Windows and AppImage installations check for updates in the application. On macOS, download the new disk image and replace Byte in Applications. Existing records and enrolment remain in the application data directory. Keep that directory when uninstalling or replacing the app.

New installations use dark mode and signal orange. Upgrades preserve your saved theme, density and accent; signal is an additional choice in Settings. Organisation device codes connect a reporting machine to an organisation. They remain distinct from an application licence.

Byte 2.1 preserves your account, records and preferences. To invite a new account, add its email in Organisation, use the pending member's Invitation button, and share that private invitation with the named recipient. They paste it when creating their account or signing in. Invitations expire after 24 hours and can be accepted once.

Keep progress with Byte 2.2

Open a task from Work and define its observable outcomes. Checks capture the command, code revision and relevant environment. Verified, Failed, Needs judgment and Not checked are distinct states. A relevant code or dependency change makes prior evidence stale.

Review a requirement change before saving. Delivery to an agent is separate, and each attempt shows the instruction revision it has acknowledged. Record an investigation with its current question, observations, rejected approaches and next experiment. Facts and hypotheses remain separate.

Keep a useful fix as a lesson. It becomes verified only when its regression check fails on the original revision and passes on the correction. Reuse requires applicable paths and reviewed context. Sharing a lesson does not share its source conversation.

Prepare selected Git text changes in an isolated workspace. Review dependencies and checks, then apply only if the destination is still the reviewed revision. Unsupported file types, ambiguous ownership and inseparable edits require manual resolution. Byte does not reverse external service or database writes.

Max includes combined-task rehearsal and bounded automatic recovery. Automation starts disabled. Enabling it requires a reviewed project grant, supported native controls and visible attempt and time limits. The defaults allow at most two attempts and fifteen minutes. Cancel or disable without losing the original workspace; applying a candidate remains a separate approval.

Hosted Byte can inspect authorized synchronized evidence and author permitted private notes. Run local checks and prepare candidates on the connected local installation. Deploy compatible server and licence metadata before upgrading collectors. Back up existing data and verify a restore before production migrations.

What 2.1.3 repairs

Collection health now distinguishes recorded live events from history. Child-agent inspection, integration-aware pricing, cost grouping, theme switching, compact density and machine setup are improved. Existing records and preferences are retained. External Codex hook delivery is still under investigation; Byte-managed execution has verified live updates. Native execution also requires the corresponding application's installation, authentication and account permissions.

What 2.1.2 repairs

Integration and machine scope now reach orchestration details and model pricing. Codex history imports in bounded pages. Review live hooks with /hooks after connecting. Settings saves zoom from 75% to 150%; existing themes and data stay in place. Cody's optional panel includes its cat companion.

What 2.1.1 repairs

Integration lists and drill-throughs keep the selected agent, host and data source together. Task attachments require matching ownership and the actual run/session link. Existing external sessions, resumed sessions and legacy IDs remain supported when they belong to the task.

Migration 34 adds missing tasks.source storage, including databases that already recorded migration 33. Existing source values, task records and execution grants stay intact. For stored imported tasks, a source is recovered only when every linked session agrees and matches the task's agent and host. Missing or conflicting evidence stays unresolved and cannot start local work.

Native cost reports distinguish measured charges, token-based estimates and missing data. A captured zero remains zero; an absent measurement stays unavailable. Lifetime totals without a usable measurement date remain undated and do not become daily chart points or period-budget spend.

Compact navigation and controls use the correct Claude Code, Codex, OpenCode and Superset logos. Integration names stay visible so the current view is easy to identify.

Connect your coding tools

Open Settings, then Integrations, to connect Codex or OpenCode on the device where it runs. Review Byte's Codex hooks in the native application. OpenCode uses a Byte-owned plugin; explicit managed runs use an authenticated local service. Superset exposes its supported workspace and underlying-agent controls separately from native chat.

Connect and managed runs check the installed CLI's required interfaces before changing configuration or starting work. A different version can be used when those interfaces are present. Reading history does not start or resume an agent.

The four workspace switches change what you inspect while connected collectors continue recording. Existing Claude Code collection stays available. Native run ownership never changes merely because you switch views, and active conversations are not transferred between agents.

Library items start private. Preview the audience and content before sharing. Budget alerts warn without stopping independent agents. Back up data before upgrading a hosted cell and deploy the compatible server before enabling new collectors.

Requires Node.js 20 or newer.

Step 1

Install

npm run setup installs the server, client and extension dependencies and links the byte CLI

Step 2

Connect

Open Settings → Integrations and connect the agents installed on this machine. Claude Code hooks can also be installed with npm run install-hooks

Step 3

Start

npm run dev brings up the server on 4820 and the client on 5173

Step 4

Start work

Run a connected agent: supported live events and history appear in its workspace

bash
npm run setup           # dependencies, and link the byte CLI
npm run install-hooks   # forward Claude Code events to Byte
npm run dev             # server on :4820, client on :5173

# production: one process serving everything on :4820
npm run build && npm start

# something on screen straight away
npm run seed            # three demo sessions

The server installs Claude Code hooks itself when you run it directly on the host. Codex and OpenCode are connected explicitly from Settings so their native trust and profile boundaries stay visible. History reconciliation runs in the background for each supported adapter.

Did it work?

Screen What you should see
Sessions Your session, at Waiting while the CLI sits at the prompt, flipping to Active the moment the selected agent starts a turn
Agent Board A main-agent card in Waiting, moving to Working on your first message and back after each turn
Activity Events arriving; click a row to expand its payload

[ 05 · Run it ]

Configuration

Everything has a working default. These are the ones worth knowing; the full annotated set is in .env.example.

Variable Default What it does
DASHBOARD_PORT 4820 Port the server listens on
DASHBOARD_HOST 127.0.0.1 Interface it binds. Loopback, so not network-reachable
DASHBOARD_TOKEN unset Required on every API call and on the WebSocket when set
DASHBOARD_ALLOWED_HOSTS empty Extra Host header names to accept beyond loopback, comma-separated
CLAUDE_HOME ~/.claude Where transcripts and settings are read from
DASHBOARD_DATA_DIR $CLAUDE_HOME/byte-agent-monitor Where the database lives
DASHBOARD_DB_PATH $DASHBOARD_DATA_DIR/dashboard.db The SQLite file itself
DASHBOARD_STALE_MINUTES 180 Idle minutes before a session is marked abandoned
DASHBOARD_SESSION_SYNC_MS 30000 How often the transcript tree is re-swept. 0 disables it
RUN_MAX_CONCURRENT 10 Live claude subprocesses the Run screen will start. Over the cap it refuses

[ 06 · Talk to it ]

API reference

Everything the screens do, they do over this API. It is 112 paths and 136 operations, and the generated OpenAPI 3.0 document is the complete reference: parameters, schemas, field descriptions and examples. It is served live at /api/openapi.json, as Swagger UI at /api/docs, and as ReDoc at /api/redoc. The ReDoc bundle is self-hosted, so it works offline.

Responses are JSON. Errors are always { "error": { "code", "message" } }. Collections take limit and offset, and the values are clamped rather than rejected: SQLite reads a negative LIMIT as "no limit". The envelope is flat and named for its collection: { sessions, limit, offset, total }.

Route groups

Prefix Covers
/api/sessions Sessions, their transcripts, marks, replay and lifelines
/api/agents, /api/events Agents and the event feed
/api/stats, /api/analytics, /api/timeline Counters, chart aggregates, the activity ribbon
/api/workflows, /api/record Orchestration data and the per-turn record
/api/hooks, /api/import Event ingestion and history import
/api/pricing, /api/settings Pricing rules, server info, export and import
/api/alerts, /api/webhooks, /api/push Alert rules, webhook targets and deliveries, web push
/api/cc-config What Claude Code has on disk. The largest group, at 19 operations
/api/run, /api/remote-sources Spawning sessions, and other machines read over SSH
/api/metrics, /api/updates Prometheus exposition, and the update check

The ones you will actually call

GET /api/health Liveness. Returns { status, version, timestamp }. Never needs a token
GET /api/sessions Sessions with agent counts and computed cost. Params status, q, limit (default 50), offset
GET /api/sessions/:id One session with its agents and events. The event array is bounded and says so, so a long session cannot return an unbounded payload
GET /api/events The event feed. Filter by event_type, tool_name, q, from, to
GET /api/stats The header counters: events today, live socket count, agents and sessions by status
POST /api/hooks/event Ingestion. Body is { hook_type, data }. This is the one the hook handler calls
GET /api/settings/info Database path, size and counts, hook install status, server version and uptime
GET /api/settings/export Streams the whole dataset as NDJSON
POST /api/run Spawns claude as a subprocess and streams it back over the WebSocket
GET /api/metrics Prometheus exposition: byte_sessions, byte_agents, byte_events_total, byte_tokens_total and process gauges

Authentication

Set DASHBOARD_TOKEN and every /api/* call and the WebSocket upgrade need it. It is read from Authorization: Bearer …, an x-dashboard-token header, or a ?token= query parameter, and compared in constant time. Four paths stay open even then: /api/health, /api/openapi.json, /api/docs and /api/hooks/*, because the local hook handler carries no token and the loopback bind is what protects it. Browsers cannot set headers on a WebSocket, so the socket accepts only the query parameter or the custom header.

WebSocket

One socket at /ws. Every frame is { type, data, timestamp }. The types are:

frame types
session_created     agent_created     new_event          alert_triggered
session_updated     agent_updated     import.progress    alert_updated
run_status          run_stream        run_input_ack      workflow_upserted
update_status       cc_config_changed remote_data.updated
remote_source.status                  subscribed

A client that says nothing receives everything. To narrow, send { "action": "subscribe", "topics": [ … ] } where each topic is a frame type and optionally a session_id; the server answers with a subscribed frame. Subscriptions replace rather than merge, and cap at 200 topics. The server pings every 30 seconds and drops a socket that misses a pong. If a client stops reading, frames are dropped past a 1 MB send buffer and the socket is closed at 8 MB: a slow reader cannot become a memory leak.

[ 07 · Talk to it ]

Beyond the browser

Six other ways into the same database.

Surface What it gives you
Desktop app macOS, Windows and Linux. Bundles and supervises the server, adds a tray icon and start-at-login. No terminal
VS Code extension Live health, tokens and cost in the sidebar; the dashboard as a tab
byte CLI Every surface from a terminal, with box-drawn tables and inline bar charts. Eleven commands work offline against the database
MCP server 30 typed tools over stdio, HTTP+SSE or a REPL, so an agent can query its own history
Plugins Ten Claude Code plugins reading the same data model
Statusline Model, context bar, tokens and session cost in your prompt

MCP server

Thirty tools: sixteen read-only, thirteen that mutate, and one that is destructive. Mutating tools are refused unless MCP_DASHBOARD_ALLOW_MUTATIONS=true. The destructive one, dashboard_clear_all_data, additionally needs MCP_DASHBOARD_ALLOW_DESTRUCTIVE=true and a confirmation token that must read exactly CLEAR_ALL_DATA. Read-only tools never touch either gate. The remote source listing scrubs hostnames, key paths and addresses before returning, because tool results are copied into a model's context.

bash
npm run mcp:install
npm run mcp:build
npm run mcp:start              # stdio, for MCP hosts
npm run mcp:start:http         # HTTP + SSE on 127.0.0.1:8819
npm run mcp:start:repl         # interactive, with tab completion

# register it with Claude Code
claude mcp add byte \
  --env MCP_DASHBOARD_BASE_URL=http://127.0.0.1:4820 \
  -- node /path/to/Byte/mcp/build/index.js

The HTTP transport serves streamable HTTP at /mcp, legacy SSE at /sse and /messages, and a liveness probe at /health. The dashboard URL it talks to must be a local host: the allowlist covers loopback and the container gateway names, and rejects anything else.

The byte CLI

npm run setup links it. It finds the server from CLAUDE_DASHBOARD_PORT or DASHBOARD_PORT, then ~/.claude/.byte-agent-monitor.json, then 127.0.0.1:4820. Colour turns itself off when you pipe it.

bash
byte status                 # is the server up, and where
byte stats                  # the header counters
byte kanban                 # the board, in the terminal
byte sessions --limit 20    # box-drawn table
byte session <id>           # one session in full
byte tail --session <id>    # follow events as they arrive
byte analytics              # tokens, cost, tools, with inline bars
byte cost                   # what it has cost you
byte doctor                 # check the install
byte repl                   # interactive shell with completion

Eleven commands work with no server at all, reading the SQLite file directly: stats, sessions, agents, events, kanban, session, pricing, alerts, rules, export and doctor. Offline runs still correct a stale active session for display, using the same process-liveness probe the server uses, and footnote that they did, without writing to the database.

Desktop app

Electron. It ships as a DMG on macOS, an NSIS installer and a portable executable on Windows, and a .deb and AppImage on Linux. The .deb is the one to prefer, because the hook command written into your settings embeds an absolute path and an AppImage remounts somewhere new every run.

The server runs in a dedicated child process, not in the window's own event loop: SQLite's API is synchronous, and a free-text search that takes most of a second froze the interface when the two shared a thread. If a healthy server is already answering on 4820 the app adopts it and leaves it running on quit; otherwise it picks a free port and writes it where the hook handler will look. The tray menu carries the port, active sessions, working agents and events today, plus open, restart, logs and an Open at Login switch, macOS and Windows only, since Electron has no supported mechanism on Linux.

VS Code extension

One activity-bar view, Monitor Control Center, polling every five seconds: four stat tiles with sparklines over the last twenty samples (sessions, agents, tokens, cost), an agent-health bar, recent sessions you can click through, and quick navigation. Four commands: open the dashboard, refresh, open in a browser, clear history. There are no settings to configure; it reads the port from the environment and falls back to 4820.

Statusline

A Python script, standard library only, that reads the JSON Claude Code pipes to it and prints seven segments: model, user, working directory, git branch, a ten-cell context bar with its percentage, tokens in and out with cache reads, and session cost to four decimal places. The context bar and the cost both change colour as they climb. It reads nothing else, no server, no database, no config, and exits zero whatever it is given, so it can never block Claude Code.

Plugins

Ten Claude Code plugins (byte-analytics, byte-cost-guard, byte-productivity, byte-devtools, byte-insights, byte-sessions, byte-workflows, byte-quality, byte-config and byte-dashboard), each bundling some mix of agents, commands, skills and hooks. They live under plugins/, alongside the marketplace manifest that lists them, and load straight from the checkout:

bash
claude --plugin-dir plugins/byte-analytics

[ 08 · Operate it ]

Deployment

One SQLite file means one writer. Byte is not a stateless pool you scale sideways; it is a cell you run more of. The Helm chart enforces that itself: it refuses to render above one replica, and CI asserts the refusal on every change.

Target What ships
Your machine npm run build && npm start, or the desktop app. The usual case
Docker or Podman A three-stage Dockerfile on node:22-alpine, plus compose files for the app alone, the app with Prometheus and Grafana, and the hosted stack
Kubernetes A Helm chart (StatefulSet, service, ingress, PVC, pod-disruption budget, network policy and a ServiceMonitor) with dev, staging and production value sets
Azure Bicep: one main.bicep over ten modules (network, key vault, storage, Front Door, data plane, observability, alerts, access, registry access and edge config) with per-environment parameter files
bash
# Docker Compose, publishes on loopback only
docker compose up -d --build

# with Prometheus and Grafana alongside
docker compose -f docker-compose.full.yml up -d --build

# Podman
CLAUDE_HOME="$HOME/.claude" podman compose up -d --build

The image's health check opens the database rather than calling /api/health: that endpoint answers ok without touching storage, which is exactly the failure you want the check to catch. Hooks must be installed from the host, not from inside the container: the installer refuses there, so it can never write a container-internal path into a bind-mounted ~/.claude.

Monitoring

GET /api/metrics is Prometheus exposition: byte_up, byte_build_info, process uptime and resident memory, byte_sessions and byte_agents by status, byte_events_total, byte_websocket_clients, byte_remote_sources, and byte_tokens_total split by input, output, cache read and cache write. Scrape configs and Grafana dashboards ship under monitoring/; npm run monitoring:verify checks the wiring.

Security

The trust boundary is the loopback bind. Everything else is a layer on top of it.

  • Loopback by default. The server binds 127.0.0.1 and is not reachable from the network.
  • It refuses to start on a wider bind with no token and no explicit acknowledgement.
  • Token auth over every API route and the WebSocket, compared in constant time, when DASHBOARD_TOKEN is set.
  • A Host header allowlist, loopback plus whatever you name in DASHBOARD_ALLOWED_HOSTS, which is what stops DNS rebinding. CORS is restricted to the same set. Both are browser defences, not authentication: neither stops curl.
  • Every query is a prepared statement with bound parameters, and query parameters go through one coercion module that fails closed. It exists because ?limit=-1 used to mean "no limit" to SQLite, and an int64 overflow used to mean a 500.
  • Spawning is same-origin guarded. Every /api/run route rejects a browser request whose origin is not loopback, so a web page you happen to have open cannot start processes on your machine.

Report anything you find to namaste@bytevion.com.

[ 09 · Operate it ]

Troubleshooting

Symptom Why, and what to do
No events arriving Check Settings → Integrations for the selected platform's detection, trust and collector state. Claude Code hooks require a new session after repair; Codex and OpenCode show their own reconnect instructions. Superset also reports the underlying agent binding
Nothing on screen on a fresh install History import runs once, in the background, on first start. Give it a moment, or force it from Settings → Import history. npm run seed puts three demo sessions in
Sessions stuck as Active A session that exits without firing SessionEnd is swept after DASHBOARD_STALE_MINUTES (180 by default), and a liveness probe catches dead processes sooner
Server will not start on a chosen host That is the wide-bind refusal. Set DASHBOARD_TOKEN, or set DASHBOARD_ALLOW_INSECURE_BIND if you genuinely mean it
403 on every request The Host header is not on the allowlist. Add the name you are browsing to, to DASHBOARD_ALLOWED_HOSTS
Docker: hooks never install By design. Run npm run install-hooks on the host after the container is up, then restart Claude Code
/api/docs returns 501 The Swagger and ReDoc packages are optional and the desktop build omits them. The spec itself is still at /api/openapi.json