Skip to content

Observe the system

hal0 gives you three observation surfaces: journald per systemd unit, the API log tail (a thin wrapper over journald with filters), and the durable Activity / Audit log that survives restarts.

Every hal0 process runs under a systemd unit, so journalctl is the ground truth. The slots use a templated unit per slot name:

Terminal window
journalctl -u hal0-slot@<name>.service -f

For example, to follow the chat slot or the image-gen slot:

Terminal window
journalctl -u hal0-slot@chat.service -f
journalctl -u hal0-slot@img.service -f

The API exposes journald over HTTP so the dashboard (and your scripts) can read logs without shell access. Return the last n entries for a unit:

Terminal window
curl 'http://localhost:8080/api/logs?unit=hal0-api&n=200'
Query paramDefaultNotes
unitRequired. The systemd unit, e.g. hal0-api or hal0-slot@chat. Validated against a conservative character set.
n200Trailing lines, 1–5000.
sinceA journalctl --since value (ISO timestamp or '5min ago').
levelFilter to this priority and higher severity: warning returns warning and all higher-severity levels (error, critical, alert, emergency).

The hal0 dashboard Logs panel showing live journal output for a slot unit The dashboard Logs panel streams journal output for any hal0 unit in real time.

On a host without journalctl (e.g. CI), the endpoint returns an empty lines array plus a hint rather than erroring.

Stream a live tail as Server-Sent Events:

Terminal window
curl -N 'http://localhost:8080/api/logs/stream?unit=hal0-slot@chat&level=warning'

Each non-empty journal line arrives as a data: frame carrying the line as a JSON string. The stream closes its subprocess when you disconnect.

journald is a volatile tail. For a permanent record of what changed, hal0 keeps a SQLite audit store (/var/lib/hal0/activity.db, preserved across updates). It records every config-mutating user action and every system state change — each with a before/after snapshot and a success/failure outcome. It’s read-only over the API (it must render on the slots page during first run).

List recent activity:

Terminal window
curl 'http://localhost:8080/api/activity?limit=200'

The response is {"records": [...], "next_since": <id>, "epoch": "..."}. Poll with ?since=<next_since> to page forward. Server-side filters (combine freely):

FilterValues
sinceid cursor — return records newer than this id.
categoryfree-form category string.
actionfree-form action name.
severityinfo, warn, error, ok.
outcomeok, error, pending.
actorthe agent / actor that performed the action.
kindaction (a user action) or event (a system state change).
searchfull-text match.
limit1–1000 (default 200).

Stream the durable backfill then a live tail (filters honoured server-side):

Terminal window
curl -N 'http://localhost:8080/api/activity/stream?kind=action'

Export the filtered history as a file download:

Terminal window
curl 'http://localhost:8080/api/activity/export?fmt=csv' -o hal0-activity.csv
curl 'http://localhost:8080/api/activity/export?fmt=json' -o hal0-activity.json
  • Manage slots — the slot lifecycle whose transitions show up in the activity log.
  • Edit configuration — config changes are audited.
  • Security — the LAN-open posture and what is (and isn’t) logged.