grithdocs

Running as a daemon

What the grith daemon owns, when it starts and stops itself, and the files it keeps on disk.

You do not normally start the daemon. grith exec, grith run and the bare grith REPL start it on demand and it shuts itself down when the last session ends. This page is for the times you drive it yourself.

One process owns everything shared: the audit database (as its exclusive writer), the digest queue, the security proxy and its 18 filters, the session registry, the canary registry, the reputation table, and the HTTP server behind http://127.0.0.1:3141. grith exec is a thin client over loopback HTTP - if it cannot reach a version-matched, authenticated daemon, the tool is never spawned.

Commands

terminal
$ grith daemon --help
Manage the grith daemon (dashboard server + shared subsystems)

Usage: grith daemon [OPTIONS] <COMMAND>

Commands:
start    Start the daemon (dashboard server + shared subsystems) as a background process
stop     Stop the running daemon
restart  Restart the daemon (stop the running one, then start this build)
status   Check if the daemon is running
pair     Authorise a browser for the dashboard (mints a single-use pairing link)
help     Print this message or the help of the given subcommand(s)

dashboard is a retained alias for daemon, and some messages still print that spelling. Both work.

terminal
$ grith daemon status
Dashboard is not running.
Start: grith dashboard start

status reads ~/.config/grith/dashboard.pid; if that file is missing it probes the port anyway and reports what answers - a grith daemon (naming its version), a foreign process, or nothing.

Starting and idle shutdown

grith daemon start re-execs a detached child, then polls until a daemon of exactly this version answers, giving up after 12 seconds. Startup failures in the detached child are recorded and re-printed by the command you ran, so they are never silent.

A daemon grith auto-started exits 30 seconds after its last session ends. An explicit grith daemon start disables idle shutdown, so that one stays up until you stop it; server.idle_shutdown_seconds = 0 disables it too. Either way a reaper runs every 5 seconds, evicting sessions whose root process is dead and whose heartbeat has gone stale.

Stopping

grith daemon stop posts a shutdown over the authenticated IPC channel and falls back to SIGTERM, waiting up to 5 seconds for the process to actually go before dropping the PID file. Shutdown is bounded: 8 seconds to drain in-flight work, then a 2-second timeout. Process exit releases the audit writer lock at the kernel, so even a hard kill never leaves it stuck. An orphaned daemon - listening with no PID file - is still stopped, by token-authenticated request.

daemon.token and daemon.json are removed on exit. dashboard.token is deliberately kept, so browser tabs you have already authorised survive a restart.

Files on disk

Runtime state lives under ~/.config/grith/:

FileWhat it holds
dashboard.pidTwo lines: the pid, then the port
dashboard.openedThe daemon pid a browser tab was already opened for
daemon.tokenIPC bearer token, mode 0600, rotated on every start
dashboard.tokenBrowser token, mode 0600, stable across restarts
daemon.jsonInstance UUID, pid, port, version, IPC protocol version, audit DB path
reputation.tomlThe learned reputation table

There is no unix-domain socket: all IPC is loopback HTTP with the daemon.token bearer. The audit directory (general.audit_dir, default ~/.local/share/grith/audit/) holds audit.db, digest.db, writer.lock and cold/ - see Logging and audit retention.

Bind and TLS

The daemon binds 127.0.0.1:3141 over plain HTTP; loopback does not need TLS. To expose the dashboard beyond the machine, turn on native TLS:

toml
[server]
host = "0.0.0.0"

[server.tls]
cert_path = "/etc/grith/cert.pem"
key_path = "/etc/grith/key.pem"

Both TLS keys must be set together - one alone fails to parse. A reverse proxy is the alternative; see Reverse proxy and TLS.

Authorising a browser

grith opens a browser tab at most once per daemon instance, and skips it on headless or SSH sessions. To authorise another browser, a second machine, or one whose site data you cleared:

terminal
$ grith daemon pair

That mints a single-use code and puts it in the URL fragment, so it never reaches the server. Redeeming it hands the browser the real dashboard token and consumes the code, which makes a screenshot of the link inert.

Health check

GET http://127.0.0.1:3141/api/health needs no token, so it works as a liveness probe.

FieldMeaning
statushealthy, degraded or unhealthy
versionDaemon version - compare it with your CLI
uptime_secondsSeconds since this daemon started
subsystemsPer-subsystem status for audit, digest, proxy and supervisor
instance_idUUID regenerated on every start, so a replaced daemon is detectable
protocol_versionIPC contract version
audit_quarantinedPresent only when the audit chain is quarantined
audit_read_onlyPresent only when another process owns the writer lock

The last two are unauthenticated on purpose: grith exec reads them before starting a session, so a daemon that cannot durably record decisions is caught before a tool is spawned.

Under a service manager

grith ships no service unit and does not need one - the daemon starts on demand. If you want it permanently up, grith daemon start and grith daemon stop are both synchronous, which suits a Type=oneshot unit with RemainAfterExit=yes. Do not point PIDFile= at dashboard.pid: it holds two lines, not one.

See also

Last updated: 2026-08-24Edit this page on GitHub →