arizuko

arizukocomponents › dashd

dashd

What it is

In plain terms, dashd is the control panel for whoever runs the instance. Open it in a browser to see groups, messages, and tasks, and to edit a few of the agent’s files.

dashd is the operator dashboard: an HTMX server that renders pages over messages.db and a fixed set of markdown files. Reads are the default; the only write paths are PUT and DELETE on that markdown list under each group’s folder.

Routes live at /dash/*. The portal at /dash/ links to status, tasks, activity, groups, memory, and profile pages, each rendered server-side as one HTML page plus HTMX partials for live sub-views.

Why it exists

Without dashd, operators inspect an arizuko instance through sqlite3 messages.db, journalctl -u arizuko_<inst>, and the arizuko CLI. That works for an engineer, but it asks a lot of anyone else, and it never gives a one-screen answer to “what is this instance doing right now”.

dashd owns no tables of its own. It reads from tables other daemons own — groups, routes, scheduled_tasks, messages, sessions, channels, auth_users, written by routd, authd, timed, and onbod — and renders them. The plan in specs/5/5-uniform-mcp-rest.md is to move those direct reads onto the sibling daemons’ /v1/* APIs, leaving dashd a pure client.

How it fits

operator browser
        |
        v   /dash/...
        |
      proxyd   requireAuth: JWT or refresh-token cookie
        |      stamp X-User-Sub, X-User-Groups, HMAC sig
        v
      dashd    render HTML / HTMX partial
        |      read: messages.db (today)
        |      write: PUT|DELETE /dash/memory/{folder}/{rel}
        v
      filesystem: <groups>/<folder>/MEMORY.md, diary/*.md, ...

dashd reads identity from signed headers set by proxyd’s requireAuth, and it checks the signature itself: every /dash/* handler — read views included — runs through guard, which calls auth.RequireSigned(PROXYD_HMAC_SECRET). A request that skips proxyd carries no valid X-User-Sig, so it never reaches a handler. Only /health, /openapi.json, and the htmx asset stay public. Write verbs go further: every TIER 1 mutation runs requireAdmin, which calls auth.Authorize with action admin against the caller’s groups, plus a same-origin CSRF guard.

Two write paths today. The memory editor accepts MEMORY.md, .claude/CLAUDE.md, and flat *.md under diary/, facts/, users/, and episodes/. Reads are capped at 1 MiB, and the path joiner blocks any symlink that escapes the group folder. TIER 1 admin — routes editor, groups CRUD, per-user secrets — sits behind the admin check above.

Standalone usage

dashd needs a SQLite file and a port. Set PROXYD_HMAC_SECRET to the same value proxyd uses and dashd verifies every /dash/* request’s signature itself — an unsigned request gets redirected to login. Leave it unset for local dev and the guard passes through, which is why you still front dashd with proxyd on the public internet: proxyd terminates TLS, runs the login flow, and stamps the signed headers dashd trusts.

export DATA_DIR=/srv/data/arizuko_demo
export DASH_PORT=:8080
export INSTANCE_NAME=demo
./dashd
# browse http://localhost:8080/dash/

DATA_DIR resolves the database at $DATA_DIR/store/messages.db and the groups tree at $DATA_DIR/groups/. Set DB_PATH to override the database location independently. INSTANCE_NAME appears in the portal header.

Health: GET /health returns 200 when the database is reachable. With PROXYD_HMAC_SECRET set, exposing dashd directly still rejects unsigned requests — but proxyd owns TLS and the login flow, so front it with proxyd anyway.

The page set

Read views (each one HTML the browser renders directly):

HTMX partials (tasks/x/list, activity/x/recent) feed live sub-views.

TIER 1 admin pages (admin auth + CSRF):

The migration to /v1/*

Today every page queries SQLite directly. The plan is to swap each read for a call to the sibling daemon that owns the table:

After the migration dashd holds an operator session token (issued by proxyd at OAuth login), forwards it as Authorization: Bearer ... on every /v1/* call, and stops touching messages.db at all.

What dashd does not do

dashd does not send messages, schedule tasks, mint tokens, or admit users — those belong to routd, timed, proxyd, and onbod. Writes are scoped to the surfaces listed above: memory editor and TIER 1 admin. Everything else is a view.

Go deeper