Docs / Command reference

Command reference

Every command, with the flags it actually accepts. safegrd <command> --help prints the same thing on the host, and is the authority if this page and the binary ever disagree.

Global flags

FlagMeaning
--configConfig file. Default ~/.safegrd/config.yaml.
--server-urlControl plane URL. Default https://safegrd.dev, or $SAFEGRD_SERVER_URL.
-v, --versionPrint the version and exit.

Setup

init

safegrd init [flags]

Generates an Age keypair if this host has none and writes local configuration. Contacts no SafeGrd server; with --storage s3 it asks the bucket whether Object Lock is on.

FlagMeaning
--node-nameName this host is shown under. Default: the hostname.
--database-urlPostgreSQL connection URL to protect.
--storagelocal, s3 or hosted. Default local.
--local-pathDirectory for the local sink.
--s3-bucketBucket for WORM storage.
--s3-prefixKey prefix in the bucket. Default safegrd/snapshots.
--s3-regionBucket region. Default us-east-1.
--s3-endpointCustom endpoint, for MinIO, R2 or Wasabi.
--retention-daysWORM retention in days. Default 14.
--worm-modeObject Lock mode for --storage s3: COMPLIANCE (default), GOVERNANCE, or NONE for a bucket with no Object Lock, such as DigitalOcean Spaces.
--forceOverwrite an existing config. This discards its settings and generates a new keypair, after which snapshots taken under the old key can only be read with the old key. Back it up first.

enroll

safegrd enroll [flags]

Registers this host with the control plane, running local setup first if needed. A personal access token enrols new hosts only. A host that is already enrolled keeps its node token; if that token is lost, rotate it under Nodes in the console and run safegrd enroll --token <node token> --node-id <id> on the host.

FlagMeaning
--tokenPre-issued node token, or a personal access token (which registers a new node).
--node-idThe node a node token belongs to. The console shows it beside the token. Not needed with a personal access token.
--api-keyOrganization or admin API key, for provisioning many hosts.
--node-nameName this host is shown under. Default: the hostname.
--orgOrganization to enrol into. Only needed when the credential can see more than one.
--projectProject id or slug. Defaults to the organization's default project.
--key-custodysafegrd (default) escrows the generated private key; local keeps it on this host and sends only the public half. Ignored when you supplied your own key.
--storageWhere this host's backups go when its project has no bucket: hosted uses SafeGrd's hosted storage where your plan includes it; local keeps them in a directory on this host.
--allow-unconfiguredEnroll even if neither the host config nor its project specifies a storage destination. By default, enrollment requires a configured storage target so the host can immediately begin backups.

claim

safegrd claim

Adds to an enrolled host's config the surfaces named for it in the console (Add surface on the host's row under Nodes). Nothing changes on the host until it runs, and it only adds: a surface the config already has is left as it is, the previous config is kept as config.yaml.bak, and running it again adds nothing. The daemon reads its config when it starts, so restart it afterwards with safegrd daemon restart. A new host enrolls with safegrd enroll --claim <code> instead.

login

safegrd login [flags]

Authenticates your user account with SafeGrd Cloud.

FlagMeaning
--tokenPersonal access token (sg_pat_...) for CI and headless use.
--no-browserPrint the URL rather than opening a browser.

whoami

safegrd whoami

Prints the authenticated user and the active server session.

Protect

backup

safegrd backup [flags]

Streams a surface, compresses it with zstandard, encrypts it to your Age public key and writes ciphertext to WORM storage. Plaintext never touches disk, except a SQLite surface's private temporary copy on the same host (why).

FlagMeaning
--database-urlDatabase connection string: postgres://… selects the PostgreSQL surface, mysql://… (or mariadb://…) the MySQL one, mongodb://… the MongoDB one, sqlite:///path/to/file.db the SQLite one.
--surfaceThe id of one surface under surfaces: in the config. Backs it up now, whatever its schedule, the way the daemon would: its own storage, retention and credential. Take one before a migration. Used alone, without the flags that describe a surface.
--filesDirectory tree to back up. Selects the files surface.
--emailRun an IMAP mailbox backup. Selects the email surface.
--excludeGlob patterns to exclude from a file backup, e.g. '*.tmp,node_modules/*'.
--formatHow --files or a PostgreSQL or SQLite database is stored: repo, incremental, each run uploading only what changed (the default), or tar, one archive per backup. MySQL and MongoDB are one archive. See incremental file backups and databases.
--change-logFor a PostgreSQL backup in repo format: skip reading tables nothing wrote since the last run, from a trigger it puts on each table. See the change log.
--roles-without-passwordsPostgreSQL: leave role password hashes out of the backup. By default the roles the schema names travel with them, sealed like everything else. See roles, owners and grants.
--new-epochStart a new monthly epoch now, uploading everything once. For --format repo, or with --surface.
--rescanRead every file, not only those whose size or times changed. For --format repo, or with --surface.
--one-filesystemStay on the root's filesystem. The default when the root is /.
--email-hostIMAP hostname.
--email-portIMAP TLS port. Default 993.
--email-userMailbox username or address.
--email-passwordMailbox password. Prefer SAFEGRD_EMAIL_PASSWORD: a flag is visible in the process table.
--email-foldersSpecific folders. Default is all except spam and trash.
--email-ca-filePEM bundle of extra CAs to trust for the IMAP server, added to the system roots, never instead of them. Also SAFEGRD_EMAIL_CA_FILE.
--retention-daysWORM immutability period for this snapshot.
--s3-bucketWrite to this bucket instead of the project's or the config's.
--s3-prefixKey prefix in the bucket.
--s3-endpointS3 endpoint, for MinIO, R2 or another S3-compatible store.
--s3-regionS3 region.
--s3-access-keyS3 access key id.
--s3-secret-keyS3 secret access key, as env:VAR or file:/path.
--tagCustom snapshot tag prefix.
--jsonEmit the result as JSON.

