Repository navigation
Releases
v0.17.0: hosts over SSH, an installer and a live demo
Linux hosts over SSH with nothing installed on them, binaries and a one-line installer for servers without Docker, and a live demo that runs in the browser. Nothing changes for an existing installation until you add a host.
Added
- SSH hosts: add any Linux machine by its address and a user in Settings → SSH hosts. dash signs in with its own key, runs one fixed read-only script and shows the machine on the new Hosts page: live CPU, memory, network and disk charts, temperatures and fans, file systems, disks and ZFS pools, containers (docker or podman) and systemd services. A full file system, a failed unit, a pool that is not online and a host that went away become attention items on the Overview. Nothing is installed on the host, dash holds no password and never writes there (the SSH hosts page).
- Pinned host keys: dash connects to a host only after an administrator has trusted the fingerprint it shows, and refuses a host whose key changed. Hosts set in the config file carry their key as
hostKey. - Release binaries: every release now has
dash_<version>_<os>_<arch>.tar.gzfor Linux and macOS on amd64 and arm64, a checksum file and a build provenance attestation. - Installer:
curl -fsSL https://dash.techdufus.com/install.sh | sudo shinstalls the binary as a hardened systemd service, creates its secret key and prints the setup link. Run it again to upgrade (the binary guide). - Live demo: the live demo is the real web UI on recorded demo data, hosted as static files. It is read-only; the container's demo mode still answers actions.
- Getting started: an Overview with nothing connected yet points administrators at adding a host.
Security
- SSH hosts need
DASH_SECRET_KEYand a writable data directory: dash's SSH private key is sealed with it incredentials.yaml. Give dash a dedicated unprivileged user on each host and add its key withrestrict. The security model and ADR 0003 say what dash runs, what it stores and what viewers see.
Upgrade notes
- No step needed. The
sshplugin stays off untilplugins.ssh.hostsnames a host. - Rolling back after adding hosts: remove
plugins.sshfrom the config file and unset everyDASH_PLUGINS_SSH_*variable first, since an older release refuses a key or a variable it does not know. The older release drops dash's SSH key at its next write ofcredentials.yaml, so after upgrading again every host needs the new public key.
v0.16.1: usage figures stay in their cards
The Hardware page's memory and root-disk figures stay inside their cards, and dash is built with Go 1.27.4 for a net/http security fix. A patch; nothing to change.
Fixed
- Hardware fleet cards: in a narrow card, a machine's "used / total %" memory and root-disk figures ran past the card's edge. They now wrap (the percentage first, then the total) and never split a number from its unit. The same holds for every usage bar in dash.
Security
- Go 1.27.4: fixes GO-2026-6859, an HTTP/1 server crash from a header race in
net/http'sMaxBytesReader, which dash's server and clients reach.
Upgrade notes
- No step needed. Rolling back to v0.16.0 is safe, but brings the vulnerable Go back.
v0.16.0: Hardware fleet
The Hardware page now shows every machine you run (#47): any number of Proxmox hosts with their full hardware detail, and machines outside Proxmox with their node-exporter figures. A minor release: hardware.hosts and the hardware attention ids change shape; one-host settings keep working.
New
- Several Hardware hosts.
plugins.hardware.hoststakes any number of hosts, each read by itsnodename(its node-exporter nodename and, in a Proxmox cluster, its node). Each keeps its own bays, fan scale, sensors, pools, disks, links and Proxmox facts. - Hardware page:
- a fleet grid with a card per host (health, CPU, memory, power, CPU temperature, pools, disks) and per machine;
- the full detail of the host you pick below it, at
/hardware/<host>; - machine cards with node-exporter stats: OS and architecture, CPU, memory, root disk, load, uptime and, where the machine reports one, its temperature (macOS memory as Activity Monitor counts it);
- machines checked through Gatus show up or down.
- Overview: the
powerKPI sums the hosts,cpuTempis the hottest package, and each topology host carries its own power, temperature and health. - Attention: pool, scrub, SMART and CPU-temperature items name their host and open its page.
- Series:
host.*take a host asnode; without one,host.poweris the sum,host.cpuTempthe hottest, and the others draw one line per host. - VM sheet: links to the Hardware page of the VM's own host.
Upgrade notes
- Settings: nothing to change for one host. To add hosts, give each a
nodename; at most one may leave it empty (it takesplugins.proxmox.node). Names and nodenames must be unique, ignoring case. A host whose nodename is a node of the Proxmox cluster is that node (its Proxmox facts, shell link and place in the topology) whateverplugins.proxmox.nodesays, so a cluster whose hosts all have a nodename no longer needs that setting. - A host without
nameis called by itsnodename(before: its Proxmox node). Where the two differ, its name, refs and attention ids change. - API and clients:
hardware.hostsis{hosts: [...]}(oneHostDataper host,[]when none is configured) instead of one object; each host hashealth;- attention ids carry the host (
zfs:pool:<host>/<pool>,zfs:scrub:<host>/<pool>,smart:<host>/<bay>,host:cpu-temp:<host>); acknowledgements of the old ids do not carry over; - an unknown host in a
host.*series is a 404; - node-exporter machines carry
stats.
- Rolling back to v0.15.0: keep one host in
plugins.hardware.hosts; v0.15.0 refuses several.
See docs/upgrading.md.
v0.15.0: Proxmox clusters
dash now reads your whole Proxmox VE cluster through its one Proxmox connection (#46): every node, the cluster's quorum, totals, and every guest and storage on its own node. A minor release: some payloads change shape; the settings do not.
New
- Clusters through one connection. dash asks whichever node
plugins.proxmox.urlreaches for the whole cluster. A standalone server is a cluster of one. - VMs page:
- a cluster summary: name, quorum, nodes online, and the CPU, memory and storage totals of the online nodes;
- a card per node: its state, CPU, memory, uptime, Proxmox VE version, CPU model and guests;
- each VM and template shows its node, and the activity table has a Node column.
- Per-VM calls go to the right node. A VM's detail and console use its own node, follow a guest that just migrated, and answer at once for a guest of an offline node.
- Storage: every node's storages, a shared one (NFS, Ceph) listed and counted once, with totals.
- Overview: the topology draws one host per node, each VM under its node.
- Attention: an offline node and a cluster that lost quorum are critical items.
- Hardware page: the Proxmox facts of the host's own node.
Upgrade notes
- Settings: nothing to change.
plugins.proxmox.nodeno longer chooses what dash reads; it names the node the Hardware page's host is. A cluster of several nodes no longer needs it for the plugin to run, but its Hardware page does (orplugins.hardware.hosts[0].nodename). - Token: the cluster's name and quorum need
Sys.Auditon/(PVEAuditoron/has it). Without it everything else works and the quorum reads as unknown. - API and clients:
proxmox.nodeis replaced byproxmox.cluster;- VMs and tasks carry
node; - storage refs carry the node (
proxmox:Storage/<node>/<name>; a shared one isproxmox:Storage/<name>); core.overview's topology hashosts(one per node) instead ofhost.
- Rolling back to v0.14.11: no settings change, but a cluster of several nodes then needs
plugins.proxmox.nodeagain.
See docs/upgrading.md.
v0.14.11: dash is public
dash is now public (#42). This is its first release published for everyone: a multi-arch image and the Helm chart on GHCR, with provenance and an SBOM attached and the image signed by cosign. It is a patch with no behaviour change; you can now install dash without building it.
New
-
Images on GHCR:
ghcr.io/techdufus/dashfor linux/amd64 and linux/arm64, tagged0.14.11and0.14. Releases are create-only: a published version is never overwritten.docker run -p 8080:8080 -e DASH_DEMO=true -e DASH_SERVER_LISTEN=0.0.0.0:8080 ghcr.io/techdufus/dash:0.14.11
-
Helm chart on GHCR:
helm install dash oci://ghcr.io/techdufus/charts/dash --version 0.14.11
-
Supply chain:
- the image is signed keyless with cosign;
- BuildKit provenance and an SBOM are attached;
- GitHub build-provenance and SBOM attestations are published (
gh attestation verify).
See
docs/security.md. -
Site: a landing page at https://dash.techdufus.com.
-
Docs: the install guides use the published image and chart.
Fixed
- A replaced
credentials.yamlis always noticed. Acredentials.yamlrestored or replaced while dash runs was not always detected on filesystems that reuse inode numbers (ext4), so dash could write over a restored file. dash now keeps the file it last read or wrote open, so its identity can't be reused (#43).
Upgrade notes
- No change for existing installs. If you built the image yourself before, switch to the published one, pinned by digest.
v0.14.10
AI agents can now act on your lab, with your approval (#40). This release adds MCP action tools that wait for a person to approve them, the approval page and its notifications, and the guides for the Android app and MCP clients. It is a patch; with MCP off (the default) nothing changes.
New
- Action tools for agents. With MCP on, an administrator's mcp token holding
actions:<plugin>sees that plugin's actions as tools:kubernetes_restart,flux_reconcile,alertmanager_silence_createandalertmanager_silence_expire. They are listed only while the plugin is running. - Human approval:
- an agent's call creates an approval request, and the agent gets a link to give you;
- you open
/approve/<id>(or the new header indicator), check the action, its target and full input, and approve or deny; - a protected target needs you to type its name, and the agent can never supply it;
- the action runs once, as the requesting agent, after re-checking its token, role and scope;
- the agent reads the outcome with
dash_approval, or waits for it through URL elicitation on MCP 2026-07-28; - requests expire after 10 minutes, and each user can have at most 20 pending.
- Approval notifications: a pending-approvals badge in the header, and a push to your devices that take approvals (v0.14.9).
- Per-plugin agent policy:
plugins.<id>.actions.agents, also in Settings → MCP:approve(default): every call waits for you;allow: runs at once, except protected targets;deny: hides the tools.
- Audit: every request, decision and run, with the requester, the approver, the target and a hash of the arguments, never their free text.
- Guides:
docs/agents/mcp.md: Claude Code with a token, Claude Desktop and claude.ai through OAuth, VS Code, omp;docs/agents/dash-skill/SKILL.md: an agent skill for using dash;docs/clients/android.md: the contract for the coming Android app.
- Inputs: action inputs describe themselves (required fields, allowed kinds), and silence matchers are capped in length.
Upgrade notes
-
No step needed. If you turned MCP on, an existing mcp token holding
actions:<plugin>now sees that plugin's action tools, and its calls create approval requests (theapprovedefault). -
Rolling back to v0.14.9:
- remove
plugins.<id>.actions.agentsfrom the config file and unsetDASH_PLUGINS_<ID>_ACTIONS_AGENTS; v0.14.9 refuses both; - a value saved in the settings page only warns;
- pending approvals are kept in memory and are lost at any restart.
See
docs/upgrading.md. - remove
v0.14.9
dash can now notify your devices (#39). This release adds Web Push for the installed web app, UnifiedPush for the coming Android app, and attention notifications. It is a patch, and push is unavailable until dash has a writable data dir and DASH_SECRET_KEY.
New
- Settings → Devices. "Subscribe this browser" registers the installed web app or a browser for push.
- The device proves it can receive pushes with an 8-character code, which the page submits by itself.
- Each device chooses its alerts: approvals, and attention at critical, warning or off.
- It can send itself a test push.
- Administrators can see and remove every user's devices.
- A QR code holds the server address for the Android app (not released yet).
- Attention notifications:
- an attention item at or above a device's threshold that lasts 2 minutes sends one push;
- an item escalating from warning to critical reaches critical-only devices;
- an item pushes again only after it clears and returns;
- at most 30 attention pushes per user per hour, with one summary for the rest.
- One sender for Web Push and UnifiedPush:
- RFC 8291 encryption and RFC 8292 VAPID, built on the Go standard library;
- endpoints must be https and resolve to global addresses, checked at dial time;
push.allowPrivateadmits a LAN ntfy; - no redirects, retries with backoff;
- fair limits per device, per user and per push service.
- Devices follow your sessions.
- A browser device stops receiving pushes when you log out, and comes back by itself the next time you sign in on it.
- The Android app's device follows its OAuth grant.
- Endpoints and keys are stored encrypted and never logged.
- Installed web app: the service worker shows notifications and opens them only on dash's own origin.
Upgrade notes
- Nothing to change. Without a writable data dir and
DASH_SECRET_KEY, push stays off, and one INFO line at start says what is missing. Push also needspush.contactor an httpsserver.publicURL. - Rolling back to v0.14.8: remove
push:from the config file (the older release refuses the unknown key). v0.14.8 keeps tokens and grants and drops the push data at its next write, so devices subscribe again after a later upgrade. Seedocs/upgrading.md.
v0.14.8
dash can now be read by AI agents (#38). This release adds a read-only MCP server, context bundles, and "Copy context for AI". It is a patch and MCP is off by default: nothing changes until you set mcp.enabled.
New
-
MCP server at
/mcp(Streamable HTTP, protocol versions 2026-07-28 and 2025-11-25), switched on and off live withmcp.enabledor in Settings → MCP.- Access: only bearer tokens with audience
mcp: personal access tokens, static tokens, or OAuth grants. - Tools:
dash_overview,dash_search,dash_get,dash_topic,dash_series,dash_logs(needslogs) anddash_context. - Resources: every topic you may read, with subscriptions.
- Prompts: four (triage, investigate, daily digest, explain an alert).
- Read-only: there are no action tools in this release.
- Access: only bearer tokens with audience
-
Untrusted lab data: every result keeps logs, events, annotations and object names inside one fenced block, after a sentence telling the agent to treat it as data. Results are scrubbed of secrets and capped at 64 KiB.
-
Limits:
- per token: 120 calls a minute (30 for logs), 8 in flight, 2 listen streams;
- per user: 16 calls in flight, 4 listen streams;
- in all: 64 calls in flight, 16 listen streams.
Listen streams end within 15 s of revocation or MCP turning off. Every call is audited with surface
mcpand a hash of its arguments. -
GET /api/v1/context: a context bundle for any object a plugin can describe, as JSON or Markdown. A pod, workload, VM, host, alert, Flux object or database comes with its status, events, attention items, metric summaries and, with thelogsscope, its recent log lines. -
Copy context for AI: a button on pods, VMs, attention items and alerts puts that Markdown on your clipboard. Where the browser blocks the clipboard, it opens a dialog to copy from.
-
Settings → MCP: the switch, the endpoint (the direct URL when set), and a ready-to-paste
claude mcp addcommand. -
OAuth: the
mcpresource now followsmcp.enabled. -
Plugins:
/api/v1/pluginssays which plugins can describe objects (objects). -
Dependencies: the official MCP Go SDK v1.8.0, plus jsonschema-go, uritemplate and segmentio/encoding. The binary grows by about 2 MB.
Upgrade notes
- No step needed. With MCP on, dash logs "mcp: serving /mcp" at start.
- Rolling back to v0.14.7: remove
mcp.enabledfrom the config file first, because the older release refuses the unknown key. A value saved from the settings page or set in the environment only warns. Seedocs/upgrading.md.
v0.14.7
dash can now authorize apps itself (#37). This release adds a built-in OAuth 2.1 server: apps such as the dash Android app, clients you configure, and clients that publish a metadata document can ask a signed-in user for a scoped, revocable grant. It is a patch and is off by default: nothing changes until you set auth.oauth.enabled.
New
- OAuth 2.1 server (
auth.oauth.enabled, default off):- authorization code with PKCE (S256 only), resource indicators, refresh tokens that rotate (reuse revokes the grant), RFC 7009 revocation, and the RFC 8414 and RFC 9728 discovery documents;
- access tokens last 15 minutes;
- it needs a writable data dir and a mode other than
none; setDASH_SECRET_KEYso access tokens survive a restart.
- Clients:
- the built-in
dash-android; - clients you list in
auth.oauth.clients; - clients that publish a metadata document. dash fetches it only for a signed-in user, from global addresses only (unless
auth.oauth.cimdAllowPrivate), and refuses a name that imitates a known client.
- the built-in
- The consent screen shows the client, its kind ("Built in", "Configured by your admin", or "Unverified · metadata from
<host>"), and the scopes it asks for. Onlyreadis pre-ticked, and scopes your role can't grant are named. - Settings → Connected apps lists your grants: client, audience, scopes, created and last used. You can revoke them, and administrators can see and revoke every user's.
- Logout scopes:
- "Log out everywhere" also disconnects your apps;
- "Sign out all users" (administrators) ends every session and grant;
- personal access tokens are untouched.
- Behind an identity proxy:
server.directURLand the Helm chart'sroutes.directgive machine clients a host that skips the proxy, while sign-in and consent stay behind it. dash never trusts identity headers on that host. - Limits:
/oauth/tokenand/oauth/revokeare rate limited per grant, per code or per client, and can't be exhausted by invented client IDs;- pending authorizations are kept only for signed-in users (20 each);
- 20 grants per user.
- Dependencies: prometheus/common 0.73.0, and security overrides for development-only web dependencies (glob, minimatch).
Upgrade notes
-
No step needed. In proxy mode with OAuth on and no
server.directURL, dash warns at start, because clients couldn't reach the token endpoint through the proxy. -
Rolling back to v0.14.6 after using OAuth:
- revoke every user's connected apps (Settings → Connected apps → All users);
- then remove
auth.oauth,server.directURLand the chart'sroutes(ahelm rollbackdoes this).
See
docs/upgrading.md.
v0.14.6
dash now accepts API tokens (#36): personal access tokens for scripts, agents and apps, static tokens for GitOps installs, and Settings → Tokens to manage them. It is a patch. Nothing changes for browsers, and tokens stay off until dash has a writable data dir.
New
-
Personal access tokens. Create one in Settings → Tokens. You choose:
- an audience: the API, or MCP for agents once the MCP server arrives;
- scopes:
readandlogs, and for adminsactions:<plugin>, optionally limited to namespaces; - an expiry from 1 to 365 days (default 30).
The token is shown once, and dash stores only its hash. A revocation takes effect on the next request and ends open streams within one heartbeat. Each user can hold at most 50 tokens.
-
Bearer requests.
Authorization: Bearer <token>works on/api/v1.- A token can do what its owner's role allows, narrowed by its scopes. That is worked out again on every request, so a group change at your identity provider reaches the user's tokens at their next sign-in, or at their next request behind a proxy.
- Bearer requests skip the CSRF check. A request that carries both a token and a dash session cookie is refused.
-
Static tokens for GitOps installs.
dash token generateprints adash_st_token and its hash, and the hash goes inauth.tokens. Edits to the config file apply without a restart. -
CORS for browser-based clients: list their origins in
server.corsOrigins. Nothing is sent by default, andAllow-Credentialsnever is. -
Limits: 300 requests a minute per API token (bursts up to 300), and 10 token creations a minute per user.
-
Audit: every token request's audit record names the token.
-
Docs:
docs/auth.mddocuments tokens, scopes, audiences and limits.
Behind an identity proxy
oauth2-proxy and similar proxies redirect requests that lack their own session, so bearer clients need a route that skips the proxy. The chart's routes.direct for this comes with the OAuth release. docs/auth.md lists what a route you set up yourself needs.
Upgrade notes
-
No change is needed. Tokens need a writable data dir in
local,oidcandproxymode. Without one, Settings → Tokens says they are unavailable. -
Every 401 now carries a
WWW-Authenticate: Bearerchallenge. -
Rolling back to v0.14.5 after creating tokens:
- with dash stopped, remove
credentials.yaml, which ends every session and revokes every token; - remove
auth.tokensandserver.corsOriginsfrom the config.
See
docs/upgrading.md. - with dash stopped, remove