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
$ 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.
$ grith daemon status
Dashboard is not running.
Start: grith dashboard startstatus 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/:
| File | What it holds |
|---|---|
dashboard.pid | Two lines: the pid, then the port |
dashboard.opened | The daemon pid a browser tab was already opened for |
daemon.token | IPC bearer token, mode 0600, rotated on every start |
dashboard.token | Browser token, mode 0600, stable across restarts |
daemon.json | Instance UUID, pid, port, version, IPC protocol version, audit DB path |
reputation.toml | The 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:
[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:
$ grith daemon pairThat 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.
| Field | Meaning |
|---|---|
status | healthy, degraded or unhealthy |
version | Daemon version - compare it with your CLI |
uptime_seconds | Seconds since this daemon started |
subsystems | Per-subsystem status for audit, digest, proxy and supervisor |
instance_id | UUID regenerated on every start, so a replaced daemon is detectable |
protocol_version | IPC contract version |
audit_quarantined | Present only when the audit chain is quarantined |
audit_read_only | Present 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.