guard

safegrd guard [--surface ID] [-- command [args...]]

Backs up one surface, waits until the snapshot is uploaded and locked, then runs the command. If the backup fails or the snapshot is not locked, the command does not run and guard exits 3. See Agent guard.

FlagMeaning
--surfaceThe surface to back up, by its id in the config.
--allow-unlockedRun the command after a backup that is not locked: local storage, or worm_mode: NONE.
--listPrint the destructive command rules.
--matchesCheck a command against the rules and take no backup: exit 0 if it matches, 1 if not.
--hookAnswer a pre-command hook on stdin: claude-code, cursor or codex.

Recover and prove

restore

safegrd restore --snapshot <id> | --path <file> | --table <schema.table> | --from <export> [flags]

Downloads ciphertext, decrypts it on this machine and restores it to a database or a directory. With --from it reads a copy made by safegrd export --to-dir instead of the storage in the config (Runbook 4).

FlagMeaning
--snapshotSnapshot id to restore. Leave it out with one --path or one --table to restore its newest kept version, or with --from naming a .safegrd file.
--fromAn export to restore from: the directory export --to-dir wrote, with --snapshot, or one .safegrd file in it.
--targetTarget database URL, postgres://… or mysql://… to match the snapshot. It must be an empty database.
--target-dirTarget directory, for file and email snapshots.
--pathFor an incremental files snapshot: restore only this path, relative to /. Repeatable; *, ? and ** match.
--versionWith one --path or --table: restore that version, as safegrd find numbers them, in place of --snapshot.
--surfaceWith --version: the surface whose repository holds the file, when more than one does.
--schemaPostgreSQL only: restore this schema's objects and rows into a database that already has other schemas, such as a Supabase project. Repeatable. The chosen schema's objects have to be absent from the target.
--data-only-schemaPostgreSQL only: load this schema's rows into the tables the target already has, and create nothing. Repeatable; combine with --schema.
--no-ownerPostgreSQL only: restore without owners, grants and default privileges, so every object belongs to the restoring role. The roles the schema names are still created, because a policy cannot be restored without them. See roles, owners and grants.
--to-sqlA new directory to write a PostgreSQL snapshot into as files psql loads: the schema as SQL, each table's rows as binary COPY, and load.sql. Run psql "$URL" -f load.sql from that directory. The files are unencrypted; the directory is created 0700.
--key-pathPath to the Age private identity file.
--private-keyThe Age private identity inline (AGE-SECRET-KEY-1...).

verify

safegrd verify --snapshot <id> [flags]

Runs a Fire Drill: pulls the snapshot, decrypts it and asserts what came back. The default is an in-memory dry restore needing no database at all.

FlagMeaning
--snapshotSnapshot id to verify. Required.
--dry-runIn-memory dry restore, with no target database.
--sandbox-targetAn empty database to restore into for a full drill. verify never empties it afterwards. When the drill fails, it prints where the sandbox is.
--keepWhen a sandbox drill fails, record that the sandbox is kept for a person to look at.
--show-urlWhen a sandbox drill fails, print the sandbox URL with its password.
--key-pathPath to the Age private identity file.
--private-keyThe Age private identity inline.
--s3-bucketRead the snapshot from this bucket instead of the configured storage.
--s3-prefixKey prefix in the bucket.
--s3-endpointS3 endpoint, for MinIO, R2 or another S3-compatible store.
--s3-regionS3 region.
--s3-access-keyS3 access key id.
--s3-secret-keyS3 secret access key, as env:VAR or file:/path.

find

safegrd find <pattern>... [flags]

