# CLI

The `seekrit` CLI injects a decrypted, layered environment into your processes. It decrypts
locally using the same keys as the web app — a service token's embedded key, or your
passphrase-unlocked private key. At runtime a **service token selects the org, app, and
environment**, so `seekrit run` needs nothing else.

For an exhaustive list of commands and flags, see the [CLI reference](/docs/reference/cli).

## Authentication

Two credentials, one for each kind of caller.

### You, at a terminal: `seekrit login`

Run it with no arguments. The CLI prints a URL and a pairing code, opens the URL
when you press `[Enter]`, and you authorize the device in the dashboard — entering
your authenticator code again if you have one, since this creates a long-lived
credential.

```bash
seekrit login
```
```
Sign in to seekrit to authorize this device (you@laptop).

  https://app.seekrit.dev/cli/login?code=RFH4R-C36QG

  code: RFH4R-C36QG   — check it matches the one in your browser

Press [Enter] to open it in your browser (Ctrl-C to cancel)…
✓ Signed in as you@example.com — this device is authorized for 90 days.
```

The saved session acts as **you**: every org you're a member of, at your role — so
there's no org, app, or environment to pick, and management commands work the same
as the dashboard. Reading a secret's *value* still unlocks your own private key with
your passphrase on that machine, which is why a stolen session file reveals no
secrets. `seekrit logout` revokes it; so does the CLI sessions list under
**account → security**.

On a headless box or over SSH, add `--no-browser` and open the printed URL wherever
you do have a browser.

### Machines and CI: a service token

A **service token** (`skt_…`) is bound to one application environment and carries
its own key, so it decrypts unattended with no passphrase and no browser. Mint one
in the web console (or with the CLI once you hold an admin token).

- `SEEKRIT_TOKEN` — the service token. Machines and CI read it from the environment.
- `SEEKRIT_API_URL` — override the API base URL (defaults to `https://api.seekrit.dev`).
- `seekrit login --token skt_…` persists it to `~/.config/seekrit/config.json`.

```bash
# machine / CI
export SEEKRIT_TOKEN=skt_...

# or persist it to the config file
seekrit login --token skt_...
```

Agents take a third path — one machine credential that drives both MCP planes; see
[AI agents](/docs/guides/ai-agents).

## Finding your way around

Signed in on a machine you've never used before, start by asking what you can reach:

```bash
seekrit whoami                  # who you are, and via which credential
seekrit org list                # every org you belong to, and your role
seekrit org tree                # its apps and groups, with their environments
```

`org tree` is usually enough to orient yourself. When you need detail, every resource has a
`show`, and each one answers the question you actually have:

```bash
seekrit app show storefront     # its environments — and whether you can decrypt each
seekrit env show --env production
```

`app show` marks each environment `can decrypt` or `no key`. That column is the answer to
"why does `secrets get` fail here?" — secret **names** are visible to any member, but a
**value** needs a key grant. `env show` goes further: which groups the environment composes and
in what order, who holds a key for it, and how many secrets it has.

To see and change who can read an environment:

```bash
seekrit grant list --app storefront --env production
seekrit grant --app storefront --env production --user teammate@example.com
seekrit grant rm --app storefront --env production --user former@example.com
```

Every listing prints an aligned table at a terminal and plain tab-separated rows when piped, so
`seekrit app list | cut -f1` works. Add `--json` anywhere you'd rather have the API's own
response.

## Linking a project

`seekrit init` writes a `seekrit.json` naming the default org and app for management commands. It
is **environment-independent** — it never pins an environment — so it's safe to commit and behaves
the same everywhere.

```bash
seekrit init --org acme --app storefront
```

The environment is chosen at runtime by the service token (or the `--env` flag when you run
commands interactively).

## Running with a service token

This is the primary path: the token carries its org, app, and environment.

```bash
export SEEKRIT_TOKEN=skt_...
seekrit run -- ./start-server          # resolves & injects; no flags needed
seekrit export --format dotenv > .env
```

