Skip to content

Start and monitor the daemon with firma sidecar and firma monitor

firma sidecar start boots the Authority and Sidecar as a single daemon-mode pair. firma sidecar stop tears them back down. firma monitor is the read-only counterpart — a live tail of audit events and component logs from the running daemon. Together they replace the old firma stack supervisor and the hand-rolled firma authority & / firma sidecar & pattern from earlier guides.

This guide covers a typical operator flow: scaffold a project, boot the daemon, observe what it’s doing, and tear it down cleanly.

  • A built workspace: cargo build --release from the repo root.
  • protoc installed.
  • Familiarity with the Quickstart and Run the Sidecar standalone. Those pages show what firma sidecar start automates away.

firma init writes a fresh project layout. Project-local config goes under <workspace>/.firma/; keys and revocation state go under the user-global state directory.

Terminal window
# Interactive wizard.
firma init
# Or scripted with every value supplied.
firma init --agent codex --provider anthropic \
--workspace ./proj --authority local --yes

Layout written:

./proj/.firma/
firma.toml authority.key audit.key
mapping-rules.toml policies/ issuance-policies/
$XDG_DATA_HOME/firma/ # or %LOCALAPPDATA%\firma on Windows
revocations.txt
generated-firma-ca/
# populated by sidecar start: authority.pid, sidecar.pid, stack.pid,
# stack.lock, authority.log, sidecar.log, supervisor.log,
# *.listen, audit.jsonl

init writes a single sectioned firma.toml ([project] + [authority] + [sidecar.*]). Existing files are preserved unless --force is set. state_dir is not embedded in the config — it is always resolved from --state-dir / FIRMA_STATE_DIR / XDG.

You can also skip init entirely: firma run <agent> invokes the same scaffold implicitly the first time it cannot discover a firma.toml.

See Initialize a project with firma init for the full flag table.

Terminal window
# Foreground. Ctrl-C cleanly tears both children down.
# --config defaults to the discovered firma.toml.
firma sidecar start
# Detached. Forks a supervisor process after readiness probes pass.
firma sidecar start --detach

What start does, in order:

  1. Boots the Authority in its own process group.
  2. Probes the Authority’s gRPC port until it accepts connections.
  3. Boots the Sidecar in its own process group.
  4. Probes the Sidecar’s listen port and waits for generated-firma-ca/ material.
  5. With --detach: forks a __supervise child that re-attaches to the pidfiles, then exits 0.
  6. Without --detach: blocks in the foreground until signalled.

If readiness fails at any step, start rolls back — every spawned child is signalled and pid/listen/lock files are cleaned up. You will not be left with half a daemon.

start flags:

FlagEnvDefault
--configFIRMA_SIDECAR_CONFIG_FILEdiscovered firma.toml
--state-dirFIRMA_STATE_DIR$XDG_RUNTIME_DIR/firma/tmp/firma-$UID
--detachoff

start resolves firma.toml via the shared Config Discovery precedence and passes that exact file to both children with --config. state_dir is never a config-file key.

Terminal window
firma sidecar status # docker-ps-style listing
firma sidecar status --json # machine-readable
firma sidecar status --daemon # daemon-mode pid only

See Inspect live sidecars for the full table and exit codes.

Terminal window
firma sidecar stop --state-dir /var/run/firma
firma sidecar stop --state-dir /var/run/firma --timeout 10

Stop order is intentional: the Sidecar is soft-signalled first so the Authority’s tonic graceful shutdown is not blocked on long-lived gRPC streams. The supervisor and Authority follow. Survivors past --timeout (default 2 s) are hard-killed; children are reaped via waitpid(WNOHANG) so zombies are not mistaken for live processes.

Exit codes: 0 on success (graceful or hard-kill fallback), 2 on error.

Tail decisions and logs with firma monitor

Section titled “Tail decisions and logs with firma monitor”

firma monitor is read-only and decoupled from sidecar: it tails files in the state directory. Multiple concurrent monitors are safe; the daemon does not need to know they exist.

Terminal window
# Everything: audit events plus authority + sidecar logs.
firma monitor --state-dir /var/run/firma
# Just denials, last 15 minutes, JSON output for piping into jq or a collector.
firma monitor --state-dir /var/run/firma \
--source audit --decision deny --since 15m --format json
# Authority logs only, one shot (no follow).
firma monitor --state-dir /var/run/firma \
--source authority --no-follow
# Filter by action class.
firma monitor --state-dir /var/run/firma \
--source audit --action-class communication.external.send

monitor flags:

FlagDefaultDescription
--configunsetAccepted for compatibility; not used to resolve state.
--state-dirresolvedState dir override.
--sourceallaudit, authority, sidecar, or all.
--no-followoffRead once and exit; default is to follow tail.
--decisionunsetAudit-only: allow, deny, passthrough.
--action-classunsetAudit-only: exact match on intent.action_class.
--sinceunsetBackfill window: 15m, 2h, 1d or RFC3339 timestamp.
--formatprettypretty (human) or json (one object per line).

--decision and --action-class apply to audit events only — they are silently ignored for authority and sidecar log lines. The tailer detects log rotation by inode and reopens automatically.

For everything you can do with the underlying audit JSONL — signature verification, structured search, debugging surprise denies — see Read & verify the audit log.

firma sidecar and firma monitor both operate on the state directory:

<state_dir>/
authority.pid authority.log authority.listen
sidecar.pid sidecar.log sidecar.listen
stack.pid stack.lock supervisor.log
audit.jsonl
generated-firma-ca/

Resolution order: --state-dir flag → FIRMA_STATE_DIR env → platform default. The Unix default is $XDG_RUNTIME_DIR/firma, falling back to /tmp/firma-$UID. Windows uses %LOCALAPPDATA%\firma\runtime then %TEMP%\firma. state_dir is never read from the config file.

sidecar start exits 2 with “address in use”. Another sidecar or authority is bound to the listen address — most often a previous foreground run that was not fully reaped. Run firma sidecar stop --state-dir ... first, or change the listeners by editing firma.toml (or re-running firma init --force with different --authority-listen / --sidecar-listen).

sidecar status reports “stopped” but the pidfile exists. The process is gone but the file was not cleaned up (sigkill from outside, OOM, host reboot). sidecar start will not refuse to boot in this case; the stale pidfile is overwritten once the new process registers. If in doubt, sidecar stop first.

monitor --since 24h returns nothing. audit.jsonl is append-only but is created fresh on each firma init. If the state dir was wiped or recreated, there is nothing to backfill. Confirm with ls -l <state_dir>/audit.jsonl.

Two firma sidecar start invocations against the same state dir. The second one fails fast on stack.lock. This is intentional — running two supervisors against one set of pidfiles is undefined.

Detached supervisor does not exit when the terminal closes. That is the point of --detach. The supervisor reparents to PID 1 (Unix) or runs as a Job Object (Windows) and survives the shell exiting. Stop it with firma sidecar stop, not by killing the terminal.