Sealrdocs

Quickstart

Record a real operation, watch a guardrail block one, and verify the evidence offline — in five minutes, with no account and no network.

By the end of this page you will have blocked a DELETE with no WHERE clause, exported the evidence, and verified it with an offline verifier. No account, no Console, no network calls.

1. Install

Download the signed binary for your platform, or build from source — see Installation. Both sealr (the recorder) and sealr-verify (the standalone offline verifier) ship in every archive.

sealr version

2. Initialize

sealr init

Leaving --endpoint unset selects offline mode: nothing is sent anywhere, and no account exists to send it to.

Initialized recorder at /home/you/.local/share/sealr
  stream_id: 01K2E9V4Q7YB3T8N0C6HRXZ5MF
  mode: offline (local)
  keystore: file backend (see ADR-010 for the security delta)

That directory is the recorder home ($SEALR_HOME, defaulting to ~/.local/share/sealr and %LOCALAPPDATA%\sealr on Windows). init creates four things in it:

PathWhat it is
config.jsonStream id, recorder id, and whether sync is on (it is not)
identity/recorder.keyThis recorder's Ed25519 signing key, in the encrypted-file keystore
identity/recorder.pem, identity/root.pemA local trust chain — local dev root, local tenant CA, recorder certificate
spool/Append-only record segments and the checkpoint log

The local trust chain is what makes offline evidence verifiable end to end: exports carry their own root, so a verifier can validate the certificate that signed them without contacting anyone. Its certificate common names say "Local Dev" so that nobody mistakes it for a Sealr-issued production identity.

3. Record something

sealr run wraps any command, records what was executed, then runs it:

sealr run -- git --version

The record holds the argv, working directory, exit code, duration, and BLAKE3 digests of stdout and stderr — the digests, not the output itself. For commands Sealr recognizes (psql -c, terraform, git push) it also parses the operation and attaches the guard's structural classification.

4. See a guardrail fire

Recording is the default; enforcement is opt-in per invocation with --enforce.

sealr run --enforce --resource db:prod-main -- psql -c "DELETE FROM users"
sealr: command BLOCKED by policy (SQL_UNBOUNDED_WRITE).
echo $?   # 20

The SQL guard parsed that statement with the real PostgreSQL grammar, found a DELETE with no WHERE clause, and classified it unbounded_write / risk CRITICAL with reason code SQL_UNBOUNDED_WRITE. Exit code 20 is the recorder's "blocked" code, distinct from anything psql itself could return.

psql never ran, and it does not need to be installed for this to work. The block happens before the child process is spawned — that is the point of a pre-execution guard. Drop --enforce and the same statement is recorded with the same verdict but executes normally, which is how you roll Sealr out before you trust it to say no.

Git works the same way. main, master, release/* and prod* are the default protected branch patterns:

sealr run --enforce --resource repo:acme/api -- git push --force origin main
# sealr: command BLOCKED by policy (GIT_FORCE_PUSH_PROTECTED).   [exit 20]

Why this blocks with no policy installed

You have not written a policy, and there is no Console to hand you one. When no policy rule matches, the verdict falls through to the guard's own default decision, and the SQL guard's default for an unbounded write is BLOCK. Policies exist to override those defaults — to allow what a guard would refuse, to require human approval instead of blocking, and to bind enforcement to specific resources so --enforce is not a per-command decision. See Policies when you get there.

--resource db:prod-main is the resource label recorded against the operation and the string policy bindings match on. It changes nothing here, because there are no bindings yet.

5. Export and verify

sealr export -o evidence.seal
Exported evidence.seal (manifest hash 9f2c…)

The bundle contains the stream's records, the signed checkpoints attesting them, and the identity chain and root needed to check the signatures. Now verify it — with the standalone verifier, which shares no state with the recorder:

sealr-verify evidence.seal --root ~/.local/share/sealr/identity/root.pem
RESULT: PASS

Proven: N records across 1 stream(s); N attested by checkpoints; 0 anchored.
Recorded span: 2026-08-12T09:14:02Z .. 2026-08-12T09:16:41Z

Your record count will be higher than the number of commands you ran: a wrapped command that executes produces both a request and an outcome record, and each run closes its segment with a lifecycle record.

sealr verify evidence.seal runs the same checks in-process if you would rather not switch binaries. Exit codes: 0 pass, 10 pass with findings, 11 fail.

Pass --root for offline bundles. Released verifier binaries embed the production Sealr roots, and your local dev chain is not under them — without --root, verification of a locally-generated bundle fails with checkpoint_cert_unknown. A verifier built from source embeds no roots at all; it falls back to the bundle's own roots.json and reports a root_bundle_pinned warning, which is PASS WITH FINDINGS (exit 10). The warning is correct: a bundle that supplies its own root proves internal consistency, not origin.

0 anchored is also correct and worth reading. Timestamp anchoring is an RFC 3161 service, so an offline stream has none: you have proven the ordering and integrity of these records and who signed them, but not that they existed before some external moment in time.

What just happened

Each operation became a record whose hash covers the previous record's hash, so the stream is a chain that cannot be reordered or have entries removed from the middle without detection; the statement text itself never entered the record, only a salted commitment to it plus the structural metadata the guard extracted. At close, the recorder built a Merkle tree over the new records and signed the root into a checkpoint with its identity key, which is what the verifier checks when it reports records as "attested".

Next steps

On this page