Getting started with the CLI
This page covers the tool itself: how to install it, where it keeps your credentials, how you sign in, and how to read what it prints. For a first installation through to a deployed application, see Get Flui running.
Install
The CLI is published on npm as @flui-cloud/cli and needs Node.js 18
or later. The command it installs is flui.
npm install -g @flui-cloud/cli # or pnpm add -g, yarn global addflui --versionflui update replaces the global install with the latest published
version. It asks npm for the latest version, tells you what it found,
and asks before installing anything.
Two version numbers matter. flui --version is the CLI’s own
version. flui version also prints the platform release this CLI
pins: the component versions a new installation would be built from.
When an install behaves strangely, check the second number first.
flui --help lists the topics. There are more than two hundred
commands, grouped into topics such as app, env, iam, scaling
and backup, and every one answers --help with its own flags and
examples. The topic map is the quickest way in.
The vault comes first
The CLI stores sensitive data: provider tokens, and the API key that acts as your account. They are encrypted, and a key kept in the same directory as the data it protects would offer no real protection. So the key is derived from a passphrase you know and the machine does not keep. That is the vault, and you set it up before you store any credential.
flui vault init # once per machineflui vault unlock # once per sessionflui vault status # open? and for how long?flui vault lock # close it nowflui vault init asks for a passphrase and suggests a five-word one
you can accept with Enter. The passphrase is not stored anywhere and
cannot be reset, so it has to be one you can write down and
reproduce. Losing it means losing every credential this machine has
sealed. For the same reason, init refuses to overwrite a vault that
already exists.
There is one vault per machine, with its header at
~/.flui/vault.json, but not one key. Each profile gets its own key,
derived from your passphrase and the profile’s name. A command
working in one profile cannot open another profile’s stored
credentials, even though both were sealed under the same passphrase.
After unlock, a small background helper holds the key for the
session and hands it to commands that ask for it. Nothing is written
to disk. The helper closes after thirty minutes of inactivity, and
after eight hours regardless of activity.
A locked vault is not an error in itself. Most commands only read a
preference or an API address, which are plain text, and never ask
for the key. Only a command that opens a stored credential stops. It
says the vault is closed and names flui vault unlock, instead of
reporting a decryption failure that would send you looking for
corrupt data.
If you are upgrading from a CLI that predates the vault, nothing is
lost. A profile still holding the old key file is read as before, and
the first flui vault unlock seals it again under the vault and
removes the old file.
For scripted setup, flui vault init and flui config set both take
--stdin and read the value from standard input:
printf 'my passphrase' | flui vault init --stdinprintf '%s' "$TOKEN" | flui config set hetzner --stdinA value passed as a command argument is visible to every process on the machine through the process list, which is not acceptable for a credential on a shared host.
Signing in
Flui authenticates against the identity provider that runs inside
your own installation. There is no Flui account anywhere else, so
flui auth login works only once there is an installation to sign in
to and the active profile knows its address.
flui auth login # opens a browserflui auth login --headless # prints the URL insteadflui auth login --key-name my-laptopThe CLI opens your browser, runs a standard code-with-PKCE sign-in against that identity provider, and uses the result to mint a long-lived API key, which it saves in the active profile. Every later command uses that key without asking again. The CLI never sees a password.
By default the sign-in shows the account picker, so you confirm which
user you are minting a key for. --prompt login forces a fresh
authentication; --prompt '' reuses the browser session silently.
The key login mints is unscoped. It carries your full permissions,
because that is what signing in means. You mint narrower keys
separately, as the next section describes.
When the browser is somewhere else
The CLI waits for the redirect on http://localhost:8899, falling
back through 8900, 8901, 8902 and 8910, and gives up after two
minutes. It listens on the loopback address only.
On a machine with no browser, --headless prints the URL so you can
open it elsewhere. The redirect still has to reach the listener on
the machine running the CLI, so forward the port from wherever the
browser is:
ssh -L 8899:localhost:8899 your-serverA key has to say what it is for
flui auth generate-api-key mints a key without a browser, for CI, a
script or an agent. You must say which kind of key you want, so the
widest credential the installation can issue is never what you get by
leaving a flag out:
flui auth generate-api-key --name ci --unscopedflui auth generate-api-key --name agent \ --scope mcp:app:read --scope mcp:obs:readIf you pass neither --scope nor --unscoped, the command stops
before anything else happens (before it needs a token, a profile or a
network) with a message naming the two choices. --unscoped gives
the key your full permissions. --scope sets a ceiling; repeat the
flag for more than one scope.
A scope you do not hold yourself is refused outright, never trimmed down to what you are allowed, because a key that comes back smaller than you asked for is hard to reason about later.
The command needs a session token from the identity provider, passed
as --token <jwt> or in FLUI_SESSION_TOKEN. --expires <days>
sets an expiry; leave it out for a key that does not expire.
There is no --groups flag. The readable permission groups, such as
“deploy and operate applications” and “operate the infrastructure”,
exist in the dashboard and the API. From the terminal you name raw
scopes. If you are minting a key for an agent,
Choose what your agent may do
explains what each group covers and where to mint it.
A key is stored as a digest, and nothing on the installation can hand
it back. The command does not print it either: it saves it into the
active profile (or the one named with --profile), replacing that
profile’s key, and the CLI uses it from there. Later you can list the
keys that exist and revoke one:
flui auth api-keys # name, state, scopesflui auth api-keys -o jsonflui auth revoke-api-key <id> # stops working immediatelyThe context banner
One workstation can drive several installations, and the worst mistake that allows is a command that works perfectly on the wrong one.
So the commands that act on an installation as a whole print a line before their output, naming where they are about to act:
┌─ context production · api https://api.example.com/api/v1context is the active profile. api is the installation that
profile points at, or a yellow (not set), which is normal for a
profile you have just created and not yet pointed at anything. Some
commands add the target cluster’s provider and region on the same
line.
Not every command prints it. The banner appears on the families whose
reach is the installation itself: env, backup, migrate, dns,
catalog and a few more. Elsewhere, flui context show names the
active profile.
Profiles on disk
A profile is one installation as this machine sees it: its API
address, its credentials, and its local view of what that
installation holds. Everything the CLI keeps lives under ~/.flui:
~/.flui/├── context # the name of the active profile├── vault.json # the vault header, one per machine└── profiles/ ├── default/ └── production/Each profile directory holds:
config.json: your preferences in plain text, plus the sealed values (the provider credentials you stored and the API keyauth loginsaved).ca/: the trust material this profile uses to reach cluster nodes.clusters.json,nodes.json,firewalls.json,vnets.json,operations.json: a local copy of what the installation last told the CLI. You can delete these; the next command that needs them fetches them again.
The directories and files are created readable by their owner only.
Switching profiles is local and instant. Nothing in any cluster notices; the CLI reads a different directory from then on.
flui context list # every profile, active marked *flui context show # just the active nameflui context create staging --switch # create it and switchflui context use default # switch backflui context delete staging # warns only; -f deletesdefault is created on first run and cannot be deleted, and neither
can the active profile. Names accept letters, digits, hyphens and
underscores. FLUI_PROFILE overrides the active profile for one
command without switching.
Nothing operational crosses between profiles. A provider token saved in one is not visible from another, and the keys that seal them are different. A command typed in the wrong profile cannot reach another installation, because it does not hold the credentials.
If you only run one installation from this machine, the auto-created
default profile is enough and you can skip this section.
Where to go next
- Get Flui running: the first installation, step by step, including the case where you are taking over one somebody else provisioned.
- Deploy an application: including the one-off GitHub and registry connections the first source-built deploy needs.
- Multi-context: why one workstation driving several installations is a different problem from one installation driving several clusters.
- Profiles and config: the layered configuration, provider credentials, and the full profile reference.
- Authentication: the login flags and the environment variables that override the active key.
- Connect an agent: what to do with a scoped key once you have minted one.