observability — making the system visible without going through the logsA system that behaves like Metnos — ReAct planner, synt that generates executors, mnestome that grows, vaglio that judges, pairing that recognises senders — produces a great deal of state. The observability dashboard is the way to see that state without opening terminals, without inspecting SQLite by hand, without grepping the JSONL logs. A single HTML file, one page that summarises everything an owner needs to understand where the system has got to.
The architectural choice is deliberately non-live: no server, no WebSocket, no JavaScript. The file is generated on demand by a Python script that reads the same authoritative data sources of the runtime, transcribes them into HTML, and stops. Open it in a local browser.
| Source | What it provides | Path |
|---|---|---|
| Mnestome | Global stats (total mnest, active, proto, decaying, events), top-N active by weight, top-N proto-mnest awaiting synthesis, last 20 chronological events. | ~/.local/share/metnos/.mnestoma/mnest.sqlite (override MNESTOMA_DB_PATH) |
| Pairings | Active pairings (channel, sender_id, level, paired_at, paired_by, last_seen) and number of revoked pairings in the history. | ~/.local/state/metnos/pairings.db |
| Turns | Last 15 turns executed by the planner (timestamp, user query, outcome, step count, first line of the answer). | ~/.local/share/metnos/turns/YYYY-MM-DD.jsonl |
| Vaglio | Last 20 decisions of the Vaglio (executor, score, blocked_by, abbreviated reasoning, ts). | ~/.local/share/metnos/vaglio/YYYY-MM.jsonl |
| Scheduler | Builtin runtime tasks (apply_ager, synt_suggest, …), schedule, last execution, outcome. |
~/.local/share/metnos/scheduler/state.sqlite |
| Test framework | Number of modules, number of test cases, last_status distribution, top modules by case count. | /opt/myclaw/runtime/testing/tests.db |
None of these sources was created for the dashboard: each one already existed as a source of truth for a runtime component. The dashboard is one more consumer; it writes nothing.
render_dashboard
The exposed function is observability.render_dashboard(out_path).
For each source there is a small private helper
(_collect_mnestoma, _collect_pairings,
_collect_recent_turns, …) that opens the source in
read-only mode, gathers a serialisable dict, and returns it.
If a source is missing or raises (e.g. SQLite does not exist because
the scheduler has never been started), the helper returns an empty dict or a
dictionary with the error key: the dashboard renders
an informative note but does not break.
The render is a single pass: no template engine, no external dependency. Just Python helpers concatenating HTML strings. Same inline CSS as the canonical docs (for visual consistency with metnos.com), static tables and cards, no JavaScript.
The produced HTML file contains, in order:
approve, red for block:guard or block:judge. Answers the question «is the guard holding? Am I blocking too much or too little?».
Everything that comes out of a source goes through html.escape
before being inserted into the DOM. The case is guaranteed by the test
render_html_escape_sicuro: even if a sender_id contains
<script>, the produced file shows
<script> — never an active tag. An
observability dashboard is not an attack surface, but it takes
discipline to keep it that way.
args_keys (not the values), the pairing
does not log the payload of the code but only its code_id, mail
attachments are never materialised in the turn log. The
dashboard inherits these choices: if it is not in the source, it is not in the
produced file.
The default file is workspace/dashboard/index.html, which
lives under METNOS_HOME and is not deployed on
metnos.com (it is a local operational tool). To consult it:
file:///opt/myclaw/workspace/dashboard/index.html in the
browser, or scp from the server to Roberto's machine if one wants
to look at it remotely.
The file is output-only. It is regenerated every time
python3 -m observability render is launched: typically 100 ms. The
next evolution (see ch. 8) will be a task of the
builtin scheduler that
regenerates it every N minutes.
python3 -m observability render # default: workspace/dashboard/index.html python3 -m observability render --out path.html # custom path
No subcommands other than render in v1.1. The
generator offers no JSON dump or export: those who want the raw data go
straight to the sources (SQLite + JSONL).
metnos-server.render_dashboard, every 5 min) will
keep it fresh without intervention.