Berserk Docs

Berserk CLI

Command-line tool for interacting with Berserk

The Berserk CLI provides command-line access for querying data, managing clusters, and automation. It pairs especially well with AI coding agents like Claude Code for investigating production issues.

Installation

curl -fsSL https://go.bzrk.dev | bash

This installs the bzrk binary to ~/.local/bin. You can override the install directory with BZRK_INSTALL_DIR:

BZRK_INSTALL_DIR=/usr/local/bin curl -fsSL https://go.bzrk.dev | bash

To install a specific version:

curl -fsSL https://go.bzrk.dev | bash -s v1.0.15

Platform support

The CLI is available for Linux (x86_64 and aarch64) and macOS (Apple Silicon).

Getting Started

The quickest path from a fresh install to your first query:

# 1. Verify the binary
bzrk --help

# 2. Create a profile pointing at your gateway, and make it active.
#    --database picks the default database for queries; "default" is
#    the one every cluster ships with (optional — this is the default).
bzrk profile add dev \
  --endpoint https://berserk.dev.example.com \
  --database default
bzrk profile use dev   # so the commands below need no -P flag

# 3. Sign in (device-code flow)
bzrk login

# 4. See what's there
bzrk database list   # databases (admin-only in v1)
bzrk table list      # tables in the active database

# 5. Run a query. Always pass --since — it defaults to "1h ago".
bzrk search "default | count" --since "24h ago"

A few notes on the sequence:

  • Profile before login. bzrk login signs in an existing profile, so it has to come after step 2 — there's no zero-config login. With no profile it stops and tells you to create one.
  • profile use sets the active profile once, so the rest of the commands need no -P. Pass -P <name> for a one-off against a different profile — see Resolution order.
  • default is the catch-all table every cluster ships with; swap in any name from bzrk table list.

The sections below cover profiles — file layout and resolution — and authentication in detail.

Profiles

Profiles let you store named connection configurations so you can switch between environments (local, dev, production) without remembering endpoint URLs. The storage splits two concerns:

  • Endpoints — named URLs. Not secret; safe to share.
  • Sessions — credentials (bearer + refresh token + expiry) referencing an endpoint by name.

Configuration file

User configuration lives at ~/.config/bzrk/config.toml (following XDG Base Directory). The file mode is enforced to 0600 — the CLI refuses to read it otherwise and tells you the exact chmod 600 <path> to run. bzrk profile add and bzrk login set the mode automatically.

default_session = "dev"      # the active profile, used when no -P is passed

# Endpoint glossary — URLs by name, no secrets.
[endpoints.dev]
url = "https://berserk.dev.example.com"

[endpoints.gw-local]
url = "http://localhost:9500"

# A session pairs credentials with an endpoint, by name.
[sessions.dev]
endpoint = "dev"
bearer_token = "abcdef01…"
refresh_token = "0123456789…"
access_token_expires_at = "2026-05-26T14:00:00Z"

[sessions.gw-local]
endpoint = "gw-local"
bearer_token = "…"
refresh_token = "…"

Each session has the following fields:

FieldRequiredDescription
endpointYesThe name of an [endpoints.X] entry the session points at.
bearer_tokenNoAccess token issued by bzrk login. Sent as Authorization: Bearer … on every request. Auto-refreshed before expiry.
refresh_tokenNoLong-lived token used to mint new access tokens. bzrk logout revokes it server-side and clears it locally.
access_token_expires_atNoRFC 3339 timestamp written by bzrk login. The CLI refreshes ~30s before this fires.
username, databaseNoOptional metadata. database sets the default database for queries on this profile (overridable per-invocation with --database).

Client certificates and custom headers

When a gateway sits behind a mutual-TLS (mTLS) edge — one that requires every client to present an X.509 certificate — attach the certificate and any routing headers to the endpoint. These describe how to reach that URL, so every session pointing at the endpoint inherits them.

[endpoints.secure]
url = "https://gateway.internal.example:443"
# Client identity presented for mTLS (PEM). Both are required together.
client_cert_path = "~/.cache/certs/client.pem"   # leaf + signing chain
client_key_path  = "~/.cache/certs/client-key.pem"
# Verify the server against this CA instead of the system trust store (PEM, optional).
ca_cert_path     = "~/.cache/certs/ca.pem"
# TLS server name (SNI / authority) to verify against, when it differs from the
# endpoint host — e.g. an upstream service identity behind a routing proxy (optional).
tls_server_name  = "upstream.internal.example"

# Headers added to every gRPC request to this endpoint — e.g. an edge routing tag.
[endpoints.secure.headers]
"x-routing-tag" = "region/prod"
Endpoint fieldDescription
client_cert_pathPEM client certificate (leaf + chain) presented for mTLS. Requires client_key_path and an https:// URL.
client_key_pathPEM private key for client_cert_path.
ca_cert_pathPEM CA bundle used to verify the server, instead of the system roots.
tls_server_nameTLS server name (SNI / authority) to verify against when it differs from the endpoint host.
headersTable of Name = "Value" pairs attached to every gRPC request sent to this endpoint.

