Warning: This project is under active development. APIs, configuration formats, and features may change without notice.
An AI-native Prometheus dashboard. Point an LLM at your metrics, get production-ready dashboards in minutes — stored as YAML in git, served from a stateless binary.
Why Dashyard?
- AI-first workflow —
gen-promptscans your Prometheus and builds an LLM prompt. Claude or ChatGPT generates complete dashboards from it. - Dashboards as Code — plain YAML files in a git repo. Diff, review, and version-control every change.
- Immutable by design — no database, no storage, no write API. The server reads YAML from disk and serves graphs. Nothing else.
- Single binary — one ~30MB Go binary with the frontend embedded. Docker image included.
The gen-prompt command reads metrics from your Prometheus server and produces a prompt file optimized for LLMs. Feed it to Claude, ChatGPT, or any other LLM to generate complete dashboard YAML files instantly.
./dashyard gen-prompt http://localhost:9090 -o .
./dashyard gen-prompt https://prom.example.com -H "Authorization: Bearer eyJ..."
./dashyard gen-prompt http://localhost:9090 --match "node_.*" -o .This writes prompt.md and prompt-metrics.md to the specified directory. prompt.md is a static template (guidelines + format reference) written only on first run — edit it freely to customize the LLM instructions. prompt-metrics.md is regenerated every time with the latest metrics. To reset prompt.md to the default, use --overwrite.
Then ask an LLM to generate dashboards. For example, with Claude Code:
Read prompt.md and prompt-metrics.md, then generate Dashyard dashboard
YAML files for all available metrics. Write the files to ./dashboards/.
To update existing dashboards:
Read prompt.md and prompt-metrics.md, then update the dashboards in
./dashboards/. Add panels for any new metrics that are not yet covered.
See examples/real-world/ for a complete example using a real monitoring stack.
Define dashboards in YAML and manage them with Git. Rows, panels, queries, and layout are all declarative. Every change is human-readable, diff-friendly, and reviewable in pull requests.
There is no database, no persistent storage, and no write API. The server reads dashboard YAML files from disk and proxies queries to Prometheus. Nothing to exploit, nothing to corrupt.
Display Prometheus metrics as line, area, bar, or scatter charts. Mix in Markdown panels for documentation alongside your graphs.
Add dropdown variables that dynamically filter queries. Users can switch between values (e.g. network device) without editing the dashboard definition.
Automatically repeat a row for each value of a template variable. One row definition generates panels for every network interface, disk, or host.
Draw horizontal reference lines on graph panels to mark warning levels, SLA targets, or capacity limits.
When Prometheus data has gaps (e.g. container redeployment where the old version stops sending metrics before the new version starts), Dashyard breaks the graph line instead of interpolating across the missing interval. This matches the behavior of Grafana and other monitoring tools.
Control panel widths using span in a 12-column grid. Use span: 12 for full-width, span: 6 for half-width, etc. When span is omitted, columns are auto-distributed equally.
Organize dashboards into subdirectories that become collapsible groups in the sidebar.
Session-based login with SHA-512 crypt password hashing.
Sign in with GitHub or GitHub Enterprise. Configure one or more OAuth providers alongside password auth. Optionally restrict access by GitHub username or organization membership.
When both password auth and OAuth are configured, users see both options on the login page.
GitHub Enterprise is supported via the base_url option, which overrides the OAuth and API endpoints to point to your GHE instance.
GET /ready returns the server and Prometheus connectivity status. No authentication required.
curl http://localhost:8080/ready
# 200 {"status":"ok","prometheus":"reachable"}
# 503 {"status":"degraded","prometheus":"unreachable"}Use it as a Docker HEALTHCHECK, Kubernetes readiness probe, or load balancer health check.
Go backend with embedded React frontend, no external dependencies. Multi-stage Dockerfile produces a ~30MB image.
Download the latest release from the Releases page. Binaries are available for Linux and macOS (amd64/arm64).
# Example for Linux amd64 (replace VERSION with the desired release)
VERSION=0.18.1
curl -Lo dashyard.tar.gz "https://github.com/tokuhirom/dashyard/releases/download/v${VERSION}/dashyard_${VERSION}_linux_amd64.tar.gz"
tar xzf dashyard.tar.gz
./dashyard serve --config config.yaml --dashboards-dir dashboardsdocker run -p 8080:8080 \
-v ./config.yaml:/etc/dashyard/config.yaml:ro \
-v ./dashboards:/etc/dashyard/dashboards:ro \
ghcr.io/tokuhirom/dashyardOr build the image locally:
docker build -t dashyard .
docker run -p 8080:8080 \
-v ./config.yaml:/etc/dashyard/config.yaml:ro \
-v ./dashboards:/etc/dashyard/dashboards:ro \
dashyardOr use the example Docker Compose setup:
docker compose -f examples/kitchensink/docker-compose.yaml upRequires Go 1.25+ and Node.js 20+.
git clone https://github.com/tokuhirom/dashyard.git
cd dashyard
make build
./dashyard serve --config examples/kitchensink/config.yaml --dashboards-dir examples/kitchensink/dashboards- Install Dashyard using one of the methods above.
- Create a
config.yaml(see Configuration below or useexamples/kitchensink/config.yaml). - Create dashboard YAML files in a directory (see Dashboard Definition below or use
examples/kitchensink/dashboards/). - Start the server:
./dashyard serve --config config.yaml --dashboards-dir dashboards- Open http://localhost:8080 and log in with the credentials defined in your config.
Run the three components in separate terminals:
make dev-dummyprom # Fake Prometheus on :9090
make dev-backend # Go server on :8080
make dev-frontend # Vite dev server on :5173To test GitHub OAuth locally, also start the fake GitHub server:
make dev-dummygithub # Fake GitHub OAuth on :5555Then use examples/kitchensink/config-dummygithub.yaml as the config (it has GitHub OAuth pointing to the dummy server).
Create a config.yaml file (see examples/kitchensink/config.yaml):
site_title: "My Monitoring" # Optional, defaults to "Dashyard"
header_color: "#dc2626" # Optional, any CSS color value
server:
session_secret: "change-me-in-production"
datasources:
- name: default
type: prometheus
url: "http://localhost:9090"
timeout: 30s
default: true
# headers: # Optional custom HTTP headers
# - name: Authorization
# value: "Bearer ${MY_TOKEN}" # Supports ${VAR} and ${VAR:-default} env expansion
users:
- id: "admin"
password_hash: "$6$..."
# GitHub OAuth (optional, can coexist with password auth)
auth:
oauth:
- provider: github
client_id: "your-github-client-id"
client_secret: "your-github-client-secret"
redirect_url: "http://localhost:8080/auth/github/callback"
# base_url: "https://ghe.example.com" # for GitHub Enterprise
# allowed_users: ["user1", "user2"]
# allowed_orgs: ["my-org"]Custom HTTP headers can be set per datasource for authentication or multi-tenancy:
datasources:
- name: prod
type: prometheus
url: "https://prometheus.example.com"
default: true
headers:
- name: Authorization
value: "Bearer ${PROMETHEUS_TOKEN}"
- name: X-Scope-OrgID
value: "my-tenant"Header values support environment variable expansion using ${VAR} syntax, so credentials can be kept out of config files.
Several config fields support ${VAR} environment variable expansion, allowing secrets and environment-specific values to be injected at startup. Only the ${VAR} (brace) syntax is supported — bare $VAR references are not expanded. This ensures that values containing literal $ characters (such as SHA-512 crypt password hashes like $6$salt$hash) are not corrupted.
You can also provide default values using ${VAR:-default} syntax. If the environment variable is not set, the default value is used instead.
| Field | Example |
|---|---|
datasources[].url |
url: "${PROMETHEUS_URL}" |
datasources[].headers[].value |
value: "Bearer ${TOKEN}" |
users[].password_hash |
password_hash: "${ADMIN_PASSWORD_HASH}" |
auth.oauth[].client_id |
client_id: "${GITHUB_CLIENT_ID}" |
auth.oauth[].client_secret |
client_secret: "${GITHUB_CLIENT_SECRET}" |
auth.oauth[].redirect_url |
redirect_url: "${OAUTH_REDIRECT_URL}" |
auth.oauth[].base_url |
base_url: "${GHE_BASE_URL}" |
server.session_secret |
session_secret: "${SESSION_SECRET}" |
If a ${VAR} reference is used and the environment variable is not set (and no :-default is provided), Dashyard will return a configuration error at startup.
The dashboards directory is specified via the --dashboards-dir CLI flag:
./dashyard serve --config config.yaml --dashboards-dir ./dashboardsHost and port are also set via CLI flags (defaults: 0.0.0.0:8080):
./dashyard serve --config config.yaml --dashboards-dir ./dashboards --host 127.0.0.1 --port 9090Generate a password hash:
./dashyard mkpasswd <password>JSON schema: schemas/config.schema.json
Place YAML files in the dashboards directory. Subdirectories become groups in the sidebar navigation.
dashboards/
overview.yaml
infra/
network.yaml
Example dashboard:
title: "System Overview"
rows:
- title: "CPU"
panels:
- title: "CPU Utilization"
type: "graph"
query: 'system_cpu_utilization_ratio'
unit: "percent"
- title: "Notes"
type: "markdown"
content: |
## About
This panel renders **Markdown**.| Type | Required Fields | Optional Fields |
|---|---|---|
graph |
title, type, query |
chart_type, unit, legend, y_min, y_max, y_scale, thresholds, stacked, span |
markdown |
title, type, content |
span |
Controls the chart visualization style. Defaults to line when omitted.
| Value | Description |
|---|---|
line |
Line chart (default) |
area |
Line chart with filled area |
bar |
Bar chart |
scatter |
Scatter plot |
Controls y-axis value formatting.
| Value | Description |
|---|---|
bytes |
Human-readable byte sizes (e.g. 1.5 GB) |
percent |
Percentage with one decimal (e.g. 75.0%). Y-axis is fixed to 0–100 unless overridden by y_min/y_max. |
seconds |
Human-readable time durations (e.g. 200ms, 1.50s, 2.5m) |
count |
Numeric with SI suffixes (e.g. 1.2k). This is also the default when unit is omitted. |
Set explicit Y-axis bounds. These override the automatic scaling and any unit-based defaults (e.g. the 0–100 range for unit: percent). Both fields are optional and can be used independently.
- title: "Temperature"
type: "graph"
query: 'sensor_temperature_celsius'
y_min: -20
y_max: 50Set the Y-axis scale type. Defaults to linear. Use log for metrics that span multiple orders of magnitude.
| Value | Description |
|---|---|
linear |
Linear scale (default) |
log |
Logarithmic scale (base 10) |
The legend field accepts a Go template string for formatting series labels (e.g. "{{device}} {{direction}}").
Add horizontal reference lines to graph panels. Each threshold is drawn as a dashed line at the specified y-axis value.
| Field | Type | Required | Description |
|---|---|---|---|
value |
number | yes | Y-axis value where the line is drawn |
color |
string | no | CSS color for the line (default: #ef4444 red) |
label |
string | no | Text label displayed at the end of the line |
- title: "CPU Utilization"
type: "graph"
query: 'system_cpu_utilization_ratio'
unit: "percent"
thresholds:
- value: 80
color: "#f59e0b"
label: "Warning"
- value: 95
color: "#ef4444"
label: "Critical"Controls how many columns a panel occupies in the 12-column grid (like Grafana). When omitted, columns are distributed equally among panels. Use span: 12 for full-width panels.
| Span | Width | Panels per row |
|---|---|---|
12 |
100% | 1 (full-width) |
6 |
50% | 2 |
4 |
33% | 3 |
3 |
25% | 4 |
rows:
- title: "Overview"
panels:
- title: "Main Graph"
type: "graph"
query: "..."
span: 8 # 8/12 width
- title: "Side Graph"
type: "graph"
query: "..."
span: 4 # 4/12 width
- title: "Full Width"
panels:
- title: "Wide Graph"
type: "graph"
query: "..."
span: 12 # full-widthJSON schema: schemas/dashboard.schema.json
cmd/
dummyprom/ Fake Prometheus server for demos
dummygithub/ Fake GitHub OAuth server for dev/testing
internal/
auth/ Session management & middleware
config/ YAML config parsing
dashboard/ Dashboard YAML loader & store
handler/ HTTP request handlers
model/ Data models
prometheus/ Prometheus API client
server/ Gin router setup
frontend/ React/TypeScript/Vite SPA
schemas/ JSON schemas for YAML validation
examples/
kitchensink/ Kitchen-sink demo configs and dashboards
real-world/ Real monitoring stack with gen-prompt workflow
make test # All Go tests
go test ./internal/config/... # Specific package
cd frontend && npm run build # TypeScript type checking + buildPlaywright-based end-to-end tests verify login, dashboard rendering, auto panel layout, and Chart.js canvas resize behavior.
# Start all three services first:
make dev-dummyprom # Terminal 1
make dev-backend # Terminal 2
make dev-frontend # Terminal 3
# Run E2E tests:
make test-e2e # Headless
cd frontend && npm run test:e2e:headed # With browser visible
cd frontend && npm run test:e2e:ui # Interactive UI modeWith all three dev services running:
cd frontend && npx tsx take-screenshots.ts







