Tutorial: Ops Dashboard¶
You are going to build a running local ops dashboard — a FastAPI-backed server that exposes a workflow runner with a per-feature scope picker, persisted run history, and live SSE log streaming. When you finish, you will have a process you can open in a browser and use to trigger attune workflows against a real project directory.
Prerequisites¶
- Python 3.10 or newer
attuneinstalled in your environment (pip install attune)- A project directory on disk (any folder with at least one workflow configured)
What you will build¶
A local server started from Python that:
- Reads your project and attune state through a
Configobject - Serves the ops dashboard on
http://127.0.0.1:8765 - Exposes KPI numbers and a cost sparkline on the home page
- Lists features and workflows scoped to your project directory
You will write roughly fifteen lines of Python and end up with a browser tab showing live dashboard data.
Step 1 — Import the public API¶
The attune.ops module uses lazy imports so that loading attune in other contexts doesn't pull FastAPI into memory. Import only what the public API exposes:
You should see: no import errors. If you get ModuleNotFoundError, confirm that attune is installed in the active virtual environment.
Step 2 — Build a Config for your project¶
Config is the single source of truth for where the dashboard reads project state and attune data. You build one with build_config, which resolves environment defaults for anything you leave unspecified:
from pathlib import Path
config = build_config(
project_root=Path("."), # your project directory
host="127.0.0.1",
port=8765,
)
build_config fills in attune_home automatically (checking the ATTUNE_HOME environment variable, then falling back to ~/.attune), so you only need to supply values that differ from the defaults.
You should see: a Config instance. Print it to confirm the paths resolved correctly:
print(config.project_root) # absolute path to your project
print(config.attune_home) # e.g. /home/you/.attune
print(config.runs_dir) # where run history will be persisted
Step 3 — Inspect what the dashboard will surface¶
Before starting the server, confirm that the dashboard can find your project's features. This step teaches you the data model the home page is built from.
list_features reads .help/features.yaml from your project root and returns a list of Feature objects — one per entry in that file:
from attune.ops.data import list_features, first_feature
features = list_features(config.project_root)
for f in features:
print(f.name, f.path, f.tags)
lead = first_feature(config.project_root)
print("Scope picker will default to:", lead)
Each Feature has a name, a description, an optional path (used as the scope argument), and a tuple of tags. The scope picker in the dashboard UI uses exactly this list.
You should see: one line per feature defined in .help/features.yaml. If the file doesn't exist yet, both calls return an empty list / None — that's fine; the dashboard still starts.
Step 4 — Create the FastAPI application¶
create_app wraps the FastAPI factory. Calling it wires up all routes — the home page KPIs, the workflow runner endpoints, the SSE log stream, and the TrustedHostMiddleware that guards the server using config.trusted_hosts:
create_app is intentionally lazy: it imports FastAPI only at this call site, not at module import time. That is why it takes a Config rather than raw kwargs — all runtime decisions are already resolved before the factory runs.
You should see: a FastAPI application object. Confirm with:
print(type(app)) # <class 'fastapi.applications.FastAPI'>
print([r.path for r in app.routes]) # list of registered URL paths
Step 5 — Start the server¶
Use uvicorn to serve the app. The dashboard is a blocking process, so run this as the last statement in your script (or from the command line):
Alternatively, use the built-in CLI entrypoint, which does exactly the same thing:
Or invoke the module directly:
You should see: uvicorn startup lines followed by:
Open http://127.0.0.1:8765 in a browser. The home page should display today's event count, today's cost, and a seven-day cost sparkline drawn from your telemetry data in ~/.attune.
Step 6 — Verify the KPI data model¶
While the server is running, step back and look at how the home page numbers are derived. home_kpis takes a TelemetrySummary and produces a HomeKpis — this is what the dashboard's home-page endpoint calls internally:
from datetime import date
from attune.ops.data import home_kpis, TelemetrySummary
# Construct a minimal summary to see the shape of the output
summary = TelemetrySummary(
total_requests=42,
total_cost=1.25,
total_savings=0.30,
by_workflow=[("my-workflow", 10, 0.50)],
by_day=[("2026-05-14", 10, 0.50)],
last_event_at="2026-05-14T12:00:00",
)
kpis = home_kpis(summary, today=date(2026, 5, 14))
print(kpis.today_events) # 10
print(kpis.seven_day_cost) # 0.50
print(kpis.sparkline) # list[DailyCost]
HomeKpis.sparkline is the list of DailyCost objects that the front end uses to draw the cost chart. Each DailyCost holds a day string, an events count, and a cost float.
You should see: the printed values match what you put into TelemetrySummary. This confirms you understand the data flow from raw telemetry to the numbers above the fold.
What you learned¶
- Step 2 —
build_configis the single place where project paths, host/port, and attune home are resolved. You never pass raw strings tocreate_app. - Step 3 — The scope picker is backed by
list_features, which reads.help/features.yaml. If that file is empty or absent, the picker is empty — not broken. - Step 4 —
create_appis a lazy factory. FastAPI is imported only when you call it, keepingattuneimportable in environments that don't have FastAPI installed. - Step 5 — The same server is reachable three ways: as a library (
uvicorn.run(app, ...)), as a CLI subcommand (attune ops), or as a module (python -m attune.ops). All three paths converge on the sameConfigandcreate_app. - Step 6 —
home_kpisis a pure function. You can unit-test the KPI logic without starting a server by constructing aTelemetrySummarydirectly.
Next steps¶
- How-to: use the ops dashboard — task-focused recipes for the dashboard's core API
- Reference: ops-dashboard CLI — every command-line flag, environment variable, and exit code
- Architecture: ops-dashboard — design decisions, key classes, and the data-flow diagram