The resolved environment is **layered**, lowest precedence first:

```
group secrets  <  app-env secrets  <  .env file  <  process env
```

Add `--explain` to see where each variable came from, and `--with <group>=<slug>` to swap a single
group's slice for one run (see [Environments & groups](/docs/guides/environments)).

## Running interactively (as a user)

Without a token, target the environment explicitly:

```bash
seekrit run --app storefront --env production -- npm run dev
seekrit export --app storefront --env production --format shell
```

## Reading & writing individual secrets

Every `secrets` command targets an environment with `--env` plus `--app` (or `--group`); `--org`
comes from `seekrit.json` or a lone org.

```bash
seekrit secrets list --app storefront --env production
seekrit secrets get STRIPE_KEY --app storefront --env production
seekrit secrets set DATABASE_URL 'postgres://…' --app storefront --env production
printf '%s' "$TOKEN" | seekrit secrets set GITHUB_TOKEN --app storefront --env production
seekrit secrets rm OLD_KEY --group common --env production   # a group's secret
```

A value may reference another secret in the same environment — stored literally
and assembled when it is read, so a rotation flows through automatically:

```bash
seekrit secrets set DB_HOST db.internal --app storefront --env production
seekrit secrets set DATABASE_URL 'postgres://app@${DB_HOST}/app' --app storefront --env production
seekrit secrets get DATABASE_URL --app storefront --env production
# postgres://app@db.internal/app        (--raw prints the stored text)
```

See [secret references](/docs/guides/references) for the full rules.

## Undoing a bad write

Each `set` appends a version, so you can always look back — and go back:

```bash
seekrit secrets history DATABASE_URL --app storefront --env production
seekrit secrets get DATABASE_URL --version 2 --app storefront --env production  # peek first
seekrit secrets restore DATABASE_URL 2 --app storefront --env production
```

`history` prints when each version was saved, who saved it, and which ones were
themselves restores — never the values. `restore` writes the old value back as
a *new* version, so nothing is lost and the rollback can be rolled back. See
[point-in-time restore](/docs/reference/cli#point-in-time-restore) for the
details.

## Importing a `.env` file

Bulk-load an existing `.env` into an environment. Each `KEY=VALUE` is encrypted
locally and stored; names that already exist are overwritten. Pass `--dry-run`
first to preview which names are new versus updated (nothing is written).

```bash
seekrit secrets import --app storefront --env production --dry-run   # preview (default .env)
seekrit secrets import .env.production --app storefront --env production
cat .env | seekrit secrets import - --group common --env production  # from stdin, into a group
```

The importer parses the same `.env` syntax as [`seekrit run`](/docs/guides/run)
(`export` prefixes, `#` comments, single/double quotes). An invalid variable name
aborts the whole import before anything is written.

## Unlocking (users)

When authenticated as a user (not a service token), decryption needs your passphrase to unlock
your private key. Set it non-interactively for scripts:

```bash
export SEEKRIT_PASSPHRASE='…'
```

Omit it and the CLI prompts. Service tokens don't need a passphrase — their key is in the token.

> **Tip:** In CI and containers, prefer a **service token** granted only the environments it needs. It requires no passphrase and can be revoked independently. See [Service tokens](/docs/guides/service-tokens).

## Installing the CLI

The CLI is published to npm. Install it globally with your package manager:

```bash
npm install -g @seekrit/cli
seekrit --help
```

### As a container

The CLI also ships as a multi-arch Docker image —
[`seekritdev/cli`](https://hub.docker.com/r/seekritdev/cli) — for CI runners and
agent sandboxes. Its entrypoint is `seekrit`, so pass subcommands straight
through:

```bash
docker run --rm \
  -e SEEKRIT_TOKEN=skt_... \
  -v "$PWD:/work" -w /work \
  seekritdev/cli run -- ./deploy.sh
```

Pin a release (`seekritdev/cli:0.10.0`) or track `:edge`. For a Node-free
runtime image, prefer the [`seekrit-run`](/docs/guides/run) launcher instead.
