Dashboard¶
A web UI for evidence emitted by registered Stove systems. Timelines, span trees, snapshots, and Kafka explorer views live in SQLite by default, or in PostgreSQL for a shared deployment. Live updates stream via SSE.
In 30 seconds
Install stove-server, run stove, add dashboard { } in Stove().with, then open http://localhost:4040. The dashboard stays empty until tests stream events to the server.
Current server versions start the dashboard with bare stove; older docs and scripts may still show stove serve.
Preview¶
Open the interactive dashboard demo →
Explore the full dashboard with fictional checkout runs: follow a payment timeout through the timeline and trace, inspect mock requests and OIDC snapshots, browse Kafka evidence, and compare historical runs. Replay a test streams a fresh run into the interface. The admin page includes a working SQLite workbench and retention controls.
The demo stores its data only in browser memory. Reset demo restores the sample runs; reloading starts fresh too. No Stove server, Docker, or installation is required.
Open evidence from a report¶
Agent reports can link directly to a run, test, or specific record. Opening a citation selects the right tab, highlights the record, and opens its inspector. You can copy that link from the dashboard, expand the surrounding context, or choose Show full test. Browser back and forward restore earlier selections.
A cited retry stays on that exact attempt even if a later attempt passed. Snapshot links can open one JSON value and let you return to the complete snapshot. Evidence with no test attribution opens at run scope. If a record was removed by retention or a link points to the wrong scope, the dashboard shows it as unavailable.
Set public_url = "https://stove.example/observe" in the server configuration to publish links for readers. Stove serves UI assets, REST, SSE, and MCP under that prefix as well as its usual root paths, so gateways can preserve or strip the prefix. The URL accepts HTTP(S), with no credentials, query, or fragment. This configures addresses only; existing deployment access controls still apply.
Monitor deployed storage¶
Stove exports Prometheus metrics at /metrics on its HTTP port, including database operation latency, connection/lock contention, ingestion and retention counters, and SQLite/PostgreSQL diagnostics. A configured public URL prefix also applies to this endpoint. Scrape each deployed server instance directly and use Grafana for charts.
See the monitoring guide, scrape configuration, alert rules, and PromQL examples. Metrics collection is automatic; scrapes remain available when the database is busy or unavailable.
Install the server¶
Download the right binary from releases and add to $PATH.
Verify: stove --version.
Upgrade an existing install (Homebrew caches the tap, so refresh it first):
Dev channel (stove-next)¶
Want the latest changes before a release? Every Maven snapshot publish also ships the server as a rolling dev channel, versioned to match the snapshot (e.g. 1.0.0.57-SNAPSHOT):
Both formulae install the same stove binary, so they conflict — switch channels by uninstalling one first:
brew uninstall stove && brew install trendyol/trendyol-tap/stove-next # stable → next
brew uninstall stove-next && brew install trendyol/trendyol-tap/stove # next → stable
New snapshots replace the channel in place; brew update && brew upgrade stove-next moves you to the latest. Older snapshot binaries are not kept — if you need a version that stays put, use the stable stove formula.
Start the dashboard¶
stove # default UI/REST/MCP port 4040, gRPC port 4041
stove --public-url https://stove.example/observe # public browser URL and optional gateway prefix
stove --port 9000 --grpc-port 9001 # override ports
stove --retention-runs-per-app 50 # keep 50 completed runs per app (default: 1; 0: unlimited)
stove --run-idle-timeout-seconds 3600 # delete idle runs after 1 hour without ingestion (0: disabled)
stove --fresh-start # back up and recreate the DB, then start
stove --db ./my-stove.sqlite # custom DB path
stove --database-url postgresql://stove:secret@db.example/stove
stove --config-file /etc/stove/stove.toml
stove --clear # clear stored runs and exit
Open the printed URL. Empty until tests run.
Configuration files and secrets¶
Production deployments can mount a TOML or JSON configuration file and keep the PostgreSQL URL in a separate secret file. For example, /etc/stove/stove.toml can contain:
port = 4040
grpc_port = 4041
database_url_file = "/run/secrets/stove/database-url"
retention_runs_per_app = 50
run_idle_timeout_seconds = 3600
log_format = "json"
The equivalent JSON keys are identical:
{
"port": 4040,
"grpc_port": 4041,
"database_url_file": "/run/secrets/stove/database-url",
"retention_runs_per_app": 50,
"run_idle_timeout_seconds": 3600,
"log_format": "json"
}
Start it with stove --config-file /etc/stove/stove.toml, or set STOVE_CONFIG_FILE to the path. A secret file contains only the connection URL and may end with a newline. --database-url-file and STOVE_DATABASE_URL_FILE provide the same indirection without a general configuration file.
CLI arguments and STOVE_* environment variables override the configuration file, which overrides built-in defaults. Configure only one of database_url and database_url_file at a given precedence level. Relative db and database_url_file paths inside a configuration file are resolved from that file's directory. Stove reads configuration and secrets once during startup, so restart replicas after rotating either file. Prefer a read-only secret mount over an inline URL, an environment variable, or a command-line argument because those values can be exposed by deployment inspection or process listings.
Server logging¶
Server logs default to newline-delimited JSON on stdout, suitable for ingestion into Elasticsearch and viewing in Kibana. Each event includes timestamp, level, target, and a fields object containing message and any structured event fields. Startup endpoints are also logged as structured fields, without a plain-text banner in JSON mode.
Use stove --log-format text for readable terminal output, or set STOVE_LOG_FORMAT=text. Configuration files accept log_format = "json" or log_format = "text" (JSON files use the same key). Precedence is CLI flag, environment variable, configuration file, then the JSON default.
RUST_LOG controls filtering for either format and defaults to info, for example RUST_LOG=stove=debug,info stove. CLI help, configuration errors before logging initializes, and interactive skills prompts remain plain text; prompts go to stderr.
Run with Docker¶
The image serves the dashboard, REST API, and MCP on port 4040, and receives test events over gRPC on port 4041. It runs as a non-root user and supports Linux AMD64 and ARM64.
Use ghcr.io/trendyol/stove-server:latest to follow stable releases or ghcr.io/trendyol/stove-server:snapshot to follow development snapshots. Publishing a Maven snapshot also publishes the matching server image with both its versioned tag (for example, :1.0.0.558-SNAPSHOT) and :snapshot. Snapshot publications never update :latest.
Manual container builds whose version ends in -SNAPSHOT (case-insensitive) also update :snapshot. Other prereleases, such as 0.28.0-beta.1, receive only their versioned tag. Choose a versioned tag to select a specific build.
For a local or single-host installation, persist SQLite at /data:
docker run -d \
--name stove \
--restart unless-stopped \
-p 4040:4040 \
-p 4041:4041 \
-v stove-data:/data \
ghcr.io/trendyol/stove-server:0.26.0
Build the image¶
Build from source at the repository root:
docker build -f server/stove-server/Dockerfile --build-arg STOVE_VERSION=dev -t stove-server:dev .
server/stove-server/scripts/verify-image.sh stove-server:dev dev
Image builds bundle the checked-in REST types; server CI verifies that they match the Rust API. After changing the API locally, run npm run generate:api in server/stove-server/spa before building the image.
The image publishing workflow builds the SPA and release binary on the runner with npm and Rust dependency caches, then packages only the binary using BINARY_SOURCE=prebuilt-binary. That build context must contain an executable named stove compiled for the target Linux architecture. Compilation uses Ubuntu 22.04 to keep its glibc requirement compatible with the Debian Bookworm runtime. The workflow checks health, version, embedded SPA, and Prometheus metrics in the resulting image before publishing tags.
Local PostgreSQL stack¶
To run the current source against PostgreSQL without preparing a database manually:
This builds the local Stove image, starts PostgreSQL 18, waits for it to become healthy, applies Stove migrations, and exposes:
- dashboard, REST, admin, and MCP at
http://localhost:4040; - gRPC ingestion at
localhost:4041; - PostgreSQL at
localhost:5433, usingstovefor the local-only database, user, and password.
The PostgreSQL volume survives normal restarts. Use just postgres-logs to follow Stove, just postgres-down to stop both containers, or just postgres-reset to stop them and permanently delete the local database volume. Override ports or retention with STOVE_HTTP_PORT, STOVE_GRPC_PORT, STOVE_POSTGRES_PORT, and STOVE_RETENTION_RUNS_PER_APP before running just postgres-up.
For a shared installation, mount a PostgreSQL URL secret and choose how many completed runs to retain per application:
docker run -d \
--name stove \
--restart unless-stopped \
-p 4040:4040 \
-p 4041:4041 \
-v /secure/stove/database-url:/run/secrets/stove-database-url:ro \
-e STOVE_DATABASE_URL_FILE=/run/secrets/stove-database-url \
-e STOVE_RETENTION_RUNS_PER_APP=50 \
ghcr.io/trendyol/stove-server:0.26.0
The container applies database migrations when it starts. PostgreSQL uses TLS by default; append ?sslmode=disable only when the database intentionally has no TLS and the connection stays inside a trusted private network. No /data volume is needed with PostgreSQL.
Run multiple replicas¶
Multiple Stove pods must all use the same PostgreSQL database. SQLite is intentionally single-process and must not be placed on a shared volume. Put both HTTP and gRPC ports behind services or load balancers; session affinity is not required.
Each dashboard event carries a stable UUID and a per-run sequence. A pod commits the domain update, deduplication record, and durable live event in one PostgreSQL transaction before acknowledging it. PostgreSQL advisory locks serialize events for the same run, preserve commit order in the live-event log, and coordinate retention pruning for the same application. The UI receives cross-pod updates through PostgreSQL LISTEN/NOTIFY, with durable outbox polling and Last-Event-ID replay as the correctness fallback. PostgreSQL is therefore both the data store and the coordination dependency; no Redis or message broker is required.
Allow up to eight PostgreSQL connections per replica (four dashboard reads, one ingestion write, two database explorer queries, and one dedicated notification listener), plus operational headroom. Run the same Stove image version on every replica. Concurrent first starts are safe because migrations are serialized in PostgreSQL.
Query connections are managed by Diesel’s r2d2 integration and r2d2_postgres. The pools create connections on demand, validate them on checkout, and replace broken connections. Waiting for pool capacity times out after two seconds with HTTP 503 or gRPC UNAVAILABLE; idle connections expire after five minutes and connections are retired after thirty minutes. An interrupted operation is returned as an error rather than automatically replayed.
For Kubernetes, use /api/v1/meta as a startup/readiness endpoint, expose 4040 for UI/REST/MCP and 4041 for gRPC, and give SIGTERM at least 10 seconds to drain. Mount ordinary settings from a ConfigMap and the connection URL from a Secret:
apiVersion: v1
kind: ConfigMap
metadata: { name: stove-config }
data:
stove.toml: |
port = 4040
grpc_port = 4041
database_url_file = "/run/secrets/stove/database-url"
retention_runs_per_app = 50
run_idle_timeout_seconds = 3600
---
apiVersion: apps/v1
kind: Deployment
metadata: { name: stove }
spec:
replicas: 2
selector: { matchLabels: { app: stove } }
template:
metadata: { labels: { app: stove } }
spec:
securityContext: { fsGroup: 10001 }
terminationGracePeriodSeconds: 15
containers:
- name: stove
image: ghcr.io/trendyol/stove-server:0.26.0
args: ["--config-file", "/etc/stove/stove.toml", "--no-skills-check"]
ports:
- { name: http, containerPort: 4040 }
- { name: grpc, containerPort: 4041 }
volumeMounts:
- { name: config, mountPath: /etc/stove, readOnly: true }
- { name: database-url, mountPath: /run/secrets/stove, readOnly: true }
readinessProbe:
httpGet: { path: /api/v1/meta, port: http }
volumes:
- name: config
configMap: { name: stove-config }
- name: database-url
secret:
secretName: stove-postgres
defaultMode: 0440
items:
- { key: url, path: database-url }
On a new PostgreSQL database, the first replica seeds the shared retention and idle-timeout values from its resolved startup configuration. Later replicas do not overwrite it. Changes made on /admin are stored in PostgreSQL, immediately visible to every replica, and survive restarts.
After deployment:
- Users open
http://stove.internal:4040and administer retained evidence at/admin. - Agents connect to the Streamable HTTP MCP endpoint at
http://stove.internal:4040/mcp. - Test processes set
ingestion = DashboardIngestion.Grpc(host = "stove.internal", port = 4041)so events reach the exposed gRPC port.
The release workflow publishes exact (0.26.0), minor (0.26), major (0), and latest tags for stable releases. Pin the exact tag in production so a restart cannot pull a different server version. Keep that version aligned with the Stove dependencies used by the test process.
Trusted networks only
The container does not add authentication or authorization. Expose ports 4040 and 4041 only through an internal network, firewall, VPN, or private ingress. Do not publish either port directly to the internet.
Wire your tests¶
Stove().with {
dashboard {
DashboardSystemOptions(
appName = "checkout-api",
metadata = mapOf(
"team" to "checkout",
"tribe" to "commerce",
"gitlab.project" to (System.getenv("CI_PROJECT_PATH") ?: "local"),
"gitlab.pipeline_id" to (System.getenv("CI_PIPELINE_ID") ?: "local")
)
)
// If you start the server with `stove --grpc-port 9001`, match that here:
// DashboardSystemOptions(
// appName = "my-service",
// ingestion = DashboardIngestion.Grpc(port = 9001)
// )
}
// ... other systems + runner
}.run()
Now the registered Stove systems stream test events to the dashboard while the server is running.
Metadata is an immutable set of string key/value pairs attached when a run starts. Keys are intentionally open-ended, so CI jobs can describe a run with team, project, pipeline, branch, environment, or any other useful dimensions without a server schema change.
Ingestion over HTTP(S)¶
By default events are streamed to the server over plaintext gRPC at localhost:4041. Configure another gRPC endpoint with DashboardIngestion.Grpc(host, port). When the server sits behind an HTTPS-only ingress or API gateway that cannot forward gRPC — for example a shared dashboard server for CI pipelines — select HTTP ingestion instead:
DashboardSystemOptions(
appName = "checkout-api",
ingestion = DashboardIngestion.Http("https://stove-gateway.internal/stove"),
metadata = mapOf("gitlab.pipeline_id" to (System.getenv("CI_PIPELINE_ID") ?: "local"))
)
With DashboardIngestion.Http, each event is sent as a protobuf-encoded DashboardEvent in the body of POST <baseUrl>/api/v1/events (Content-Type: application/x-protobuf) and acknowledged with a protobuf EventAck. The base URL may include the gateway path prefix but must not include /api/v1/events, a query, or a fragment. Queueing, retry, and auto-disable semantics are identical to the default DashboardIngestion.Grpc transport, and the server applies the same validation, deduplication, and live broadcast pipeline to both.
The server exposes its HTTP API documentation at /swagger-ui and its OpenAPI document at /api-docs/openapi.json. The ingestion request and response are binary protobuf payloads; the shared .proto files in stove-dashboard-api remain the authoritative message schema.
For profiling on the same deployment, configure stoveTracing.profiling.serverUrl separately. Its multipart POST /ingest uses the HTTP port too. See shared profiling deployment for a common CI setting, path prefixes, required headers, upload limits, Java certificate trust, authentication limitations, and verification steps.
What you see¶
Chronological list of every HTTP call, DB op, Kafka publish, WireMock match, gRPC call. Click any entry to see request/response payloads.
Interactive span tree with attribute search. Requires Tracing enabled.
System state captured when an assertion failed. WireMock unmatched, Kafka topics, DB rows.
All published + consumed messages. Filter by topic, partition, headers. Drill into payloads.
Data model¶
database
└── apps (one per appName)
└── runs (one per test suite execution)
└── tests (one per test case)
├── entries (HTTP, DB, Kafka, ...)
├── spans (OTel tree)
└── snapshots (system state at failure)
Admins can choose Browse by on /admin and select a recorded metadata field such as gitlab.team. The dashboard then shows a Team selector above Application; other fields use their own label, such as Environment or Region. The full metadata key is available in the label's tooltip.
Choosing a value narrows the application list and its runs, tests, and evidence. An application appears if any retained run matches, and its summary reflects its latest matching run. The choice is remembered in that browser while switching applications and reloading. All values clears it. Existing run metadata filters further narrow the selected scope. Changing the admin field clears the previous scope, and open dashboards pick up the change within the five-second refresh interval. The admin setting persists across restarts on both SQLite and PostgreSQL.
The sidebar can switch between retained runs and filter them by any number of metadata key/value pairs. Keys and values are selectable from those present in the application's retained runs, so users do not have to type CI identifiers manually. Every pair uses exact string matching and all supplied pairs must match.
By default, Stove retains the newest completed run for each application, preserving the previous local behavior. Set --retention-runs-per-app N or STOVE_RETENTION_RUNS_PER_APP=N to keep more; 0 keeps unlimited history. Running runs are not removed by automatic retention. Ingestion keeps a just-completed run through its receipt and live-event commit; if it falls outside the retention window, a later retention pass removes it. In PostgreSQL mode the value is shared and persisted; in SQLite mode it belongs to the current process.
Storage backends¶
SQLite remains the zero-configuration default and stores data at ~/.stove-dashboard.db. For a server shared by CI jobs, teams, and agents, configure PostgreSQL with either form:
stove --database-url 'postgresql://stove:secret@db.example/stove'
STOVE_DATABASE_URL='postgresql://stove:secret@db.example/stove' stove
stove --database-url-file /run/secrets/stove/database-url
PostgreSQL connections use TLS by default. Add ?sslmode=disable only for a trusted PostgreSQL endpoint that intentionally has no TLS. Stove applies versioned migrations at startup. Refinery owns migration discovery and history (refinery_schema_history); backend-specific SQL lives in parallel server/stove-server/src/storage/migrations/sqlite/ and server/stove-server/src/storage/migrations/postgres/ directories. Diesel owns normal reads and writes. Raw SQL is limited to backend-specific coordination and queries whose CTE, JSON attribution, aggregation, or SQLite rowid behavior is not usefully expressed by the ORM.
This storage rewrite is intentionally a clean break. Databases created by a server version that recorded migrations in schema_migrations are not upgraded or imported. Delete the local SQLite database, or recreate the PostgreSQL database/schema, before starting this version. Run metadata is stored as JSONB with a GIN jsonb_path_ops index, so dynamic exact-subset filters remain efficient without predeclaring keys.
--db and --fresh-start are SQLite-only; Stove rejects --fresh-start when PostgreSQL is selected. --clear operates on the selected backend.
Fault tolerance¶
Dashboard is opt-in and non-blocking:
- Events queue locally; publishing (gRPC or HTTP) happens in the background.
- If the server is down or unreachable, the emitter auto-disables for the rest of the suite. Tests continue. No flakes.
- Tests never wait on the dashboard.
REST API¶
The server exposes REST endpoints for integration:
| Endpoint | Use |
|---|---|
GET /api/v1/meta |
discovery; version, capabilities, MCP availability |
GET /api/v1/top-filter |
configured browsing field, recorded keys, values, and matching application summaries |
GET /api/v1/apps |
list registered apps |
POST /api/v1/events |
ingest a protobuf-encoded DashboardEvent; responds with a protobuf EventAck |
GET /api/v1/runs?app=...&metadata=... |
list runs by app and/or an exact metadata subset |
GET /api/v1/runs/{run}/tests |
tests in a run |
GET /api/v1/runs/{run}/mock-interactions |
mock exchanges for a run; append /ambient for unattributed exchanges |
GET /api/v1/runs/{run}/mock-warnings |
mock diagnostics for a run; append /ambient for unattributed diagnostics |
GET /api/v1/runs/{run}/tests/{test}/mock-interactions |
mock exchanges attributed to a test |
GET /api/v1/runs/{run}/tests/{test}/mock-warnings |
mock diagnostics attributed to a test |
GET /api/v1/traces/{trace_id} |
span tree |
GET /api/v1/events/stream |
SSE: live test events |
Useful for CI artifact extraction, custom analyzers, or building tooling on top.
The metadata query value is a URL-encoded JSON object whose values must be strings. Every supplied pair must match:
curl --get 'http://localhost:4040/api/v1/runs' \
--data-urlencode 'app=checkout-api' \
--data-urlencode 'metadata={"team":"checkout","gitlab.pipeline_id":"12345"}'
Agents can apply the same dynamic filter through stove_runs:
Idle run cleanup¶
Running runs left behind by cancelled CI jobs or failed runners are permanently deleted after 3600 seconds (1 hour) without newly committed ingestion. A background worker checks at startup and every 60 seconds, even without incoming requests. Deletion cascades to all tests, evidence, and ingestion receipts belonging to the run. Completed runs are unaffected; no additional status is introduced.
Set Admin → Idle run cleanup → Idle timeout (seconds) to change the timeout. Use 0 to disable automatic expiry. This setting is persisted in both SQLite and PostgreSQL; PostgreSQL replicas share it. A change applies on the next sweep. Reducing the timeout can permanently delete runs already idle beyond the new value.
For a new database, --run-idle-timeout-seconds, STOVE_RUN_IDLE_TIMEOUT_SECONDS, or file property run_idle_timeout_seconds seeds the value, using normal configuration precedence. The default is 3600 everywhere. Once stored, the Admin value takes precedence over startup configuration and survives restarts.
Activity uses the database receipt clock, independent of producer timestamps. Duplicate retries and rejected events do not extend the deadline. A healthy test with no new ingestion for an hour can also expire; increase the timeout for long, silent work. Existing runs are migrated using their latest ingestion receipt, or migration time when receipt history is absent.
New valid ingestion before the sweep refreshes the deadline. Once deleted, late test or completion events cannot revive the run. Open dashboards receive a durable deletion event and discard the removed run and evidence.
PostgreSQL uses the built-in pg_try_advisory_lock on a dedicated session so only one pod sweeps a shared database at a time. Losing or closing that session releases the lock. Per-run transaction locks serialize expiry with ingestion, and the worker rechecks activity after taking the lock. No extension or separate coordination service is required.
Administration¶
Select Admin in the dashboard header to open the dedicated /admin page, where you can inspect storage, browse the active database, run SQL, change runtime retention, preview and purge matching runs, or clear all data. SQL mutations and destructive administration operations require confirmation. A retention change prunes excess completed runs immediately. It lasts for the current process with SQLite and is persisted as a shared setting with PostgreSQL.
Purge preview accepts an optional application and RFC 3339 older_than cutoff, then returns the exact run IDs and evidence counts. Purging uses those IDs. Both preview and purge exclude active runs unless include_running is explicitly true.
| Endpoint | Use |
|---|---|
GET /api/v1/admin/status |
backend, retention, idle timeout, run, and evidence counts |
GET /api/v1/admin/database/schema |
active backend, tables, columns, nullability, and primary keys |
POST /api/v1/admin/database/query |
run one SQL statement with sql and optional max_rows |
PUT /api/v1/admin/top-filter |
set the browsing field with {"metadata_key": "gitlab.team"}; use null to disable |
PUT /api/v1/admin/idle-timeout |
persist idle timeout with {"run_idle_timeout_seconds": 3600}; 0 disables expiry |
PUT /api/v1/admin/retention |
set runtime retention with {"runs_per_app": 50} |
POST /api/v1/admin/purge/preview |
preview with app_name, older_than, and include_running |
POST /api/v1/admin/purge |
delete exact run_ids; active runs still require include_running |
DELETE /api/v1/data |
clear every run and all evidence |
Database explorer¶
The database explorer is implemented by Stove itself and runs inside the Rust process; it does not require a sidecar or separate admin service. The UI provides table and column discovery, editable SELECT/INSERT/UPDATE/DELETE templates, a result grid, and confirmation before running a statement it considers mutating. The same operations are available through REST:
curl http://localhost:4040/api/v1/admin/database/schema
curl -X POST http://localhost:4040/api/v1/admin/database/query \
-H 'Content-Type: application/json' \
-d '{"sql":"SELECT id, app_name FROM runs ORDER BY started_at DESC","max_rows":100}'
The query endpoint accepts one statement up to 64 KiB. max_rows defaults to 100 and is clamped to 1–500. PostgreSQL SELECT results use a server-side cursor and fetch only max_rows + 1 records, so the truncated flag does not require materializing an unbounded result in Stove. PostgreSQL statements have a 10-second timeout. SQLite uses a dedicated peer connection and stops stepping through the result after the truncation check. Non-row statements return affected_rows; row values are returned as strings or null.
The explorer has direct write access to Stove's tables. Confirmation in the browser is a safety prompt, not an authorization boundary, and direct SQL changes can violate application invariants. Keep the endpoint on a trusted operator network and prefer the purpose-built retention, purge, and clear controls for routine operations.
Trusted networks only
The dashboard, REST API, database explorer, admin operations, gRPC ingestion, and MCP endpoint intentionally have no authentication or authorization. The servers listen on all interfaces so remote CI jobs and agents can connect. Deploy Stove only on an internal trusted network and control exposure outside Stove (for example with firewall rules or a private ingress).
Server options reference¶
| Flag | Default | Notes |
|---|---|---|
--config-file |
unset | TOML or JSON configuration path; also STOVE_CONFIG_FILE |
--log-format |
json |
json or text; also STOVE_LOG_FORMAT or config-file log_format. Verbosity is controlled by RUST_LOG (default info) |
--public-url |
unset | browser URL for MCP citations, including an optional path prefix; also STOVE_PUBLIC_URL or config-file public_url |
--port |
4040 | web UI, REST, and MCP; also STOVE_PORT |
--grpc-port |
4041 | event ingestion from Stove tests; also STOVE_GRPC_PORT |
--db |
~/.stove-dashboard.db |
persistence path; also STOVE_DB |
--database-url |
unset | PostgreSQL URL; replaces SQLite. Also configurable with STOVE_DATABASE_URL |
--database-url-file |
unset | file containing the PostgreSQL URL; also STOVE_DATABASE_URL_FILE |
--run-idle-timeout-seconds |
3600 (1 hour) | initial idle timeout; 0 disables expiry. Also STOVE_RUN_IDLE_TIMEOUT_SECONDS or file property run_idle_timeout_seconds; persisted Admin changes override this seed |
--retention-runs-per-app |
1 | completed runs kept per app; 0 keeps all runs. Also configurable with STOVE_RETENTION_RUNS_PER_APP |
--clear |
off | clear stored runs and exit |
--fresh-start |
off | back up and recreate the SQLite DB before serving; unsupported with PostgreSQL |
Acceptance and load tests¶
From server/stove-server, run the public-boundary acceptance suite with a Docker-compatible daemon available:
The acceptance suite verifies the same ingestion, filtering, retention, administration, UI, and MCP behavior against SQLite and a disposable PostgreSQL instance created with testcontainers 0.28.0. The separate load test seeds 50,000 PostgreSQL runs, requires the planner to use the metadata GIN index, and mixes concurrent dashboard, REST, admin, and MCP reads under a configurable p95 latency budget. See server/stove-server/acceptance-tests/README.md for tuning variables and the manual browser workflow.
Pairs well with¶
-
Tracing. Span tree shows up in Trace view.
-
MCP. Same database, agent-readable.
-
Reporting. Console reports plus dashboard history cover complementary debugging surfaces.
-
When a test fails. Dashboard is step 3 of the failure flow.
Troubleshooting¶
| Symptom | Check |
|---|---|
| Dashboard empty | stove running? dashboard { } registered in Stove().with? appName set? |
| Events not arriving | Port mismatch. DashboardIngestion.Grpc(port = ...) must match --grpc-port |
| "gRPC disabled" warning | Expected if the server started after tests; restart in correct order |
| Cancelled CI run remains running | After 1 hour without newly committed ingestion, the next sweep deletes the run and its tests and evidence. Check Admin’s idle timeout and worker health if it remains running. |
| Disk filling up | Set --retention-runs-per-app (or STOVE_RETENTION_RUNS_PER_APP) to limit completed runs per app |
Continuous profiling¶
In 0.28.0 (upcoming), Stove Server receives Pyroscope Java JFR and native Go pprof recordings and
provides Drill Down for CPU and memory investigation, with no separate
profiling backend. Enable collection in the tracing Gradle plugin and keep the
normal dashboard integration. The plugin profiles the test JVM; Go applications use go/stove-profiler
and dashboard-exposed run configuration.
See Profiling and Drill Down for the complete setup, HTTPS configuration, language support, recording lifecycle, memory-leak interpretation, MCP workflow, ingestion contract, and resource limits.