CLI
Readyydfi operates a deployment end to end — standing it up, running its PKI, managing its secrets, downloading and installing its license, issuing enrollment invites, and administering a running server. It is one binary, twelve command groups, around fifty commands, and it is the only interface you need: there is no console you are expected to click through instead.
Who this is for: whoever runs the deployment. If you are integrating an application rather than operating a server, you want the API reference and an SDK — the CLI is not on that path. New here? Quickstart uses about six of these commands and explains them in order.
Getting the CLI#
The CLI ships as a container image, so there is nothing to install and nothing to keep up to date by hand. Alias it once and every command below runs inside it:
# the alias mounts your working directory, the Docker socket the CLI drives, and # ~/.config/ydentifi, where the API key from `ydfi register` is kept $ mkdir -p ~/.config/ydentifi && chmod 700 ~/.config/ydentifi $ alias ydfi='docker run --rm -it -v "$PWD":/work \ -v "$HOME/.config/ydentifi":/config/ydentifi -e XDG_CONFIG_HOME=/config \ -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/ydentifi/ydfi' $ ydfi --version
Three flags work everywhere. --help on any command or group prints its own tree and flags —
that output is generated from the same definitions as this page, so it is never out of date.
--version prints the build, which is stamped in at release time.
--no-color strips ANSI codes, as does setting NO_COLOR in the environment,
which is what you want in CI logs.
The twelve groups#
Every command is ydfi <group> <command>. The groups split by what you are operating
on, not by how often you touch them — so the ones you use once at install sit beside the ones you use weekly.
Every command#
ydfi bootstrap
The shortest path from nothing to a deployment that can start. Writes the PKI, generates every secret, and emits a .env wired to both.
| Command | What it does |
|---|---|
| ydfi bootstrap | Initialise a fresh deployment: PKI + secrets + .env |
ydfi deploy
Recipes, not a framework. local is a real Docker Compose deployment on your machine — the same server image production runs, with the same mutual-TLS handshake.
| Command | What it does |
|---|---|
| ydfi deploy local preflight | Check the host has everything needed to run the local stack |
| ydfi deploy local bootstrap | Mint per-install PKI + secrets for the local deployment |
| ydfi deploy local image | Build the local deployment image |
| ydfi deploy local up | Start the compose stack — postgres, seeder, server |
| ydfi deploy local down | Stop the compose stack |
ydfi pki
Readings of a certificate. It issues nothing: ydfi bootstrap makes a new deployment’s certificates, and your own CA issues under that root after.
| Command | What it does |
|---|---|
| ydfi pki pin-hash <cert.pem> | Compute the SPKI pin (base64url SHA-256) of a PEM cert — what a setup code carries |
| ydfi pki fingerprint <cert.pem> | Compute a cert’s fingerprint (hex SHA-256 of the DER) — the value the operator revocation list takes, not a pin |
ydfi secret
The deployment’s own key material. To encrypt new data under a new key, append the generated pair to YDFI_PRIMARY_ENCRYPTION_KEY and restart; the older pairs stay and decrypt what they wrote. With more than one server instance, add it first in the list, where it only decrypts, restart every instance, then move it to the end and restart again.
| Command | What it does |
|---|---|
| ydfi secret generate-encryption-key | Generate a new AES-256 primary encryption key |
Licensing account
register exchanges a code sent to your address for an API key, kept on this machine. pull downloads the license the account is entitled to. See Get a license.
| Command | What it does |
|---|---|
| ydfi register | Create a licensing account |
| ydfi pull | Download the license this account is entitled to |
| ydfi rotate | Replace the API key |
ydfi license
Inspecting and installing the license. ydfi pull downloads one; apply installs it at the path the server reads.
| Command | What it does |
|---|---|
| ydfi license describe | Show a license’s holder, seats and expiry |
| ydfi license apply | Install a license at the path the server reads |
| ydfi license status | Show live license usage from the running server |
| ydfi license countries | List the countries a license can be issued to (--plain for one code per line) |
ydfi deployment
A license file, checked locally; each command takes --license-file. preview-license is the one to know: it answers what would this license do given the users and seats I already have before you install it.
| Command | What it does |
|---|---|
| ydfi deployment preview-license | Show what a new license would do to current users and seats |
| ydfi deployment verify-license | Verify a license’s signature and expiry |
| ydfi deployment status | Show the state, expiry and limits of a license file |
ydfi admin
Everything against a running server, over mutual TLS. This is the largest group and the only one that writes to production data, so it is also the one with the strictest conventions — see below.
| Command | What it does |
|---|---|
| ydfi admin health | Deployment-wide health: DB pool, cert expiry, reapers |
| ydfi admin headroom | License capacity snapshot — cap, seats, users, headroom |
| ydfi admin footprint | Per-table row counts and storage footprint |
| ydfi admin create-rp | Provision a new relying party |
| ydfi admin get-rp <rp_id> | Full detail for one relying party: users, devices, seat use and certificate fingerprint |
| ydfi admin list-rps | List relying parties (paged) |
| ydfi admin update-rp | Update an existing relying party |
| ydfi admin delete-rp | Permanently delete a relying party destructive |
| ydfi admin provision-rp-cert | Sign a CSR and register the resulting cert for a relying party |
| ydfi admin list-users <rp_id> | List users belonging to one relying party (paged) |
| ydfi admin get-user <rp_id> <opaque_id> | Full detail for one user — account record, devices and rate-limit state |
| ydfi admin delete-user <rp_id> <opaque_id> | Operator-initiated account closure destructive |
| ydfi admin reset-quotas <rp_id> <opaque_id> | Clear one user’s rate-limit state |
| ydfi admin deactivate-device <device_id> | Operator-initiated device revocation destructive |
ydfi invite
One command, because enrollment only needs one. The token it prints is what a QR code carries.
| Command | What it does |
|---|---|
| ydfi invite mint | Mint one enrollment invite and print its token as hex |
ydfi seed
A demo relying party you can point a phone at without writing any integration code first. Useful for evaluation and for reproducing a report against something known.
| Command | What it does |
|---|---|
| ydfi seed demo | Create a demo RP and users, print enrollment QR codes |
| ydfi seed challenge | Issue a fresh challenge against a seeded RP and user |
| ydfi seed reset | Delete the demo RP and optionally remove its local cert files |
ydfi validate-env
Reads a .env and tells you what is wrong with it before anything tries to boot on it.
| Command | What it does |
|---|---|
| ydfi validate-env | Pre-flight check: validate a deployment .env file |
Conventions that repeat#
The same handful of flags recur across the whole tree, and they mean the same thing everywhere. Learn these five and most of the CLI stops needing its own documentation.
| Flag | Where and why |
|---|---|
| --config | Every admin command. Path to the admin config holding
the server URL and the client certificate, key and CA that authenticate you.
Defaults to ~/.config/ydfi-admin/config.yaml. Admin access is mutual TLS —
there is no password, no token, and no way to call these commands without a certificate the deployment trusts. |
| --reason | Required on every state-changing admin command, and
written verbatim into the audit event. It is not a comment field — it is the record of why a person did this,
so that a compliance review can reconstruct the action and its justification together. There is no way to skip it. |
| --confirm / --yes | Destructive commands stop and ask. --yes
skips the prompt for scripted use; --confirm is stronger and must be passed explicitly on the
operations that cannot be undone. Deleting data you did not mean to delete should take two decisions, not one. |
| --output | On read commands: table (default),
json, or yaml. Table for a human, JSON for a pipeline. The JSON is the
same data, not a summary of it. ydfi pull is the exception: its --output
names the file to save the license to, and - writes it to standard output. |
| --limit / --cursor | Listing commands are paged: page size 1–200, default 50, and a cursor to continue from. Nothing silently truncates. |
There is no operation the product supports that has no command — no step where the documented answer is to edit a table by hand or click something. That is deliberate: an operation you cannot script is an operation you cannot rehearse, audit, or run the same way twice at three in the morning.
Exit behavior
Success exits 0. Any failure exits 1 with the error on stderr and
nothing useful on stdout — so if ydfi ...; then and piping stdout to a parser both behave.
Errors carry the server’s typed reason where there is one; see Errors.