Paths may start with ~ or $HOME; the CLI expands them to your home directory. The mTLS fields require an https:// endpoint — the CLI refuses to start otherwise. The certificate is re-read on every invocation, so an externally-rotated certificate is picked up by the next command.

bzrk profile add accepts the same flags and persists them into the new [endpoints.X] entry, so you don't have to hand-edit config.toml:

bzrk profile add secure \
  --endpoint https://gateway.internal.example:443 \
  --client-cert ~/.cache/certs/client.pem \
  --client-key  ~/.cache/certs/client-key.pem \
  --ca-cert     ~/.cache/certs/ca.pem \
  --tls-server-name upstream.internal.example \
  --header "x-routing-tag: region/prod"

Every setting can also be supplied (or overridden) per-invocation with a flag — handy for CI or while testing:

bzrk -P secure search "default | take 10" --since "1h ago" \
  --client-cert ~/.cache/certs/client.pem \
  --client-key  ~/.cache/certs/client-key.pem \
  --ca-cert     ~/.cache/certs/ca.pem \
  --tls-server-name upstream.internal.example \
  --header "x-routing-tag: region/prod"

Flags win over the endpoint's stored values; --header is repeatable and merges over the endpoint's headers (the flag wins on a name clash).

Managing profiles

# List profiles
bzrk profile list

# Add a profile
bzrk profile add dev --endpoint https://berserk.dev.example.com

# Set the active profile (used when no -P is passed)
bzrk profile use gw-local

# Rename
bzrk profile rename dev-gw dev

# Remove
bzrk profile remove old-env

After adding a profile, run bzrk login to authenticate against it (or set BZRK_BEARER_TOKEN for unattended use). See Authenticating below.

Resolution order

When you run bzrk, the CLI picks a profile by walking these in order:

  1. Explicit --endpoint / --bearer-token flags override the resolved profile's URL / token.
  2. -P <name> — use that profile.
  3. BZRK_SESSION env var — same.
  4. Otherwise the active profile (default_session, set by bzrk profile use).
  5. Default endpoint (http://localhost:9500) if nothing matches.

Migration

If you previously had ~/.config/bzrk/profiles.toml, the first invocation auto-migrates it to config.toml and renames the original to profiles.toml.bak-<ISO>. The migration is idempotent — once config.toml exists, the legacy reader doesn't fire again.

Authenticating

The CLI talks to Berserk through the gateway service — the auth edge that owns OIDC, sessions, and bearer-token issuance. Every CLI invocation (except bzrk login itself) carries a bearer token; without one you'll see Run 'bzrk login' to authenticate. and exit.

bzrk login — RFC 8628 device-code flow

bzrk login signs in the active profile, so create one first. With no resolvable profile it stops with an error telling you to pass --profile <name> or run bzrk profile use <name> first; there is no zero-config login.

Sign in via the device-code flow:

bzrk login            # signs in the active profile
bzrk -P dev login     # or target a specific profile

The CLI does three things:

  1. POSTs to /api/oauth/device on your gateway, getting back a short-lived device_code + user_code + verification_uri.
  2. Prints the verification URL + user code on stderr so stdout stays clean for piping, and (on a TTY) tries to open the browser as a soft best-effort.
  3. Polls the gateway every few seconds until you approve in the browser (or until the device code expires — ~10 minutes).
$ bzrk -P dev login
To authenticate, open https://berserk.example.com/oauth/device and enter:

    user_code: ABCD-WXYZ

Waiting for approval…
✓ Signed in as alice@example.com (profile: dev)

On success the CLI persists (access_token, refresh_token, expires_at) into the active profile in ~/.config/bzrk/config.toml. Access tokens refresh automatically on every command; you only re-run bzrk login when the refresh token expires or you're switching identities.

Where the verification URL points

verification_uri is derived from the gateway's GATEWAY_PUBLIC_BASE_URL. If you're running locally with port-forward, set that to http://127.0.0.1:9500 so the URL is reachable from your browser.

bzrk auth status — who am I

Prints the resolved identity from the gateway's GET /api/me:

bzrk auth status
# alice@example.com (user_id 019e41d1-…, session expires 2026-05-26T14:00:00Z)

bzrk logout — revoke the token

Revokes the refresh token server-side and clears the access / refresh / expiry fields from the active profile. Idempotent.

bzrk logout

Scripted / CI use

For non-interactive use (CI, scheduled jobs), set BZRK_BEARER_TOKEN directly — it overrides whatever's in the active profile:

BZRK_BEARER_TOKEN="…" bzrk search "default | take 10"

Provision the bearer token via your secret manager. Service-account-style tokens (issued by a logged-in admin, scoped to a single workload) are tracked as a follow-up.

On this page