Lists every kept version of the matching files in incremental backups: when each was first and last seen, its size and SHA-256, and how many snapshots hold it. Patterns are paths relative to /; a directory selects everything below it. Runs where the private key is.

FlagMeaning
--surfaceSearch this surface only. Without it, a host searches the surfaces it has the key for and says how many others it did not search; naming another host's surface fetches its key when SafeGrd holds it.
--deletedList only files the newest snapshot no longer holds.
--jsonPrint the histories as JSON.
--key-pathPath to the Age private identity file.
--private-keyThe Age private identity inline.

check

safegrd check --snapshot <id> | --epoch <id> | --all [--read-data]

Checks incremental backups without restoring them: every pack a snapshot names is in storage and agrees with its index, every directory listing decodes, the content digest recomputed from them matches the one recorded, and the catalog agrees. Exits non-zero and names what is wrong.

FlagMeaning
--read-dataAlso open every chunk and check its SHA-256. Downloads the snapshot's data.
--key-pathPath to the Age private identity file.
--private-keyThe Age private identity inline.

history

safegrd history [flags]

Checks a node's attestation chain and the Ed25519 signature of each record under the key it names. Aliased as verify history.

FlagMeaning
--nodeNode id whose history to verify.
--fileLocal JSON file of verifications, for an offline audit.
--saveAlso write the records fetched from SafeGrd to this file, for a later --file check.
--keyOne hex-encoded Ed25519 public key, checked against every record.
--key-fileFile containing that one public key.
--keys-fileThe JSON of /api/v1/attestations/public-key, saved while online: the active key and the retired ones, for a chain that spans a key rotation.
--jsonEmit the verification result as JSON, with the keys that signed the chain.

Storage

list

safegrd list

Lists every snapshot in the bucket, with the node it was filed under, what it holds and its retention state. restore and verify find a snapshot under whichever node it is filed under, so a machine rebuilding a lost host does not need the old node id (Recovery runbooks). Incremental file backups are listed in a second table: the month (epoch) each snapshot belongs to, whether its run opened the month or followed it, the size of the tree it holds and the bytes its run uploaded.

FlagMeaning
--jsonPrint a JSON array on stdout, one object per snapshot with snapshot_id, created_at, status, locked and locked_until. Every other line goes to stderr.

undelete

safegrd undelete [flags]

Removes the delete markers hiding snapshots in a versioned bucket. It only ever deletes delete markers, addressed by version id, and cannot remove a version holding data. With --all it rolls the bucket back to before the deletion, every snapshot and sidecar, and re-uploads nothing (how a deletion is undone).

FlagMeaning
--snapshotMake one snapshot visible again.
--allClear delete markers from every hidden snapshot.

export

safegrd export --to-dir <dir> | --to-bucket <bucket> [flags]

Copies every snapshot and its metadata, still encrypted, to a directory or to a bucket you own. --snapshot and --node narrow it. No key is needed. An incremental files backup is copied a whole month (epoch) at a time, since a snapshot needs every object of its month, and --snapshot copies the month that holds it. Each copy is checked against the digest recorded at backup time, a snapshot keeps its lock in the destination bucket, and one already there is skipped, so an interrupted export can be run again. Use it to leave hosted storage or to keep an offline copy. Credentials for --to-bucket come from the standard AWS environment. safegrd restore --from restores from a directory export.

FlagMeaning
--to-dirExport into this local directory.
--to-bucketExport into this S3 bucket.
--to-endpointS3 endpoint of the bucket (MinIO, B2, R2, ...).
--to-regionRegion of the bucket. Default us-east-1.
--to-prefixKey prefix in the bucket. Default safegrd/snapshots.
--to-worm-modeCOMPLIANCE (default), GOVERNANCE or NONE.
--snapshotExport only this snapshot. Repeat it or give a comma-separated list. An id that is not in storage is an error.
--nodeExport only this node's snapshots. Repeatable.

estimate

safegrd estimate --database-url postgres://... [flags]

Measures a PostgreSQL database and prints the egress a month for weekly, daily and hourly backups at its provider, after the provider plan's included egress. Every backup reads every row, uncompressed, so one backup reads about the size of the tables without their indexes. The provider is read from the host name (Supabase, Neon, Amazon RDS); the prices were read from their pricing pages on 2026-10-05. A warning on stderr names each schedule whose egress costs more a month than the SafeGrd plan you compare it with, at the price the server publishes. Your application's own traffic uses the same allowance, so pass what is left with --included-gb. For a database SafeGrd backs up itself, the console shows the same estimate for the surface's schedule when its connection string is saved.

