Administration

Operator CLI

Manage the platform from a terminal — organizations, applications, pricing, usage, readiness — with nothing to configure.

dl is the operator CLI for the platform — for a platform admin managing the deployment, not for a tenant's backend or end users. It signs in as you, the same way the admin console does, and needs nothing configured beyond which deployment to talk to.

go install github.com/deeplinq-org/deeplinq-cli/cmd/dl@latest

dl auth login
dl org list

Why nothing needs configuring

dl reads /.well-known/oauth-protected-resource (RFC 9728) from the API, which names the identity provider and the CLI's own public client id. It never compiles in an issuer or a client id, so pointing it at a different deployment is one setting:

export DEEPLINQ_API=https://api.example.com   # default: https://api.ondeeplinq.com

Sign-in is the device authorization grant (RFC 8628): approve the login in a browser, on any device, including one other than the terminal you ran the command on. There is no client secret to leak and nothing to rotate on a laptop — the CLI is a public native client (RFC 8252).

Commands

The grammar is GitHub CLI's: dl <noun> <verb>, noun singular. Plural and long noun forms (organizations, apps, …) are aliases, as are the top-level dl login, dl logout and dl whoami.

Authentication

dl auth login [--api URL] [--client-id ID]
dl auth logout
dl auth status [--json]        # alias: dl whoami

auth status answers three questions — am I logged in, as whom, what next — and verifies rather than guesses: an expired token is put to the proof by attempting the refresh, so the state shown is real. Diagnostic depth (issuer, client, scope, claims) lives behind --json. Token values never appear.

Organizations

The engine's own organizations (see Organizations) — not the identity provider's. All platform-admin only.

dl org list [--status deleted|purging|all] [--json]
dl org view [<org>] [--json]
dl org create --name <name> [--application <id>]
dl org bind [<org>] --ref <external-ref>
dl org credit [<org>] --micro-usd <amount> [--idempotency-key <key>]
dl org use [<org>]
dl org delete <org> [--yes]
dl org restore <org>
dl org delete <org> --purge --confirm <name>
dl org purge <org> [--yes]
dl org purge-status <org> [--json]

dl org use sets a sticky default organization (the kubectl use-context pattern): read and bind/credit commands accept their org positionally or fall back to it. Destructive commands never fall back — a delete or purge always names its target explicitly.

Applications

Products built on the engine (see Applications); each owns a realm at the identity provider.

dl app list [--status deleted|purging|all] [--json]
dl app create --realm <realm> --name <name>
dl app delete <app> [--yes]
dl app restore <app>
dl app delete <app> --purge --confirm <realm>
dl app purge <app> [--yes]
dl app purge-status <app> [--json]

Pricing, usage, readiness

dl pricing list [--json]
dl pricing set <model> --provider <p> --input <micro-usd/MTok> --output <micro-usd/MTok>
               [--margin <pct>] [--tier economy|standard|frontier]
               [--cache-read <20ths>] [--cache-write-5m <20ths>] [--cache-write-1h <20ths>]
dl pricing delete <model>
dl usage [--org <org>] [--json]
dl readiness [--json]

pricing set is a full-row upsert (see Models and pricing): omitting a cache multiplier clears any stored override, and --input/--output are required so a forgotten flag can never write a silent zero rate. usage shows every organization's balance; with --org, month-to-date spend by model. readiness is the platform's capability health, component by component.

The deletion lifecycle

Deleting is two explicit steps, never one accident (ADR-0078). Both ship today.

  1. delete is reversible. Access ends immediately; every byte is retained indefinitely; restore undoes it. The CLI asks before acting (--yes skips the prompt). Nothing is erased, at any point, by this step.
  2. purge is irreversible. It erases an already-deleted organization's data — or an application's, including its realm — through a fenced, checkpointed background workflow: purge-status reports the per-store checkpoint set (which store, if any, is stuck) and repeating purge re-drives a stalled run from the first incomplete step rather than starting over. Both commands resolve the row first, so they work for exactly as long as it exists — see the warning below for what that means for an application. The one-step immediate mode, delete --purge, demands --confirm <exact name> for an organization or --confirm <exact realm> for an application — the CLI never infers it, because that confirmation is the one step a script cannot perform by accident.

Purge is irreversible. It erases PostgreSQL rows, blobs, chunk and memory vector tenants, memory graphs, provider grants, and the identity provider's objects for the target — there is no restore once it completes. The engine only reports *.purge.completed once every required store confirms erasure; a store that failed, was skipped, or was never configured leaves the target purging with *.purge.failed naming the stuck store instead. For an organization, purge-status (or purge, to re-drive) is how you find out which one: PostgreSQL is the last step, so the row is still there to ask about.

For an application it is not. The application row is deleted in step 1 and the realm in step 2, and both commands resolve the row before anything else — so once step 1 lands, purge-status and purge answer 404, the same as an id that never existed. If the realm deletion then fails, the engine writes application.purge.failed naming identity_realm, retries up to five times (≈6 minutes), and gives up; no command can finish the job from there and the remedy is deleting the realm by hand at the identity provider. The audit event is the only signal.

An organization purge erases the organization's identity objects — its service accounts and, if one was provisioned, its first administrator — never the application-tier account of whoever signed up through it; that account is only erased when the application itself is purged, dropping the whole realm.

The engine enforces the ordering. Deleting an application that still contains organizations answers organizations_remain with the count (a deleted-but-unpurged organization still counts), and the platform's default application refuses deletion outright with default_application. Purging an active (not yet deleted) organization or application answers not_deleted; restoring one mid-purge answers already_purging; and financial history (ledger_entries, and the audit trail) survives a purge while balances and content do not.

Output conventions

Every list/view command takes --json for scripting — typed, indented, and piped output never carries ANSI codes (color follows the terminal and NO_COLOR). Mutating commands print one line saying what changed. Money is integer micro-USD on the wire and dollars in tables.

What the token can do

The token carries your identity, not a machine's — engine-side audit, metering, and per-user limits attribute every call to you. It is the same operator lane the admin console uses: a role granted in the console's own identity-provider project, not a tenant credential, and not available to a tenant no matter what role they assert inside their own project.

Admin commands require platform-admin. A token that authenticates but lacks the role gets a message saying so, rather than being sent back to auth login. Org-scoped calls ride the X-Deeplinq-Admin-Org header, which the engine accepts only from a platform admin — and which rewrites the request's principal to that organization's org-admin, dropping platform-admin for that request.

Session storage

The session — including the refresh token — is written to your user configuration directory (~/.config/deeplinq/session.json on Linux, ~/Library/Application Support/deeplinq/session.json on macOS) with mode 0600. No token is ever printed. offline_access is always requested, so an expired access token refreshes on the next command without a new login.

dl auth logout removes the local session file only — it does not revoke anything at the identity provider. The refresh token stays valid there until it expires or is revoked centrally. The sticky organization set by dl org use survives logout; it is working context, not a credential.

See authentication for the tenant lanes this CLI does not use, and per-command detail in the deeplinq-cli README.

On this page