CLI commands
seekrit <command> [options]. At runtime a service token selects the org, app,
and environment — so seekrit run/export need no config file. Management
commands select their target with --org/--app/--group/--env flags
(plus --branch for an ephemeral branch config),
falling back to the optional seekrit.json written by seekrit init.
Environment variables
| Variable | Purpose |
|---|---|
SEEKRIT_TOKEN | Service token (skt_…). Carries its bound org + app + environment. Also accepts a CLI session token (skc_…) if you'd rather pass one explicitly than save it. |
SEEKRIT_CLIENT_ID / SEEKRIT_CLIENT_SECRET | Machine (M2M) credentials. When set (and no SEEKRIT_TOKEN is), an admin token is minted from them automatically and cached — the seamless path for autonomous agents. |
SEEKRIT_API_URL | API base URL. Overrides saved config; defaults to https://api.seekrit.dev. |
SEEKRIT_PASSPHRASE | Passphrase to unlock your private key non-interactively. |
SEEKRIT_CACHE | Set to 1 to enable the last-known-good cache for run / export without passing --cache. |
SEEKRIT_CACHE_DIR | Where cached responses live. Defaults to $XDG_CACHE_HOME/seekrit, else ~/.cache/seekrit. |
SEEKRIT_CACHE_MAX_AGE | How stale a cached response may be and still be used. Defaults to 24h. |
Precedence: environment variables override values saved by seekrit login in
~/.config/seekrit/config.json. seekrit run additionally reads these from its
.env file(s) (below process.env, above saved config) — see
Running & exporting.
Output conventions
Everything the CLI can do from the dashboard, it can do from the terminal, and every listing reads the same way:
- Listings print an aligned table with a header when stdout is a terminal,
and plain tab-separated rows with no header when it is piped — so
seekrit app list | cut -f1keeps working. --jsonon any read command prints the API's own response instead. Use it when a table would flatten something you need (ids, nested config, timestamps).- Data goes to stdout; everything else goes to stderr — confirmations
(
created app …), "nothing to list" notes, and pagination hints. A command's stdout is always safe to pipe. - Destructive commands ask first. Anything that deletes or revokes prompts
for confirmation at a terminal, and refuses outright when there is no terminal
unless you pass
--yes(or, forsync enable,--acknowledge-decryption). listis aliased asls, andrmasdelete, wherever both read naturally.
Auth & identity
seekrit login
With no flags, signs you in through your browser: it prints a URL and a
pairing code, opens the URL when you press [Enter], and waits while you
authorize the device in the dashboard (re-entering your authenticator code if you
have one). The session it saves authenticates as you — every org you belong to,
at your role — and lasts 90 days. Nothing to copy and paste, and no org, app, or
environment to choose.
Passing a credential stores that instead and skips the browser entirely — the path machines and CI use.
| Flag | Description |
|---|---|
--token <token> | Service token (skt_…). Stored as-is; replaces any browser session. |
--client-id <id> / --client-secret <secret> | Machine (M2M) credentials (given together). An admin token is minted from them automatically on next use and cached. |
--api-url <url> | API base URL. |
--no-browser | Print the sign-in URL instead of opening it (SSH sessions, headless machines). |
A browser session carries no key material, so reading a secret's value still
unlocks your private key with your passphrase (SEEKRIT_PASSPHRASE, else
prompted) — exactly as the dashboard does. Service tokens carry their own key and
don't prompt, which is why they remain the right credential for unattended jobs.
seekrit logout
Forget the saved credentials. A browser-authorized session is also revoked
server-side, so the token can't be used again; a service token is only removed
locally (other machines may hold it — revoke it with seekrit token revoke).
Machine (M2M) credentials are left in place.
seekrit whoami
Show the authenticated identity. For a service token, prints its bound
org/app/env scope; for a browser session, names the session so you can revoke it.
seekrit keys setup
Generate your P-256 keypair and upload your public key plus a passphrase-encrypted private key.
Run once per account. Honors SEEKRIT_PASSPHRASE, otherwise prompts.
Resources
seekrit init
--org <slug> --app <slug> — write seekrit.json naming default org + app for
management commands. Environment-independent and safe to commit — it never
pins an environment (the token does that at runtime).
Organizations (seekrit org)
| Command | Description |
|---|---|
seekrit org list | Every organization you can reach, with your role in each. |
seekrit org show [slug] | One org: slug, id, your role, and how many applications, groups, members, and service tokens it holds. A count your role can't read prints as —. |
seekrit org tree [--org <slug>] | The whole org as a tree — every application and group with their environments. The fastest "what is in here?". |
seekrit org create --name <name> --slug <slug> | Create an organization (you become owner). |
seekrit org rename [--org <slug>] --name <name> | Change the display name. Slugs are permanent identifiers and never change. |
seekrit org member list [--org <slug>] | Members, their roles, and whether each has finished key setup. Someone showing pending cannot be granted an environment key yet. |
seekrit org invite list [--org <slug>] | Outstanding invitations. |
seekrit org invite add <email> [--role admin|member] | Invite someone. Membership is created when they first sign in, so they will not appear in member list until then. |
seekrit org invite rm <inviteId> | Rescind an invitation. |
seekrit org mfa [--set required|optional] | Show — or change — the org-wide second-factor requirement. Reports "no identity provider configured" on a deployment without one. |
Applications (seekrit app)
| Command | Description |
|---|---|
seekrit app list [--org <slug>] | Applications in an org. |
seekrit app show [slug] | One application, its environments, and whether you hold a key for each — no key is why secrets get would fail there. Lists live branches too. |
seekrit app create [--org <slug>] --name <name> --slug <slug> | Create an application. |
seekrit app rename [slug] --name <name> | Change the display name. |
seekrit app rm <slug> [--yes] | Delete an application, its environments, and every secret in them. Names the number of environments before asking. Cannot be undone. |
Environments (seekrit env)
| Command | Description |
|---|---|
seekrit env list [--app <slug>] | An application's environments and your access to each. |
seekrit env show --env <slug> [--app <slug>] | One environment: its composed groups in precedence order, who holds a key for it (admins only), its secret count, and its branches. |
seekrit env create [--org <slug>] --app <slug> --name <name> --slug <slug> | Create an application environment. Generates the environment's data key locally and wraps it to your public key. |
seekrit env rm --env <slug> [--app <slug>|--group <slug>] [--yes] | Delete an environment and every secret in it. Names the secret count before asking. Works for group environments too, via --group. |
seekrit branch create
<slug> [--org <slug>] [--app <slug>] --from <env> [--name <name>] [--ttl <duration>] [--no-share] — fork an application environment into an ephemeral branch (a
per-PR / preview config). The branch inherits its parent's secrets by layering at
read time — nothing is copied or re-encrypted — and stores only what you override
on it. Generates the branch's own data key locally and, unless --no-share, wraps
it to everyone who already holds a grant on the parent.
--ttl accepts 30m, 12h, 7d, 2w, … or never (default 7d, max 30 days).
Expired branches are deleted automatically, along with their overrides, key grants,
and any service token bound to them.
seekrit branch list
[--org <slug>] [--app <slug>] [--env <slug>] — list branches in an application,
or just those of one environment. Prints slug, id, and expiry.
seekrit branch delete
<slug> [--org <slug>] [--app <slug>] — tear down a branch and every value it
overrode. The environment it overlays is untouched. Aliased as branch rm.
Shared groups (seekrit group)
A group is a reusable secret bag shared across applications, holding one environment per slug (its variants).
| Command | Description |
|---|---|
seekrit group list [--org <slug>] | Groups in an org. |
seekrit group show <slug> | One group and the environments it holds, with your access to each. |
seekrit group create [--org <slug>] --name <name> --slug <slug> | Create a group. |
seekrit group rename <slug> --name <name> | Change the display name. |
seekrit group rm <slug> [--yes] | Delete a group, its environments, and their secrets. Every application environment composing it stops receiving these values on its next resolve. |
seekrit group env list --group <slug> | The group's environments. |
seekrit group env create --group <slug> --name <name> --slug <slug> | Create a group environment (a per-slug value set / variant). Generates its data key locally. |
Composition (env groups)
Compose shared groups into an application environment. At resolve time each group
is matched to the environment whose slug matches the app environment's (or a
--with override).
| Command | Description |
|---|---|
seekrit env groups add --app <slug> --env <slug> --group <slug> [--position <n>] | Compose a group (higher position wins). |
seekrit env groups list --app <slug> --env <slug> | List composed groups, lowest precedence first. |
seekrit env groups rm --app <slug> --env <slug> --group <slug> | Remove a group. |
Secrets
Every secrets command targets one environment via flags: an application
environment (--app --env, or the config's app + --env) or a group environment
(--group --env). --org is inferred from seekrit.json or a lone org.
| Command | Description |
|---|---|
seekrit secrets list --env <slug> [--app <slug>|--group <slug>] | List secret names, versions, update times (no values). --json prints the same metadata — never a value, and never the stored ciphertext. |
seekrit secrets get <name> --env <slug> [--raw] [--version <n>] [--pretty] … | Decrypt and print one value. ${OTHER_SECRET} references are expanded against that environment's own secrets; --raw prints the stored text. --version prints an earlier version instead of the current one, always as stored. --pretty re-indents the value if it is JSON and leaves it untouched if it is not — for reading, not for piping. |
seekrit secrets set <name> [value] --env <slug> [--file <path>] … | Encrypt and store a value. Reads stdin if value is omitted or -; --file reads it from a file. Both drop one trailing newline and store the rest byte-for-byte — the way to store a JSON credential or a PEM key without shell quoting. |
seekrit secrets import [file] --env <slug> [--dry-run] … | Bulk-import a .env file (default .env; - reads stdin). Each KEY=VALUE is encrypted and stored; existing names are overwritten. Aborts before writing if any name is invalid; --dry-run lists what would change (marking each new/update) without writing. |
seekrit secrets history <name> [--limit <n>] --env <slug> … | List the secret's versions — when each was saved, who saved it, and which ones were restores. Never prints values (default 20, max 200). |
seekrit secrets restore <name> <version> --env <slug> … | Roll the secret back to an earlier version. |
seekrit secrets rm <name> --env <slug> … | Delete a secret, and with it every earlier version. |
JSON and multi-line values
A value is an opaque string to seekrit — a service-account key, a PEM block, or
a certificate chain is stored and delivered byte-for-byte. The only thing that
needs care is getting it in without a shell or a .env file mangling it
first. Read it from a file and neither is involved:
seekrit secrets set GOOGLE_SERVICE_ACCOUNT --file ./service-account.json \
--app storefront --env production
cat ./key.pem | seekrit secrets set TLS_KEY - --app storefront --env production
Both drop a single trailing newline and store everything else exactly as written. To read one back formatted:
seekrit secrets get GOOGLE_SERVICE_ACCOUNT --pretty --app storefront --env production
--pretty only re-indents values that parse as JSON; anything else prints
unchanged. Without it, output stays byte-exact, which is what you want when
piping to a file or another tool.
.env syntax
seekrit secrets import, the --env-file overlays, and the dashboard's paste
.env tab all use one parser — as does the seekrit-run
launcher, byte-for-byte:
| Syntax | Meaning |
|---|---|
KEY=value | Unquoted: single-line, and a trailing # comment is dropped. |
KEY='value' | Single quotes: literal. No escapes are interpreted, so a \n inside stays two characters. |
KEY="value" | Double quotes: \n, \r, \t, \", and \\ are interpreted. |
export KEY=value | The export prefix is ignored. |
# comment | Whole-line comments and blank lines are skipped. |
A quoted value may span lines — it runs to its closing quote, wherever that lands. That is what makes a pretty-printed credential storable:
GOOGLE_SERVICE_ACCOUNT='{
"type": "service_account",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQ…\n-----END PRIVATE KEY-----\n"
}'
Single quotes are the right choice for JSON: the value is full of double quotes
and \n escapes that must survive as written, and single quotes pass them
through untouched.
An unquoted value stops at the end of its line. Paste a multi-line JSON
credential without quotes and the lines below it are read as further
assignments — you get KEY={ plus a handful of garbage names, not an error.
Quote it, or skip the file entirely and use --file.
seekrit export --format dotenv writes this same syntax and quotes as needed,
so exporting and re-importing a value round-trips exactly, escapes included.
Point-in-time restore
Every write appends to the secret's history, so a bad value is always one command away from being undone:
seekrit secrets history DATABASE_URL --app storefront --env production
VERSION WHEN BY NOTE
v3 2026-07-24T18:22:05.994Z user:usr_KvxTL40S… current
v2 2026-07-24T18:19:41.769Z user:usr_KvxTL40S…
v1 2026-07-24T18:02:13.539Z user:usr_KvxTL40S…
Check what you're rolling back to, then roll back:
seekrit secrets get DATABASE_URL --version 2 --app storefront --env production
seekrit secrets restore DATABASE_URL 2 --app storefront --env production
Restoring is a roll-forward: v2's value is written back as v4, so nothing
in the history is lost and the rollback is itself undoable. Because the server
simply replays ciphertext it already stores, no key is involved — a machine
(M2M) credential that cannot decrypt the value can still roll it back. The
restore is audited as secret.restored.
Deleting a secret deletes its history with it. After seekrit secrets rm
there is nothing left to restore.
Running & exporting
Both resolve a layered environment for the current principal:
group secrets < app-env secrets < .env file < process env (highest wins)
With a service token, org/app/env come from the token. As a logged-in user, pass
--app --env (and --org if ambiguous).
Once the layers are merged, ${OTHER_SECRET} references
inside values are expanded — locally, in the same process that decrypted them.
| Flag | Applies to | Description |
|---|---|---|
--branch <slug> | run, export | Read an ephemeral branch of the target environment. Defaults to SEEKRIT_BRANCH (process env, then .env). |
--with <group>=<slug> | run, export | Resolve one group at a different slug for this invocation (repeatable). |
--env-file <path> | run, export | A .env file to overlay; repeatable; defaults to .env. |
--explain | run, export | Print each variable's source layer to stderr (never values). Marks variables whose ${OTHER_SECRET} references were expanded, and lists references that matched nothing. |
--no-interpolate | run, export | Leave ${OTHER_SECRET} references as literal text. |
--cache | run, export | Keep a last-known-good copy of the encrypted response and fall back to it when the API is unreachable. Off by default. |
--cache-dir <path> | run, export | Where to keep it. Defaults to $XDG_CACHE_HOME/seekrit, else ~/.cache/seekrit. |
--cache-max-age <duration> | run, export | How stale that copy may be and still be used — 15m, 24h, 7d. Defaults to 24h. |
seekrit run -- <command…>
Run a command with the resolved environment injected. Everything after -- is the command.
SEEKRIT_TOKEN=skt_… seekrit run -- ./start-server
# swap only the auth group to its staging slice for this boot:
seekrit run --with auth-providers=staging -- pnpm dev
run reads its .env file(s) before authenticating, so SEEKRIT_TOKEN and
SEEKRIT_API_URL can live in .env — resolved as
process.env > .env > saved config, matching the seekrit-run launcher. Drop
a token into a project's .env and seekrit run uses it with no global login.
Resolving seekrit secrets is best-effort: if no credentials are configured
or seekrit can't be reached (network, auth, or decryption failure), run logs a
warning to stderr and still launches the command with just the .env overlay
and process.env. This mirrors the seekrit-run launcher.
(seekrit export does not degrade — it errors if it can't resolve the secrets.)
run is a transparent wrapper: it forwards termination signals (SIGINT from
Ctrl-C, plus SIGTERM/SIGHUP/SIGQUIT) to the command and every process
below it, then stays alive until the command exits and exits with its status
(signal death is re-raised, so Ctrl-C yields 130). Relaying down the whole
process tree, rather than to the one process, is what makes Ctrl-C reliably tear
down commands that spawn their own children (npm/pnpm scripts running
nodemon, for example), since those don't always pass the signal on themselves.
The command keeps your terminal: run does not put it in a separate session, so
it stays visible in ps as usual, still gets the terminal's own Ctrl-C and its
hangup when you close the window, and can still prompt on /dev/tty for things
like a git credential or an SSH passphrase.
Nothing the command started outlives run. Once the command itself has
exited, anything still alive underneath it has both ignored the signal and lost
the process that started it, so nothing is left to stop it — not the terminal
either, which only ever hangs up its own foreground group. Rather than trust it,
run escalates: SIGTERM, then SIGKILL two seconds later, printing the pids
it had to force-kill. A process that ignores both is usually a signal handler in
the app that cleans up but never exits — in Node, process.on("SIGINT", …)
replaces the default action, so the process stops dying on Ctrl-C unless the
handler itself exits. Watch for that if you see the message; it names the pids.
A command that exits on its own is never chased this way, so if it deliberately
leaves a daemon running in the background, that keeps working.
The compiled seekrit-run launcher replaces itself with the command (exec), so
signals and the process tree behave exactly as if you had run the command
directly — with no wrapper left to escalate, cleaning up a command that ignores
signals is up to the command. See its exit-code notes below.
seekrit export
Print the resolved secrets (managed layers + .env, without process.env).
--format <dotenv|json|shell> (default dotenv).
seekrit-run launcher
seekrit-run is a separate, compiled single-file binary — a dependency-free
seekrit run for machines (containers, CI, agents). It is service-token
only and reproduces seekrit run's precedence and .env parsing exactly. See
the launcher guide for install and container usage.
seekrit-run [OPTIONS] [--] <command> [args...]
seekrit-run run [OPTIONS] [--] <command> [args...] # `run` is optional
| Flag | Default | Description |
|---|---|---|
-t, --token <skt_…> | SEEKRIT_TOKEN (env or .env) | Service token. |
--api-url <url> | SEEKRIT_API_URL or https://api.seekrit.dev | API base URL. |
-e, --env-file <path> | .env | A .env file to overlay (repeatable). |
--no-env-file | Do not load the default .env. | |
--branch <slug> | SEEKRIT_BRANCH (env or .env) | Read an ephemeral branch of the bound environment. |
--with <group=env> | Override one composed group's slice (repeatable). | |
--explain | Print each variable's source to stderr (names only). | |
--no-interpolate | Leave ${OTHER_SECRET} references as literal text. | |
--cache | off | Keep a last-known-good copy of the encrypted response and fall back to it when the API is unreachable. Also SEEKRIT_CACHE=1. |
--no-cache | Override SEEKRIT_CACHE=1 for this run. | |
--cache-dir <path> | SEEKRIT_CACHE_DIR, else $XDG_CACHE_HOME/seekrit | Where to keep it. |
--cache-max-age <d> | 24h | How stale that copy may be and still be used. |
Like seekrit run, it degrades gracefully: a missing/malformed token or an
unreachable API is logged to stderr, and the command runs with just .env +
the live environment. Exit codes: 2 usage error, 1 a local failure (an
unreadable explicit --env-file, or a reference cycle in one), 127 command
not found; otherwise the command's own exit code
(Unix exec). Honors HTTPS_PROXY / ALL_PROXY. Its default API URL is the
hosted https://api.seekrit.dev — the same default the Node seekrit run uses
when nothing else is configured.
Last-known-good cache
Off by default. With --cache, a successful resolve is written to disk and a
later run falls back to it when the seekrit API cannot be reached — so a
deploy, a CI job, or an agent boot still works during an outage.
seekrit run --cache -- ./start-server
seekrit-run: could not reach the seekrit API: … — using cached secrets fetched 6m ago
Only the encrypted response is stored — ciphertext plus your token's wrapped
data keys, the same bytes the API serves. Decrypting still requires the service
token's private key, so the file is no more sensitive than the token sitting
beside it; it is written 0600 inside a 0700 directory. The zero-knowledge
invariant is untouched: nothing is written in plaintext,
and nothing new is sent to the server.
How it behaves:
- Live first, always. Every invocation tries the API before touching the cache, so a recovered network is picked up immediately — the cache never serves a request that could have been answered fresh.
- A refused resolve does not fall back. If the API answers
401/403/404, the entry is deleted and the command fails as it would have anyway. Revoking a token still takes effect on the next run. Only "the API is unreachable" — a network failure, a5xx, or a rate limit — uses the cache. - Bounded by
--cache-max-age(default24h). Past that, the entry is ignored and pruned. - Scoped to the exact request. The entry is keyed by API URL, token,
--branch, and--withoverrides, so a different environment or override never reads another's copy. - Shared with
seekrit-run. Both use the same file format and directory, so whichever one runs first warms the cache for the other.
Two trade-offs worth stating plainly, both consequences of a copy that outlives the network:
- A revoked token keeps working offline until the entry expires. That window
is exactly
--cache-max-age, and it only applies while the API is unreachable (a reachable API that refuses the token clears the entry immediately). Set a shorter max-age if that window matters more to you than the outage coverage. - A run served from cache makes no resolve call, so it produces no
env.resolve_deniedaudit entry. If you monitor for revoked credentials still in use, a cached client is invisible to that signal until it next reaches the API.
For the long-lived integrations, the same cache is configured in their own way:
[cache] enabled = true in the egress proxy's config,
and cache.enabled=true in the Kubernetes chart. Both
also retry in the background and switch to live secrets as soon as the API
answers.
Access
Who can decrypt an environment. Every command targets the environment with
--env plus --app or --group.
| Command | Description |
|---|---|
seekrit grant --env <slug> --user <email>|--token <tokenId> | Give a member or service token the environment's key. The key is unwrapped on your machine and re-wrapped to the recipient, so the API only ever sees ciphertext. Members must have finished key setup (seekrit org member list shows who has). |
seekrit grant list --env <slug> | Who currently holds a key, by email or token name rather than raw ids. Admins only. |
seekrit grant rm --env <slug> --user <email>|--token <tokenId> [--yes] | Take the key away. This removes their wrapped copy — anything they already decrypted stays decrypted, so rotate the value too if it may have leaked. Aliased as grant revoke. |
seekrit grant --user … --env … is the bare grant verb and behaves exactly as
it always has; list and rm are subcommands beside it.
Service tokens
| Command | Description |
|---|---|
seekrit token create --name <name> --app <slug> --env <slug> [--allow <group>=<slug>] [--no-grant] | Mint a runtime token bound to an app environment; prints it once. Auto-grants that env's key and every composed group's matching slice. --allow pre-authorizes an alternate group slice for run --with; --no-grant skips granting. |
seekrit token create --name <name> --admin [--org <slug>] | Mint an admin token: org-scoped, no env binding, passes admin-gated routes (create apps/groups/envs, compose, grant, mint tokens). For headless provisioning by agents/automation. Only an admin caller may create one. |
seekrit token list [--org <slug>] | List tokens with role, status, and last-used time. |
seekrit token revoke <tokenId> [--org <slug>] | Revoke a token. Reversible-safe: a revoked token authenticates nothing and frees its plan slot, but stays in the list. |
seekrit token delete <tokenId> [--org <slug>] | Delete a token and drop the keys granted to it. Only allowed once the token has been revoked. Cannot be undone. |
An admin token can also be bound to an environment (pass --admin --app --env)
to both provision structure and decrypt that environment.
Honey tokens
Decoy credentials that unlock nothing and alert your admins the moment anyone presents one. See the honey tokens guide.
| Command | Description |
|---|---|
seekrit honey-token create --name <name> [--placement <note>] [--org <slug>] | Mint a decoy credential and print it once (stdout), so it can be piped straight into the file or variable you're baiting. --placement records where you planted it and is repeated back in the alert email. |
seekrit honey-token list [--org <slug>] | List decoys with trip count, placement, and the time and source IP of the last trip. Aliased as honey-token ls. |
seekrit honey-token delete <honeyTokenId> [--yes] [--org <slug>] | Delete a decoy, which stops it alerting — pull the planted bait too. Trips already recorded stay in the audit log. Aliased as honey-token rm. |
A decoy is byte-for-byte indistinguishable from a real skt_ token, and
presenting one returns exactly the same 401 unknown service token an
unregistered token gets — so an attacker probing credentials can't tell bait from
a typo. Plant them where a thief would look, never anywhere your own tooling
reads: a deploy script that tries one by mistake trips the alarm just as loudly.
Agent integration
seekrit mcp
Run an MCP server over stdio so AI agents
(Claude Code and other MCP clients) can drive seekrit as tools. It reads the
same credentials as every other command — a SEEKRIT_TOKEN, machine credentials
(SEEKRIT_CLIENT_ID + SEEKRIT_CLIENT_SECRET, which auto-mint an admin token),
or the saved config.
# Register with Claude Code (token selects the org; admin token enables provisioning):
SEEKRIT_TOKEN=skt_… claude mcp add seekrit -- seekrit mcp
For a fully autonomous agent, pass machine credentials instead — the server mints and caches its own admin token from them (see the AI agents guide):
claude mcp add seekrit \
--env SEEKRIT_CLIENT_ID=… --env SEEKRIT_CLIENT_SECRET=… -- seekrit mcp
All decryption happens locally, in this process — the server exposes the
tools that touch plaintext (secret values, data keys, decryption-capable
grants), which is why it runs on your machine rather than a hosted endpoint.
Call get_started first — an in-protocol tool (and the server's instructions,
shown to the model on connect) that returns the recommended first-project recipe
so an agent landing here mid-context can orient itself. Other tools include
create_org/create_app/create_env, set_secret/get_secret,
create_token, grant_env, and run_command (inject secrets into a subprocess
without returning their values). Because stdin is the transport, user-auth
sessions that decrypt need SEEKRIT_PASSPHRASE set (token auth needs nothing
extra). Prefer run_command over get_secret with reveal:true so plaintext
never enters the agent's context.
Temporary Postgres credentials (pg)
Mint short-lived database logins that auto-expire. Minting happens client-side: the password and its SCRAM verifier are generated on your machine and only the verifier is sent, so the plaintext never reaches seekrit or Postgres at rest. See Temporary access.
| Command | Description |
|---|---|
seekrit pg target add --name <name> --host <h> --database <db> [--access readonly|readwrite|custom] [--schema public] [--port 5432] [--executor in_do|remote] [--provisioner-url <url>] [--hmac-key <base64>] [--admin-url <url>] [--create-statement <sql>]… | Register a provisioning target. --access (default readonly) sets what leased credentials can do; for the presets the command prints a one-time group-role setup query to run as admin. custom uses --create-statement/--revoke-statement. For --executor in_do, the admin connection string (or SEEKRIT_PG_ADMIN_URL) is wrapped to the broker locally; for --executor remote, pass the shared HMAC key via --hmac-key (or SEEKRIT_PROVISIONER_HMAC_KEY) instead — see the self-hosted provisioner guide. (admin) |
seekrit pg target list [--org <slug>] | List targets (id, name, connection, access level, executor). |
seekrit pg target setup-sql <targetId> [--org <slug>] | Reprint the group-role setup SQL for a preset target. |
seekrit pg target rm <targetId> [--org <slug>] | Remove a target. |
seekrit pg lease <target> [--role <name>] [--ttl 1h] [--json] | Mint a credential; prints a ready-to-use postgres:// URL (the password is shown once and stored nowhere). --ttl accepts 30m/1h/7d. |
seekrit pg leases [--org <slug>] | List the lease ledger (status, role, expiry). |
seekrit pg revoke <leaseId> [--org <slug>] | Revoke a lease now (drops the role immediately). |
# Register a read-only target (prints the group-role setup SQL to run once):
SEEKRIT_PG_ADMIN_URL=postgres://admin:…@db.example.com:5432/app \
seekrit pg target add --name prod-db --host db.example.com --database app --access readonly
# Lease a 30-minute credential and hand the URL straight to psql:
psql "$(seekrit pg lease prod-db --ttl 30m)"
Temporary MySQL / MariaDB credentials (mysql)
The MySQL/MariaDB analog of pg. Minting is client-side too: the password and
its mysql_native_password hash are generated on your machine and only the hash
is sent, so the plaintext never reaches seekrit or MySQL at rest. Presets apply
their GRANTs inline per user (no one-time setup step), and there is no
account-level expiry — the broker drops the user at the deadline. See
Temporary access.
| Command | Description |
|---|---|
seekrit mysql target add --name <name> --host <h> --database <db> [--access readonly|readwrite|custom] [--user-host %] [--port 3306] [--executor in_do|remote] [--provisioner-url <url>] [--hmac-key <base64>] [--admin-url <url>] [--create-statement <sql>]… | Register a provisioning target. --access (default readonly) sets what leased credentials can do; custom uses --create-statement/--revoke-statement. --user-host is the host part of created accounts ('name'@'<host>', default %). For --executor in_do, the admin connection string (or SEEKRIT_MYSQL_ADMIN_URL) is wrapped to the broker locally; for --executor remote, pass the shared HMAC key via --hmac-key (or SEEKRIT_PROVISIONER_HMAC_KEY) instead — see the self-hosted provisioner guide. (admin) |
seekrit mysql target list [--org <slug>] | List MySQL targets (id, name, connection, access level, executor). |
seekrit mysql target rm <targetId> [--org <slug>] | Remove a target. |
seekrit mysql lease <target> [--user <name>] [--ttl 1h] [--json] | Mint a credential; prints a ready-to-use mysql:// URL (the password is shown once and stored nowhere). --ttl accepts 30m/1h/7d. |
seekrit mysql leases [--org <slug>] | List the MySQL lease ledger (status, user, expiry). |
seekrit mysql revoke <leaseId> [--org <slug>] | Revoke a lease now (drops the user immediately). |
# Register a read-only target (no setup SQL needed — grants apply inline):
SEEKRIT_MYSQL_ADMIN_URL=mysql://admin:…@db.example.com:3306/app \
seekrit mysql target add --name prod-db --host db.example.com --database app --access readonly
# Lease a 30-minute credential and hand the URL straight to the mysql client:
mysql "$(seekrit mysql lease prod-db --ttl 30m)"
Temporary Redis credentials (redis)
The Redis (6+) analog of pg/mysql. Minting is client-side too: the password
and its SHA-256 digest are generated on your machine and only the digest is sent
(ACL SETUSER … on #<digest>), so the plaintext never reaches seekrit or Redis
at rest. Presets apply their ACL rules inline per user (no one-time setup step),
and there is no account-level expiry — the broker deletes the ACL user at the
deadline. See Temporary access.
| Command | Description |
|---|---|
seekrit redis target add --name <name> --host <h> [--access readonly|readwrite|custom] [--port 6379] [--db <index>] [--executor in_do|remote] [--provisioner-url <url>] [--hmac-key <base64>] [--admin-url <url>] [--create-statement <cmd>]… | Register a provisioning target. --access (default readonly) sets what leased credentials can do; custom uses --create-statement/--revoke-statement (each a Redis command line, {{name}}/{{verifier}} templated). --db is the logical database index used in the printed URL. For --executor in_do, the admin redis:///rediss:// connection string (or SEEKRIT_REDIS_ADMIN_URL) is wrapped to the broker locally; for --executor remote, pass the shared HMAC key via --hmac-key (or SEEKRIT_PROVISIONER_HMAC_KEY) instead — see the self-hosted provisioner guide. (admin) |
seekrit redis target list [--org <slug>] | List Redis targets (id, name, connection, access level, executor). |
seekrit redis target rm <targetId> [--org <slug>] | Remove a target. |
seekrit redis lease <target> [--user <name>] [--ttl 1h] [--json] | Mint a credential; prints a ready-to-use redis:// URL (the password is shown once and stored nowhere). --ttl accepts 30m/1h/7d. |
seekrit redis leases [--org <slug>] | List the Redis lease ledger (status, user, expiry). |
seekrit redis revoke <leaseId> [--org <slug>] | Revoke a lease now (deletes the ACL user immediately). |
# Register a read-only target (ACL rules apply inline, no setup step):
SEEKRIT_REDIS_ADMIN_URL=rediss://default:…@cache.example.com:6379 \
seekrit redis target add --name prod-cache --host cache.example.com --access readonly
# Lease a 30-minute credential and hand the URL straight to redis-cli:
redis-cli -u "$(seekrit redis lease prod-cache --ttl 30m)"
Agent egress proxy (proxy)
Fetch, configure, and run seekrit-proxy without a
Rust toolchain and without hand-writing a config file. The proxy itself is
unchanged by these commands — they resolve the released binary (verifying its
SHA-256) and generate the same TOML you would otherwise write.
| Command | Description |
|---|---|
seekrit proxy run | Fetch the binary if needed and run it. With --preset/--host/--agent it generates a config on the fly and leaves nothing behind. |
seekrit proxy init | Write a reviewable seekrit-proxy.toml. |
seekrit proxy presets | List the ready-made upstream presets. |
seekrit proxy compose | Print a docker compose sidecar snippet for a generated config. |
seekrit proxy install | Download the binary and print its path. |
seekrit proxy where | Show which binary run would use, without fetching it. |
Generating a config
init and run share these flags. Pass presets, ad-hoc hosts, or an agent
identity — the last takes the rules from
published policy and cannot be combined with
the first two, because server-policy mode rejects local rules rather than
silently ignoring them.
| Flag | Default | Description |
|---|---|---|
--preset <name> | A preset from seekrit proxy presets (repeatable). | |
--host <host[=SECRET,…]> | Ad-hoc rule: a bare hostname and, optionally, the secrets that may reach it (repeatable). Omitting =SECRET permits the operation without letting a credential travel with it. | |
--base-url <url> | Upstream base URL for an OpenAI-compatible gateway. Required by the openai-compatible preset. | |
--secret <NAME> | preset's own | Override a preset's secret name. |
--prefix <path> | preset's own | Override a preset's route prefix. |
--agent <slug> | Take the rules from published agent policy (server mode). | |
--agents <slug> | the --agent one | Additional identities this proxy may serve, for session tickets (repeatable). |
--org <slug> | Organization, for --agent. | |
--mode <reverse|forward|both> | reverse | Which data plane(s) to configure. |
--listen <addr> | 127.0.0.1:8080 | Reverse-proxy address. |
--forward-listen <addr> | 127.0.0.1:8081 | Forward-proxy address. |
--unmatched <tunnel|deny> | tunnel | What to do with an unruled host in forward mode. |
--ca-cert <path> / --ca-key <path> | seekrit-proxy-ca[-key].pem | Interception CA paths (forward mode). |
--cache | off | Add a [cache] block so the proxy can start during a seekrit outage. |
--cache-max-age <dur> | 24h | How stale a cached resolve may be (implies --cache). |
--refresh <dur> | 30s file / 10s server | Re-resolve (and, in server mode, re-fetch) interval. |
--control <addr> | Add a [control] listener for per-agent session tickets. |
init additionally takes -o, --out <path> (default ./seekrit-proxy.toml),
--print to write to stdout instead, and --force to overwrite.
run additionally takes -c, --config <path>, --proxy-version <version>, and
--print-config. With no generation flags it runs the config file as-is.
Resolving the binary
| Variable | Default | Purpose |
|---|---|---|
SEEKRIT_PROXY_BIN | Path to a binary you already have. Skips the download entirely. | |
SEEKRIT_PROXY_VERSION | the CLI's pinned version | Version to fetch. latest is re-resolved every run rather than cached. |
SEEKRIT_PROXY_BASE_URL | https://proxy.seekrit.dev | Where artifacts come from. |
Downloads are cached under $XDG_CACHE_HOME/seekrit/proxy/v<version>/<target>/,
so the fetch happens once per version. A binary already on PATH is deliberately
not used: silently running a different version than the one the CLI pins is
the kind of surprise that costs an afternoon.
seekrit proxy never sees a secret value — it generates config and launches
a process. The proxy resolves and decrypts on its own, with its own
SEEKRIT_TOKEN, which is also why that token must live somewhere the workload
cannot read.
Self-hosted provisioner (provisioner)
Helpers for the remote executor — the
seekrit-provisioner daemon that runs a target's provisioning SQL inside your
own network, so seekrit never sees the database admin credential.
| Command | Description |
|---|---|
seekrit provisioner keygen | Generate a shared HMAC key (base64) for a remote target. Use the same value for --hmac-key when registering the target and for the daemon's SEEKRIT_PROVISIONER_HMAC_KEY. |
Temporary SSH access (ssh)
Issue short-lived SSH certificates. seekrit acts as a certificate authority:
target add generates a CA keypair locally (only the private half is wrapped and
uploaded) and prints the public key to install on your hosts. Minting generates
an ephemeral keypair on your machine and sends only the public key; the signed
certificate comes back and the private key never leaves. See
Temporary access.
| Command | Description |
|---|---|
seekrit ssh target add --name <name> [--host <h>] [--user <login>] [--principal <name>]… [--extension <name>]… [--max-ttl <dur>] | Create an SSH CA target. Generates the CA locally, wraps its private key to the broker, and prints the CA public key + one-time host setup (TrustedUserCAKeys). --principal allow-lists which login users a cert may request (blank = any); --host/--user seed the printed ssh command. (admin) |
seekrit ssh target list [--org <slug>] | List SSH targets (id, name, host, allowed principals). |
seekrit ssh target setup <targetId> [--org <slug>] | Reprint the host setup instructions for a target. |
seekrit ssh target rm <targetId> [--org <slug>] | Remove a target. |
seekrit ssh lease <target> [--principal <name>]… [--ttl 1h] [--out <dir>] [--json] | Mint a certificate; writes id_ed25519 + id_ed25519-cert.pub and prints a ready-to-run ssh command. --principal defaults to the target's user/allow-list. --ttl accepts 30m/1h/8h. |
seekrit ssh leases [--org <slug>] | List the SSH lease ledger (status, expiry). |
seekrit ssh revoke <leaseId> [--org <slug>] | Mark a lease revoked in the ledger. The issued certificate stays valid until it expires (short TTLs are the control). |
# Create a CA target and install the printed CA key on your hosts:
seekrit ssh target add --name prod-fleet --host bastion.example.com --user deploy --principal deploy
# Issue an 8-hour cert, then run the ssh command it prints:
seekrit ssh lease prod-fleet --ttl 8h
Temporary AWS credentials (aws)
Mint short-lived AWS credentials via STS AssumeRole (a tier-2 provider — the
credential comes back wrapped to your machine's ephemeral key, never in the
clear through seekrit). target add registers one assumable IAM role and wraps
a base IAM credential (needs only sts:AssumeRole) to the broker. Minting
generates an ephemeral P-256 keypair locally, sends only the public key, and
unwraps the returned credential on your machine. See
Temporary access.
| Command | Description |
|---|---|
seekrit aws target add --name <name> --role-arn <arn> --region <region> [--external-id <id>] [--session-policy <file>] [--max-ttl <dur>] [--access-key-id <id>] [--secret-access-key <secret>] | Register an AWS role target. The base IAM credential comes from the flags or AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY (and AWS_SESSION_TOKEN if set) and is wrapped to the broker locally. --session-policy further restricts the leased credential; --max-ttl clamps requested lifetime. Prints the IAM trust policy the role needs. (admin) |
seekrit aws target list [--org <slug>] | List AWS targets (id, name, region, role ARN). |
seekrit aws target trust <targetId> [--org <slug>] | Reprint the IAM trust-policy setup for a target. |
seekrit aws target rm <targetId> [--org <slug>] | Remove a target. |
seekrit aws lease <target> [--ttl 1h] [--json] | Mint credentials; prints export AWS_… lines (or JSON with --json). --ttl accepts 15m–12h (STS minimum is 15 minutes; clamped to the role's MaxSessionDuration). |
seekrit aws leases [--org <slug>] | List the AWS lease ledger (status, expiry). |
seekrit aws revoke <leaseId> [--org <slug>] | Mark a lease revoked in the ledger. The issued credential stays valid until it expires (short TTLs are the control). |
# Register a role (base creds from your AWS env vars), then source a 1h credential:
seekrit aws target add --name prod-deploy \
--role-arn arn:aws:iam::123456789012:role/seekrit-deploy --region us-east-1
eval "$(seekrit aws lease prod-deploy --ttl 1h)"
aws sts get-caller-identity
Temporary GCP credentials (gcp)
Mint short-lived GCP access tokens via IAM generateAccessToken (a tier-2
provider — the token comes back wrapped to your machine's ephemeral key, never
in the clear through seekrit). target add registers one impersonable service
account and wraps a base service-account key (needs
roles/iam.serviceAccountTokenCreator on the target) to the broker. Minting
generates an ephemeral P-256 keypair locally, sends only the public key, and
unwraps the returned token on your machine. See
Temporary access.
| Command | Description |
|---|---|
seekrit gcp target add --name <name> --service-account <email> [--scope <scope>…] [--delegate <email>…] [--max-ttl <dur>] [--key-file <path>] | Register a GCP service-account target. The source SA key JSON comes from --key-file or GOOGLE_APPLICATION_CREDENTIALS and is wrapped to the broker locally. --scope (repeatable) sets the OAuth scopes (default cloud-platform); --max-ttl clamps requested lifetime. Prints the IAM binding the target needs. (admin) |
seekrit gcp target list [--org <slug>] | List GCP targets (id, name, service account). |
seekrit gcp target setup <targetId> [--org <slug>] | Reprint the IAM setup for a target. |
seekrit gcp target rm <targetId> [--org <slug>] | Remove a target. |
seekrit gcp lease <target> [--ttl 1h] [--json] | Mint a token; prints export CLOUDSDK_AUTH_ACCESS_TOKEN / export GOOGLE_OAUTH_ACCESS_TOKEN lines (or JSON with --json). --ttl accepts 1m–12h (tokens over 1h need the credential-lifetime-extension org policy). |
seekrit gcp leases [--org <slug>] | List the GCP lease ledger (status, expiry). |
seekrit gcp revoke <leaseId> [--org <slug>] | Mark a lease revoked in the ledger. The issued token stays valid until it expires (short TTLs are the control). |
# Register a service account (source key from GOOGLE_APPLICATION_CREDENTIALS),
# then source a 1h token:
seekrit gcp target add --name prod-deploy \
--service-account deploy@my-project.iam.gserviceaccount.com
eval "$(seekrit gcp lease prod-deploy --ttl 1h)"
gcloud storage ls
Temporary MongoDB credentials (mongodb)
Mint short-lived MongoDB users (a tier-2 provider — MongoDB hashes the password
server-side, so the broker generates it, runs createUser, and returns the
credential wrapped to your machine's ephemeral key, never in the clear
through seekrit). target add registers one cluster and wraps an admin
mongodb:// connection string (needs userAdmin on the database) to the broker.
Minting generates an ephemeral P-256 keypair locally, sends only the public key,
and unwraps the returned credential on your machine. Unlike AWS, revoke is
real — it drops the user. See Temporary access.
| Command | Description |
|---|---|
seekrit mongodb target add --name <name> --database <db> [--uri <uri>] [--access readonly|readwrite|custom] [--role <role@db>…] [--auth-source <db>] [--max-ttl <dur>] [--no-tls] | Register a MongoDB target. The admin connection string comes from --uri or SEEKRIT_MONGODB_ADMIN_URL and is wrapped to the broker locally. --access picks the built-in read/readWrite role on --database (or custom with one or more --role role@db); --max-ttl clamps requested lifetime. Prints the provisioning-user setup. (admin) |
seekrit mongodb target list [--org <slug>] | List MongoDB targets (id, name, host:port, database, access). |
seekrit mongodb target rm <targetId> [--org <slug>] | Remove a target. |
seekrit mongodb lease <target> [--ttl 1h] [--json] | Mint a user; prints export MONGODB_URI='…' (or JSON with --json). --ttl accepts 60s–7d, clamped to the target's --max-ttl. |
seekrit mongodb leases [--org <slug>] | List the MongoDB lease ledger (status, expiry). |
seekrit mongodb revoke <leaseId> [--org <slug>] | Revoke a lease now — drops the MongoDB user immediately. |
# Register a cluster (admin creds from SEEKRIT_MONGODB_ADMIN_URL), then lease a 1h user:
export SEEKRIT_MONGODB_ADMIN_URL='mongodb://admin:pw@mongo.example.com:27017/?authSource=admin'
seekrit mongodb target add --name prod-app --database app --access readonly
eval "$(seekrit mongodb lease prod-app --ttl 1h)"
mongosh "$MONGODB_URI"
Managed keys (kms)
Client-side managed keys for application-layer encryption and signing. Material is generated locally and wrapped to grantees; the server never sees it. See the Managed keys guide.
| Command | Description |
|---|---|
seekrit kms create --name <name> --purpose <encrypt|sign> [--org <slug>] [--app <slug>|--group <slug>] [--grant-user <email>…] [--grant-token <id>…] | Create a key. Generates material locally, self-grants, and optionally grants others. encrypt = AES-256-GCM; sign = ECDSA P-256 (its public key is published). Scope to an app or group, or leave org-wide. |
seekrit kms ls [--org <slug>] | List keys you can see (admins see all; members see granted keys). |
seekrit kms grant --key <name> (--user <email>|--token <id>) [--org <slug>] | Grant a principal the current version. |
seekrit kms revoke --key <name> (--user <email>|--token <id>) [--org <slug>] | Revoke a principal from the key (all versions). |
seekrit kms rotate --key <name> [--org <slug>] | Add a new version and re-wrap it for every current grantee. Old versions stay valid. |
seekrit kms disable --key <name> [--org <slug>] | Block all use: encrypt, decrypt, sign, and new grants/rotations. |
seekrit kms delete --key <name> [--org <slug>] | Delete a key — hides it from every listing and read path; the name frees up for reuse. |
seekrit kms encrypt --key <name> [--context <ctx>] [--org <slug>] | Encrypt stdin → a ce1. blob. --context is bound as AAD and must match on decrypt. |
seekrit kms decrypt --key <name> [--context <ctx>] [--org <slug>] | Decrypt a ce1. blob from stdin. |
seekrit kms generate-data-key --key <name> [--org <slug>] | Print { plaintextBase64, wrapped } — an envelope data key for large payloads. |
seekrit kms open-data-key --key <name> [--org <slug>] | Recover a data key from a dk1. blob on stdin (prints base64). |
seekrit kms sign --key <name> [--org <slug>] | Sign stdin with a signing key → an sg1. signature. |
seekrit kms verify --key <name> --signature <sg1…> [--org <slug>] | Verify an sg1. signature over stdin (exit 0 = valid). Needs only the published public key. |
# Encrypt a field, bound to its context, then read it back:
echo -n "$SSN" | seekrit kms encrypt --key pii --context "field=ssn" > ssn.enc
seekrit kms decrypt --key pii --context "field=ssn" < ssn.enc
# Sign a release and verify it:
echo -n "release-v1.2.3" | seekrit kms sign --key release-signer > r.sig
echo -n "release-v1.2.3" | seekrit kms verify --key release-signer --signature "$(cat r.sig)"
Secret rotation (rotation)
Managed, scheduled replacement of a stored secret's value — and, for the database kinds, of the password on the account it belongs to. (admin). Enabling rotation wraps the environment's data key to your org's rotator key locally; see the rotation guide and Secret rotation.
Every command accepts a rotation id (rot_…) or the secret's name when that name
rotates in only one environment. Durations accept s/m/h/d suffixes
(minimum 5 minutes, maximum 365 days).
| Command | Description |
|---|---|
seekrit rotation enable <SECRET_NAME> --env <slug> --kind <generated|postgres|mysql|redis> --every <duration> [--app <slug>|--group <slug>] [--target <idOrName>] [--username <name>] [--user-host <host>] [--length <n>] [--alphabet <set>] [--now] [--org <slug>] | Configure rotation for an existing secret. --target + --username are required for the database kinds and name an account that already exists. --alphabet (generated only) is alphanumeric, hex, base64url, or printable. --now also rotates immediately. Prints the rot_… id. (admin) |
seekrit rotation list [--org <slug>] [--json] | List policies: id, secret, kind, cadence, status, next run. Never values. (admin) |
seekrit rotation show <rotationOrSecret> [--org <slug>] | One policy in full, including lastError from the last failed attempt. (admin) |
seekrit rotation rotate <rotationOrSecret> [--org <slug>] | Rotate now — the same path the scheduler uses. Prints the new version. (admin) |
seekrit rotation pause <rotationOrSecret> [--org <slug>] | Stop rotating, keeping the policy. (admin) |
seekrit rotation resume <rotationOrSecret> [--org <slug>] | Resume rotating; also clears a failed streak. (admin) |
seekrit rotation set-interval <rotationOrSecret> --every <duration> [--org <slug>] | Change the cadence. (admin) |
seekrit rotation disable <rotationOrSecret> [--org <slug>] | Remove the policy. The secret and its versions are untouched; the rotator's key grant is dropped when the environment has no rotation left. (admin) |
# Re-key an existing Postgres role weekly, against a registered target:
seekrit rotation enable DATABASE_PASSWORD --app web --env production \
--kind postgres --target prod-db --username app_user --every 7d --now
# A value only your own code checks — nothing external is contacted:
seekrit rotation enable API_SIGNING_KEY --app web --env production \
--kind generated --every 30d
seekrit rotation list
seekrit rotation rotate DATABASE_PASSWORD # e.g. after a suspected exposure
Customer-controlled recovery (recovery)
Org-scoped M-of-N recovery. The recovery key is generated and split locally; seekrit stores only its public half and shares it cannot open. Management is (admin); any custodian can approve a ceremony. See the recovery guide.
| Command | Description |
|---|---|
seekrit recovery setup --threshold <M> --custodian <email|skt_id>… [--org <slug>] | Enable recovery: split a fresh recovery key across the custodians, then cover the environments you can decrypt. (admin) |
seekrit recovery status [--org <slug>] | Show the threshold, custodians, and environment coverage. (admin) |
seekrit recovery sync [--org <slug>] | Recovery-protect environments you can decrypt but that aren't yet covered. (admin) |
seekrit recovery rotate --threshold <M> --custodian <email|skt_id>… [--org <slug>] | Rotate to a fresh recovery key and custodian set; re-wraps the environments you can decrypt. (admin) |
seekrit recovery disable [--org <slug>] | Remove the recovery key and every recovery grant. (admin) |
seekrit recovery request [--target-user <email>|--target-token <id>] [--reason <text>] [--org <slug>] | Start a recovery ceremony (defaults to recovering access for yourself). Prints an rrq_… id. (admin) |
seekrit recovery approve <requestId> [--org <slug>] | As a custodian, unwrap your share and contribute it, re-wrapped to the target. |
seekrit recovery complete <requestId> [--org <slug>] | As the target, reconstruct the recovery key and restore your environment access. (admin) |
seekrit recovery cancel <requestId> [--org <slug>] | Cancel an open recovery request. (admin) |
# Enable 3-of-5 recovery, then check coverage:
seekrit recovery setup --threshold 3 \
--custodian alice@example.com --custodian bob@example.com --custodian carol@example.com \
--custodian dan@example.com --custodian erin@example.com
seekrit recovery status
# Run a ceremony: start it, custodians approve, then the target completes.
seekrit recovery request # prints rrq_…
seekrit recovery approve rrq_XXXXXXXX # each custodian, until the quorum is met
seekrit recovery complete rrq_XXXXXXXX
Your account
Your devices and your email preferences. Both are per-user, not per-org, so
neither takes --org.
| Command | Description |
|---|---|
seekrit session list [--all] | The devices seekrit login has authorized, newest first, with the one you're calling from marked. Shows only live sessions unless you pass --all (which includes revoked and expired ones — the ledger is kept). |
seekrit session revoke <sessionId> [--yes] | Sign a device out; its token stops authenticating on its next request (revoking drops the cached copy as it commits, and any copy that outlives it is re-checked within a minute of use). Revoking the session you're currently using is allowed, and says so before it asks. |
seekrit notifications | Your per-type email preferences, on or off. |
seekrit notifications set <type> <on|off> | Turn one notification on or off. An unknown type lists the valid ones. |
Audit
seekrit audit
Print the org's audit trail — the append-only record of every mutation. Admins only.
| Flag | Description |
|---|---|
--org <slug> | Which organization. |
--limit <n> | Entries per page (default 50, max 200). |
--action <action> | Only this action, e.g. env.key_granted. An unrecognized action is rejected rather than silently returning nothing. |
--resource-type <type> | Only this resource type, e.g. environment. |
--cursor <cursor> | Continue from the cursor a previous page printed. |
--all | Page through the whole trail rather than stopping after one page. |
--metadata | Add each entry's metadata as a JSON column. |
When more entries remain, the next cursor is printed to stderr so it doesn't corrupt piped output.
seekrit audit actions
List every action the trail can record — the vocabulary for --action.
# Everything that changed who can decrypt something, as JSON:
seekrit audit --action env.key_granted --all --json
Audit export (log-sink)
Ship every audit row to your own OTLP/HTTP collector (SIEM) within about a
minute of it being written. Admins only. Header values are write-only —
encrypted at rest and never returned — so show reports only the header names.
| Command | Description |
|---|---|
seekrit log-sink | The configured endpoint, whether it's enabled, the header names, and delivery health (last success, last attempt, last error). |
seekrit log-sink set <endpoint> [--header "Name: value"] [--clear-headers] [--disabled] | Point the export at an OTLP/HTTP logs endpoint. --header is repeatable and replaces the whole header set, so pass all of them each time. Passing none leaves the stored headers alone — that's how you change the endpoint without re-entering the credential; --clear-headers removes them. |
seekrit log-sink test | Send a probe and report the result. Exits non-zero on failure, so it works as a health check. |
seekrit log-sink rm [--yes] | Stop exporting and forget the endpoint. |
seekrit log-sink set https://collector.example.com/v1/logs \
--header "Authorization: Bearer $SIEM_TOKEN"
seekrit log-sink test
Third-party sync
Push an environment's resolved secrets to a platform that keeps its own copy: Vercel project env vars, Cloudflare Worker secret bindings, Cloudflare Pages env vars, Cloudflare Secrets Store secrets, Railway service variables, AWS Secrets Manager secrets, AWS SSM parameters, a Render service or environment group, a Fly.io app's secrets, a Northflank secret group, DigitalOcean App Platform variables, Heroku config vars, Netlify site variables, Bunnyshell environment or project variables, GitHub Actions secrets, or Google Secret Manager secrets. Admins only. Each destination has its own guide under Third-party sync.
Sync is the one place seekrit's servers hold plaintext: a destination needs
the value and runs when nobody is logged in, so the sync engine decrypts in
memory for the length of a push. Enabling it for an environment is therefore an
explicit, audited decision — sync enable requires --acknowledge-decryption
(or a yes at the prompt), and who acknowledged is recorded. Where the runtime
lets you decrypt on your own side instead, prefer
seekrit run, the proxy, or the SDKs.
A connection is a destination account; a binding is one environment syncing to one place in it.
| Command | Description |
|---|---|
seekrit sync connections | Destination accounts, with status and last error. |
seekrit sync connect --name <name> [--provider <kind>] [--team-id <id>] [--account-id <id>] [--token-kind <kind>] [--region <region>] [--access-key-id <id>] [--base-url <url>] [--project-id <id>] [--langgraph-region <region>] [--langgraph-tenant <id>] | Register an account. The credential is read from stdin (or prompted) — never a flag, so it can't land in shell history — and is wrapped to the connection's public key before it is sent. --team-id is Vercel's (omit for a personal account); --account-id is required for every Cloudflare provider and for Netlify, where it is the team slug (or account ID) whose environment variables the connection writes; --token-kind is Railway's (account or project — Railway sends the two in different headers); --region and --access-key-id for every AWS one; --project-id is gcp-secret-manager's, the project whose Secret Manager the connection writes; --base-url is GitHub's and LangGraph Platform's, and only for a self-hosted install — a GitHub Enterprise Server appliance (https://github.acme.com/api/v3) or a self-hosted LangSmith control plane (https://langsmith.acme.com/api-host) — omit it for github.com, Enterprise Cloud, and a LangChain-hosted LangSmith, and note it must be https, since the URL carries the token; --langgraph-region picks which of LangChain's four control-plane hosts a langgraph-platform connection addresses (us by default, then eu, apac, aws-us) and matters because a key minted in one region is refused by another with a bare 401, so the wrong one looks exactly like a bad credential — it is mutually exclusive with --base-url; --langgraph-tenant is the LangSmith workspace UUID, needed only for an organization-scoped key, which reaches several workspaces and is refused without it; render, fly, northflank, digitalocean, heroku, and bunnyshell take none of them — a Render API key is user-scoped, a Northflank token names its own team, a DigitalOcean token its own account, a Heroku token its user's access to every app they can reach, a Bunnyshell token its user's access to every organization they belong to, and a Fly token is pasted whole, FlyV1 prefix included, because seekrit reads which auth scheme it takes from the token itself. On AWS the credential read from stdin is the secret access key — the access key id is an identifier, not a secret, so it is stored in the clear where the dashboard can show it. On GCP it is the whole service-account key JSON, the same credential shape seekrit gcp target add takes, so it is usually piped from the key file (… < key.json). |
seekrit sync verify <connection> [--provider <kind>] <destination flags> | Check the stored credential against a destination. Takes the same destination flags as sync enable. Exits non-zero on failure. |
seekrit sync disconnect <connection> [--yes] | Delete an account, its bindings, and its keypair. Values already pushed stay on the destination. |
seekrit sync bindings | What is syncing where, with mode, last run, and last error. |
seekrit sync enable … | Start syncing one environment (see below). |
seekrit sync pause <bindingId> / resume <bindingId> | Stop and restart pushing without deleting the binding. |
seekrit sync disable <bindingId> [--yes] | Delete a binding and revoke seekrit's key for that environment. Aliased as sync rm. |
seekrit sync run <bindingId> | Push now, synchronously, and report what landed. Exits non-zero unless the run fully succeeded — partial is a real outcome. |
seekrit sync runs [--binding <id>] | The run history. |
seekrit sync enable takes the environment (--env, plus --app), the
connection (--connection), and the destination:
| Flag | Description |
|---|---|
--connection <name> | Destination account, by name or id. |
--provider <kind> | vercel (default), cloudflare-workers, cloudflare-pages, cloudflare-secrets-store, railway, aws-secrets-manager, aws-parameter-store, render, fly, northflank, digitalocean, heroku, netlify, bunnyshell, github-actions, gcp-secret-manager, or langgraph-platform. |
--project <id> | vercel: project id (prj_…) or name. cloudflare-pages: project name. northflank: project id — the slug in its URL. bunnyshell: project ID — writes the project's variables, which every environment created in it afterwards inherits. |
--target <list> | Comma-separated deployment targets (default production). vercel: production, preview, development. cloudflare-pages: production, preview. netlify: production, deploy-preview, branch-deploy, branch, dev. |
--git-branch <branch> | vercel: restrict preview writes to one git branch. netlify: the branch a --target branch context applies to (required with it). |
--script <name> | cloudflare-workers: the Worker's name. A Wrangler environment is its own Worker — my-api --env staging is the Worker my-api-staging. |
--store-id <id> | cloudflare-secrets-store: the store ID (32 hex). |
--scopes <list> | cloudflare-secrets-store: comma-separated scopes for secrets seekrit creates (default workers). |
--railway-project <id> | railway: the project ID (a UUID). |
--railway-environment <id> | railway: the Railway environment ID (a UUID) — its deployment environment, not the seekrit one. |
--service <id> | railway: the service ID (a UUID). Omit to write the environment's shared variables. render: the service ID from its dashboard URL (srv-…, or crn-… for a cron job). |
--skip-deploys | railway: stage values without triggering the redeploy that would put them live. |
--path <path> | aws-parameter-store: the hierarchy to write under, /prod/storefront/ (leading and trailing slash). aws-secrets-manager: an optional name prefix, prod/storefront/. |
--layout <layout> | aws-secrets-manager, gcp-secret-manager: secret-per-name (default) or json-bundle — every value as one JSON secret, the shape ECS and Lambda read with secret-arn:json-key::. |
--secret-name <name> | aws-secrets-manager, gcp-secret-manager: required with --layout json-bundle — the one secret to write. |
--param-type <type> | aws-parameter-store: SecureString (default) or String. |
--tier <tier> | aws-parameter-store: Standard (default), Advanced, or Intelligent-Tiering. |
--kms-key-id <id> | aws: a customer-managed KMS key, as an ID, ARN, or alias. Defaults to the AWS-managed key. |
--env-group <id> | render: the environment group ID (evg-…). Pass this or --service, not both — which flag you use picks the destination. |
--fly-app <name> | fly: the Fly app name (not --app, which is the seekrit application). One secret set per app, staged until Machines restart — fly secrets deploy rolls them out. |
--secret-group <id> | northflank: the secret group to write, by the slug in its URL. It must already exist. |
--do-app <id> | digitalocean: the App Platform app ID — the UUID in its dashboard URL, not the app's name. |
--component <name> | digitalocean: write one component's own variables instead of the app-level ones. A component-level name overrides an app-level one. |
--env-scope <scope> | digitalocean: RUN_TIME (default), BUILD_TIME, or RUN_AND_BUILD_TIME. Run time keeps values out of build logs and buildpacks. |
--heroku-app <name> | heroku: the Heroku app name, or its UUID (not --app, which is the seekrit application). One set of config vars per app; writing them cuts a release and restarts the app's dynos. |
--netlify-site <id> | netlify: the site's API ID — the UUID under Project configuration → General → Project information, not the site name or its .netlify.app address. Netlify resolves no site names on the environment variable endpoints, and a site it cannot resolve gets the variables written to the whole team. |
--no-netlify-secret | netlify: create readable variables instead of write-only Netlify secrets. seekrit creates secrets by default; pass this if your plan has no Secrets Controller. |
--bunnyshell-environment <id> | bunnyshell: the environment ID, from bns environments list or the dashboard URL — its variables are inherited by every component in the environment. Omit it and pass --project to write the project's variables instead; passing both is an error, since a binding writes to one. |
--no-bunnyshell-secret | bunnyshell: create variables visible in Bunnyshell's dashboard instead of secret ones. seekrit marks them secret by default. Bunnyshell encrypts every variable at rest either way, so the flag decides who can read it, not whether it is stored in the clear. |
--gh-repo <owner/name> | github-actions: the repository, exactly as GitHub writes it (acme/storefront). Taken as one flag because that is how GitHub writes a repository everywhere; asking for it in two invites pasting the pair into one of them. |
--gh-environment <name> | github-actions: write to one deployment environment's secrets rather than the repository's. Needs --gh-repo. The environment must already exist — seekrit will not create one, because an environment is a deployment gate and creating an unprotected one from a typo would remove it. |
--gh-org <login> | github-actions: write organization secrets instead of a repository's. Mutually exclusive with --gh-repo and --gh-environment. |
--gh-visibility <v> | github-actions org secrets: all, private (CLI default), or selected. all includes repositories added later, and public ones. |
--gh-repo-ids <ids> | github-actions: comma-separated numeric repository IDs for --gh-visibility selected. GitHub's API takes IDs, not names — gh api repos/acme/storefront --jq .id. |
--gcp-prefix <prefix> | gcp-secret-manager: prepended to every secret ID, e.g. prod-storefront-. Not --path: a Secret Manager ID takes letters, digits, hyphens, and underscores — no slashes or dots. |
--gcp-replication <policy> | gcp-secret-manager: automatic (default) or user-managed. Set when a secret is created and immutable after. |
--gcp-locations <list> | gcp-secret-manager: comma-separated regions, required with --gcp-replication user-managed. Each is billed as its own active version. |
--gcp-kms-key <name> | gcp-secret-manager: a Cloud KMS key, as its full resource name (projects/…/cryptoKeys/…). KMS keys are regional, so one key covers automatic replication or a single location. |
--langgraph-deployment <id> | langgraph-platform: the deployment UUID, from its dashboard URL or the id in GET /v2/deployments. A deployment is the whole destination — its secrets belong to the deployment, so there is no narrower scope to name. Every write creates a new revision, which rebuilds and rolls out the Agent Server; seekrit reads first and sends nothing when nothing would change, so a stable environment never redeploys on the reconcile timer. |
--gcp-prune-versions | gcp-secret-manager: destroy the version each push supersedes, keeping one active version per secret. Only ever a version seekrit itself wrote. |
--prefix <prefix> | Prepend this to every destination key name. |
--include <globs> / --exclude <globs> | Comma-separated name globs. include allows, exclude then removes; exclusion wins. |
--on-delete delete|retain | What happens on the destination when a secret is removed here (default delete). |
--mode auto|manual | Push on every write (default), or only on sync run. |
--acknowledge-decryption | Required non-interactively; confirms seekrit's servers may decrypt this environment. |
Enabling wraps the environment's data key — and the key of every group it composes — to the connection, on your machine. You need a key for all of them, so run it as someone who can already read the environment.
printf '%s' "$VERCEL_TOKEN" | seekrit sync connect --name acme-vercel --team-id team_…
seekrit sync enable --connection acme-vercel --app storefront --env production \
--project prj_… --target production --acknowledge-decryption
seekrit sync run syb_…
# Cloudflare: one scoped token per product, plus the account id
printf '%s' "$CLOUDFLARE_API_TOKEN" | seekrit sync connect --name acme-cf \
--provider cloudflare-workers --account-id 0123456789abcdef0123456789abcdef
seekrit sync enable --connection acme-cf --provider cloudflare-workers \
--script my-api --app storefront --env production --acknowledge-decryption
# Railway: three UUIDs address a variable, and the token kind picks the header
printf '%s' "$RAILWAY_TOKEN" | seekrit sync connect --name acme-railway \
--provider railway --token-kind project
seekrit sync enable --connection acme-railway --provider railway \
--railway-project 11111111-1111-4111-8111-111111111111 \
--railway-environment 22222222-2222-4222-8222-222222222222 \
--service 33333333-3333-4333-8333-333333333333 \
--app storefront --env production --acknowledge-decryption
# AWS: the region and key id are config, the secret access key is the credential
printf '%s' "$AWS_SECRET_ACCESS_KEY" | seekrit sync connect --name acme-aws \
--provider aws-secrets-manager --region us-east-1 --access-key-id AKIA…
seekrit sync enable --connection acme-aws --provider aws-secrets-manager \
--path prod/storefront/ --app storefront --env production --acknowledge-decryption
# Render: one key for the whole workspace, then a service or an env group
printf '%s' "$RENDER_API_KEY" | seekrit sync connect --name acme-render --provider render
seekrit sync enable --connection acme-render --provider render \
--service srv-abc123 --app storefront --env production --acknowledge-decryption
seekrit sync enable --connection acme-render --provider render \
--env-group evg-xyz789 --app storefront --env staging --acknowledge-decryption
# Fly.io: the app name is the whole destination; nothing to set on the connection
printf '%s' "$(fly tokens create deploy -a storefront-production)" \
| seekrit sync connect --name acme-fly --provider fly
seekrit sync enable --connection acme-fly --provider fly \
--fly-app storefront-production \
--app storefront --env production --acknowledge-decryption
# Northflank: one secret group, named by slug — the token carries its own team
printf '%s' "$NORTHFLANK_API_TOKEN" | seekrit sync connect --name acme-northflank \
--provider northflank
seekrit sync enable --connection acme-northflank --provider northflank \
--project default-project --secret-group app-secrets \
--app storefront --env production --acknowledge-decryption
# DigitalOcean App Platform: app-level variables, written encrypted.
# Each push submits a new app spec, which starts a deployment.
printf '%s' "$DIGITALOCEAN_TOKEN" | seekrit sync connect --name acme-digitalocean \
--provider digitalocean
seekrit sync enable --connection acme-digitalocean --provider digitalocean \
--do-app 4f6c71e2-1e90-4762-9fee-6cc4a0a9f2cf \
--app storefront --env production --acknowledge-decryption
# Heroku: config vars on one app — each push restarts its dynos
printf '%s' "$(heroku authorizations:create --short)" \
| seekrit sync connect --name acme-heroku --provider heroku
seekrit sync enable --connection acme-heroku --provider heroku \
--heroku-app storefront-production \
--app storefront --env production --acknowledge-decryption
# Netlify: one site's variables, per deploy context — the team is on the connection
printf '%s' "$NETLIFY_AUTH_TOKEN" \
| seekrit sync connect --name acme-netlify --provider netlify --account-id acme
seekrit sync enable --connection acme-netlify --provider netlify \
--netlify-site 3970e0fe-8564-4903-9a55-c5f8de49fb8b \
--target production,deploy-preview \
--app storefront --env production --acknowledge-decryption
# Bunnyshell: one environment's variables — the connection carries no scope
printf '%s' "$BUNNYSHELL_TOKEN" \
| seekrit sync connect --name acme-bunnyshell --provider bunnyshell
seekrit sync enable --connection acme-bunnyshell --provider bunnyshell \
--bunnyshell-environment env-9f3a2b \
--app storefront --env production --acknowledge-decryption
# Bunnyshell: the project instead, to seed ephemeral environments that don't exist yet
seekrit sync enable --connection acme-bunnyshell --provider bunnyshell \
--project prj-4c8d1e \
--app storefront --env preview --acknowledge-decryption
# GitHub Actions: prefer seekritdev/github-action, which decrypts in the run.
# Sync only for what an Action cannot reach — `with:` inputs of third-party
# actions, `secrets: inherit`, job-level container/services credentials.
printf '%s' "$GITHUB_TOKEN" \
| seekrit sync connect --name acme-github --provider github-actions
# ...to one deployment environment's secrets, the narrowest scope GitHub has
seekrit sync enable --connection acme-github --provider github-actions \
--gh-repo acme/storefront --gh-environment production \
--app storefront --env production --acknowledge-decryption
# Google Secret Manager: the credential is the whole key file, so pipe it in
seekrit sync connect --name acme-gcp --provider gcp-secret-manager \
--project-id acme-prod < key.json
seekrit sync enable --connection acme-gcp --provider gcp-secret-manager \
--gcp-prefix prod-storefront- --gcp-prune-versions \
--app storefront --env production --acknowledge-decryption
Billing
| Command | Description |
|---|---|
seekrit billing | The org's plan, subscription status, current usage against what the plan includes, and which self-serve actions this deployment supports. While limits aren't enforced it says so — the numbers are informational. |
seekrit billing entitlements | Every entitlement the org resolves to, and where each value came from. |
seekrit billing checkout <family> | Start a self-serve upgrade. Prints a checkout URL to open. |
seekrit billing portal | Print a billing-portal URL for payment methods and invoices. |
seekrit billing cancel [--yes] | Cancel the subscription and drop back to the Free plan. |