FlagMeaning
--database-urlThe database to measure. Default: the first PostgreSQL surface in the config.
--surfaceMeasure this surface's database.
--providersupabase, neon, rds or other. Default: read from the host name.
--provider-planWhose included egress applies: Supabase free, pro (default) or team; Neon free, launch (default) or scale.
--egress-price-per-gbThe price in US dollars per GB, for --provider other or to replace the one built in.
--included-gbEgress a month that is free and not used by your application.
--schedulePrice this schedule as well, as the config writes it.
--planThe SafeGrd plan to compare with: starter, growth (default) or scale.
--jsonPrint the estimate as JSON.

keep

safegrd keep --snapshot <id> --until <date> --yes

Extends one snapshot's lock, its backup file, metadata and recovery document together, to the end of --until (UTC). A lock can be extended and never shortened, by anyone, so the date can be at most 13 months from today and the command needs --yes. In your own bucket the host extends it, which needs s3:PutObjectRetention and s3:GetObjectRetention, and tells the server. On hosted storage the server extends it. An incremental snapshot is kept as long as its month and cannot be kept on its own (keep a snapshot longer).

FlagMeaning
--snapshotThe snapshot to keep longer.
--untilThe new lock end: a date, kept to the end of that day in UTC, or an RFC 3339 time.
--yesExtend it. Without this the command says what it would lock and stops.

prune

safegrd prune [--dry-run] [--grace 24h] [--min-keep 3]

Deletes snapshots from your S3 bucket whose Object Lock retention expired more than a day ago, evaluated against the bucket's timestamp and retention status. SafeGrd keeps the newest --min-keep snapshots of a surface (three by default) whatever their locks say, and preserves the last known-good snapshot whenever Threat Shield reports an open anomaly. Snapshot versions are removed before delete markers and metadata. Requires s3:DeleteObjectVersion and s3:GetObjectRetention permissions. Set storage.expire_after_lock: true to enable automated daily pruning. An incremental files backup is pruned by month: a month's expired objects are deleted once every snapshot that could use them is past its retention, and never from the month holding the surface's newest snapshot.

FlagMeaning
--min-keepHow many of each surface's newest snapshots are never deleted, whatever their locks say. At least 1; default 3.
--dry-runList what would be deleted, and delete nothing.
--graceHow long after a lock ends a snapshot is kept anyway. Default 24h.

Unattended

daemon run

safegrd daemon run [flags]

Runs the resident daemon: evaluates due surfaces, takes per-surface single-flight locks and backs them up.

FlagMeaning
--onceOne reconciliation pass, then exit. For cron and Kubernetes Jobs.
--intervalPoll interval. Default 5m.
--state-dirState and locks directory.

daemon status

safegrd daemon status [flags]

Live status of every configured surface and the daemon itself.

FlagMeaning
--jsonEmit status as JSON.
--state-dirState directory to read.

daemon install

safegrd daemon install [flags]

Generates or installs a systemd unit or launchd job. daemon restart and daemon uninstall manage it from there.

FlagMeaning
--userInstall as a user agent rather than a system service.
--printPrint the service definition to stdout and install nothing.

Diagnose

doctor

safegrd doctor [flags]

Deep preflight: config permissions (0600 on POSIX), keypair integrity, WORM sink connectivity and real Object Lock support, control plane reachability, host clock skew, and that every surface opens with the credential its backup will use: a query on each PostgreSQL, MySQL, MongoDB and SQLite database, a login to each mailbox, and each files root. For each database it finds a pg_dump or mysqldump the server can be dumped with. For each PostgreSQL surface it warns when the role can write and prints the read-only role to use, and names the tables row-level security hides rows of (read-only role). On an enrolled host the results are reported to the console, which shows the host as checked.

FlagMeaning
--jsonEmit the diagnostic report as JSON.
--agent-proofCheck instead whether an AI agent on this host could destroy the backups, and print the fix for each failure. See Agent guard.

status

safegrd status

Quick check of connectivity, storage immutability and encryption keys.

config validate

safegrd config validate

Validates configuration syntax, permissions and surface definitions without running anything.

Organization

org

safegrd org list | safegrd org members

org list prints your organization profile, plan and quota status; org members lists the team. Aliased as orgs.

projects

safegrd projects list

Lists the projects inside an organization.

version

safegrd version

Prints the CLI version, commit and build date. Include it in any bug report.

Environment variables

VariableMeaning
SAFEGRD_SERVER_URLControl plane URL, the same as --server-url.
SAFEGRD_PRIVATE_KEYThe Age private identity, for restores and drills on a host without the key file.
SAFEGRD_EMAIL_PASSWORDMailbox password. Prefer this to the flag.
SAFEGRD_EMAIL_CA_FILEPEM bundle of extra CAs to trust for IMAP.

Token lifetime

Personal access tokens expire 90 days after creation, and the console displays the expiration date. For automated environments and CI pipelines, plan regular token rotation to prevent build interruptions, and scope each token to its specific project to limit exposure. Tokens issued before this expiration policy remain valid indefinitely.