# Export & break-glass recovery

Zero-knowledge means seekrit cannot read your secrets. It should also mean you
don't need us to. **`seekrit archive`** exports your whole organization as one
signed file, and opens that file offline — with your passphrase, a service
token, or a quorum of recovery custodians. No network, no account, no seekrit.

Use it for a durable backup, for a compliance or due-diligence snapshot, or to
prove to yourself (or a security reviewer) that leaving is a file copy rather
than a migration project.

## What's in an archive

One JSON file, `seekrit-archive/v1`, holding every row we store for the
organization:

- **Structure** — applications, groups, environments (including branches and
  their parents), and which groups each environment composes.
- **Secrets** — every current ciphertext, and every historical version, exactly
  as stored.
- **Key grants** — each environment's data key wrapped to each principal
  (`wd1.` blobs), for **every** principal, plus managed-key (KMS) grants and the
  wrapped recovery shares.
- **People and credentials** — members and roles, service-token and machine-client
  metadata, outstanding invites.
- **Operations** — rotation policies, sync connections and bindings, lease
  targets, and the append-only audit log.
- **Agent access policy** — every agent identity and the full version history of
  its published, signed policy bundles, so what an agent was allowed to reach
  stays verifiable offline, for past versions as well as the current one.
- **Your own key** — the requesting user's passphrase-encrypted private key
  (`pk1.`), so the archive plus your passphrase is self-sufficient.

Ciphertext stays ciphertext: exporting decrypts nothing, and the archive is
exactly as unreadable to us as the database it came from.

> **Note:** An archive carries **your** wrapped private key and nobody else's. Every member's key stays where it is; each person exports their own. That's why the manifest records who asked for it.

Three *columns* are deliberately **left out**, because including them would either
hand you an offline cracking target or an undecryptable blob: service-token and
session **hashes** (authentication verifiers, useless to you), the **admin
credentials** on lease targets, and the **destination API credentials** on sync
connections. The last two are encrypted to a server-side key that no key of
yours can open — the row is in the archive, the credential column isn't.

A few whole tables are out too, and for one of them the reason is worth knowing:
**honey tokens are never in an archive.** A decoy works because nobody knows where
it's planted, and an archive is a file that travels — so the one place a decoy's
placement must not appear is a portable copy of your organization. Every *trip* is
still there, in the audit log. Also omitted: expired lease records, sync run
history, in-flight recovery ceremonies, the log-sink credential, and billing rows —
each either duplicated by the audit log or not your data. The full list, with
reasoning, is in the design notes shipped with the code.

## Create one

Admins only, from the CLI:

```bash
seekrit archive create --out acme-2026-08-19.json
```

It prints a row count per section, verifies the file it just wrote, and names
the signing key. Options: `--no-versions` and `--no-audit` to shrink it,
`--audit-limit <n>` to cap audit history (the default keeps the newest 25,000
rows). Or straight from the API:

```bash
curl -X POST https://api.seekrit.dev/v1/orgs/$ORG/export \
  -H "authorization: Bearer $SEEKRIT_TOKEN" \
  -H "content-type: application/json" -d '{}' \
  -o acme-2026-08-19.json
```

Every export writes an `org.exported` audit row — who, when, how many rows, and
the archive's digest — so an export is as visible as any other privileged
action. Export is **never** gated on your plan; the ability to leave isn't a
paid feature.

## Verify it

The manifest carries a SHA-256 digest per section, and the whole manifest is
signed with Ed25519. So an archive is tamper-evident years later, offline:

```bash
seekrit archive info    acme-2026-08-19.json   # summary + verification
seekrit archive verify  acme-2026-08-19.json   # exits non-zero if anything fails
```

`verify` reports *which* section broke rather than just "bad file". To check
provenance as well as integrity, pin the signer — the public key is published
unauthenticated, so you can fetch it once and keep it:

```bash
curl -s https://api.seekrit.dev/.well-known/seekrit-export-signing-key
# → { "algorithm": "ed25519", "publicKey": "…", "keyId": "1ab3bd8b98170773" }

seekrit archive verify acme-2026-08-19.json --key-id 1ab3bd8b98170773
```

## Open it offline

Two ways in, both with no network.

**With the CLI**, which needs no credentials and never builds a client for these
subcommands:

```bash
seekrit archive decrypt acme-2026-08-19.json --out ./plaintext
# ./plaintext/apps/web/production.env
# ./plaintext/groups/shared/staging.env
```

You'll be prompted for your passphrase (or set `SEEKRIT_PASSPHRASE`). Other key
sources: `--token skt_…` for a service token, `--key-file` for a raw private-key
JWK. Add `--format json|shell`, `--env web/production` to narrow it, or
`--stdout` to print instead of writing files. Environments your key holds no
grant on are **skipped**, not failed — an archive spans the whole organization,
and no single principal is expected to open all of it.

**With no install at all**, using the standalone decryptor: a single HTML file
you keep alongside your archives.

```bash
seekrit archive decryptor --out seekrit-decrypt.html
```

Open it in any browser — including on an air-gapped machine, straight from
`file://` — drop the archive in, enter your passphrase, and read your secrets.
It verifies the digests and signature first, and shows values masked until you
reveal them.

> **Tip:** The page declares `Content-Security-Policy: default-src 'none'`. Your browser will refuse every outbound request it could make, so the page that sees your passphrase and your plaintext **cannot** send them anywhere. It's one line at the top of the file, and you can read it before you trust it.

## Break glass: opening an archive nobody holds the key to

The hard case isn't losing the file, it's losing the person. If the only
key-holder for an environment is gone, their passphrase is gone with them — and
we never had it.

That's what [customer-controlled recovery](/docs/guides/recovery) is for, and an
archive carries everything the ceremony needs: each environment's data key
wrapped to the org recovery key, plus every custodian's wrapped Shamir share. So
the ceremony also runs **offline**, from the archive alone.

Each custodian unwraps their own share from their own archive:

```bash
seekrit archive share acme-2026-08-19.json --out share-ana.json
# (or --token skt_… for a service-token custodian)
```

Then any *threshold* of shares reconstructs the recovery key and opens
**everything**:

```bash
seekrit archive decrypt acme-2026-08-19.json \
  --share share-ana.json --share share-bo.json \
  --out ./recovered
```

Below the threshold it fails outright rather than producing plausible garbage.
The standalone HTML decryptor accepts pasted shares too, under
**custodian shares (recovery quorum)**.

> **Warning:** An unwrapped share is sensitive: a threshold of them *is* the recovery key, and the recovery key opens every environment. Move them as you would the secrets themselves, and delete them when the ceremony is done.

## Notes and limits

- **It's an exit and audit artifact, not a restore point.** There is no import:
  re-establishing access to a live organization means re-granting keys, which is
  the recovery ceremony above, not a file upload.
- **Values are as stored.** A `${REFERENCE}` in a secret is expanded when an app
  reads it (see [references](/docs/guides/references)); an archive shows the
  literal stored value.
- **Truncation is always declared.** If an audit cap trims history, the section
  says so and `verify` repeats it. A quiet trim would make an incomplete archive
  look complete.
- **Two exports of unchanged data are byte-identical**, so you can diff
  yesterday's archive against today's.
- **Keep a decryptor with your archives.** `seekrit archive decryptor` is the
  half that has no dependencies at all; an archive plus that file plus your
  passphrase is the whole recovery path.
