Skip to main content

CLI

The miabi CLI is the imperative command-line client for Miabi. Almost all of it is a pure consumer of the public HTTP API — the same API the web console uses — so anything you can do in the console you can script from a terminal or a CI pipeline. Its headline job is the deploy flow:

miabi apps deploy web --tag "$GIT_SHA" --wait

This deploys the app at the given image tag, blocks until the deployment reaches a terminal state, and exits non-zero if it failed — exactly what you want in CI.

note

The CLI is a standalone tool released on its own cadence, separate from the Miabi server. Source, releases, and the authoritative command reference live on GitHub: github.com/miabi-io/cli.

Install​

Homebrew (macOS and Linux):

brew install miabi-io/tap/miabi
note

Homebrew 6 requires third-party taps to be trusted. The one-liner above handles it; if you tap first, run brew trust miabi-io/tap before brew install miabi.

Go:

go install github.com/miabi-io/cli@latest
mv "$(go env GOPATH)/bin/cli" "$(go env GOPATH)/bin/miabi" # Go names the binary after the module: `cli`

Or grab a prebuilt binary for Linux, macOS, or Windows from the releases page.

Docker — no install at all, which is handy in CI:

docker run --rm -e MIABI_SERVER -e MIABI_TOKEN miabi/cli:latest whoami

# deploy from a pipeline — exits non-zero if the rollout fails
docker run --rm -e MIABI_SERVER -e MIABI_TOKEN \
miabi/cli:latest apps deploy web --tag "$GIT_SHA" --wait

Authenticate​

The CLI talks to your instance with an API token. Provide the URL and token by environment variable — ideal for CI:

export MIABI_SERVER="https://miabi.example.com"
export MIABI_TOKEN="mb_…" # created in the console: Settings → API tokens
miabi whoami # verify: shows the identity, scopes, and active workspace/app

Or log in once for interactive use. miabi login stores the URL + token in ~/.miabi/config.yaml (mode 0600):

miabi login --server https://miabi.example.com   # opens the browser to sign in (password or SSO)
miabi login --no-browser # no local callback: paste a token from /request-token
miabi --token "$MIABI_TOKEN" login # non-interactive: validate and save this token

By default login opens the console's /cli/authorize page and captures the token through a one-time code sent to a local callback — nothing to copy and paste. When a token is already set with --token or MIABI_TOKEN, it validates and saves that instead; --web forces the browser flow anyway. Without --server, login re-authenticates the current context's server.

Narrowing what the token may do​

--scopes limits the token to read, write, deploy, or any combination — the default grants all three. The scope rides through the sign-in, including an SSO one, so the browser hands back a token that is already narrowed:

miabi login --context prod-ro --scopes read       # a context you can only read from
miabi login --scopes deploy # ship, but not edit

A login token can never carry admin or *; the server refuses to mint one, and the CLI rejects those names before opening the browser. If the server is older than --scopes it ignores the request — the CLI checks what it was actually given and refuses to save a token broader than you asked for, rather than leaving you with a false assurance.

A read-only context is what makes miabi mcp read-only in fact and not only in the tools it advertises.

Configuration resolves in the order flags → environment (MIABI_SERVER, MIABI_TOKEN) → config file. Point at a different file with MIABI_CONFIG. --url and MIABI_URL are the deprecated spellings of --server / MIABI_SERVER; both still work.

tip

For CI, mint a least-privilege deploy token bound to one workspace and one app (scope deploy). It can deploy that app and nothing else. Use broader read/write tokens for interactive work. See API tokens.

Multiple servers​

Each login is saved as a named context — server URL, TLS trust, token, and the bound workspace/app — named after the server's hostname unless you pass --context <name>.

miabi context ls                     # all contexts; the arrow marks the current one  (alias: ctx)
miabi context current # print the current context's name
miabi context use staging # switch
miabi context delete staging # remove (alias: rm)
miabi --context prod apps ls # target one context for a single command

MIABI_CONTEXT does the same as --context. For a server with a private CA, pass --certificate-authority <bundle> (or MIABI_CA); login saves the bundle path with the context.

Context: workspace and app​

Most commands act on an app in a workspace. Rather than repeating those every time, set them once as part of the current context in ~/.miabi/config.yaml:

miabi workspace list                 # name, display name, role  (alias: ws)
miabi workspace switch acme # set the active workspace
miabi workspace show # the currently active workspace

miabi use web # bind a default app for app-scoped commands
miabi use # show the current binding
miabi use --clear # unbind

With an app bound, app commands need no argument (miabi apps deploy targets the bound app). The binding is per workspace and is cleared when you switch workspaces. You can always override per-command with a positional app argument or --workspace/-w. A workspace-bound token already targets its workspace, so it needs no workspace switch.

Commands​

App-scoped commands live under apps (alias of app) and take the app as their first argument, or use the app bound with miabi use.

CommandWhat it does
miabi login [--no-browser | --web] [--scopes read,write,deploy] · miabi whoamiSign in and save a context; show identity, scopes, and active context.
miabi context ls | current | use | deleteList, show, switch, or remove saved contexts (alias: ctx).
miabi workspace ls | show | switch <name-or-id>List, show, or set the active workspace (alias: ws).
miabi use [app] | --clearBind (or show/clear) the default app.
miabi apps lsList the workspace's applications (marks the bound app).
miabi apps create <name> (--image <img> [--tag] | --git-repo <url> [--git-ref] [--build-method]) [--port] [--node <id>] [--use]Create an app from an image or Git source. --build-method is auto, dockerfile, or buildpack.
miabi apps deploy [app] [--tag <tag>] [--strategy <s>] [--no-cache] [--wait] [--timeout 10m]Deploy; --wait blocks and exits non-zero on failure. --no-cache rebuilds every layer (Git-source apps).
miabi apps start | stop | restart [app]Control the app's container.
miabi apps rollback [app] (--to <version> | --to-previous) [--yes]Roll back to a previous release.
miabi apps status [app] [--deployment <n>]Show app / deployment status.
miabi apps logs [app] [--follow] [--tail N] [--deployment <n>]Runtime logs (or a deployment's build logs with --deployment); --follow streams.
miabi apps deployments [app]Deploy history — the NUMBER column addresses a deployment.
miabi apps releases [app]List an app's releases (by VERSION).
miabi apps env ls [app]List the app's env vars (secret values are masked).
miabi apps env set [app] KEY=VALUE [--secret]Set an environment variable.
miabi apps env set [app] KEY --from-file <f> [--secret]Set the value from a file (or - for stdin) — keeps it out of your shell history.
miabi apps env import [app] --from-file .env [--secret]Bulk-import variables from a file (- = stdin).
miabi apps set-source [app] (--image <img> [--tag] [--registry-id <id>] | --git-repo <url> | --git-repository-id <id>) [--git-ref] [--build-method] [--builder] [--yes]Switch the app between a prebuilt image and a Git build, or edit its current source. Keeps domains, env, volumes and history. --git-repository-id uses a saved repository and its credentials; --yes skips the prompt when switching source type.
miabi apps resync-pipeline [app]Reload the repository's pipelines.yaml — adopts one if the app has none, re-syncs it if it does.
miabi apps invalidate-cache [app]Start a new build-cache generation, so the next build rebuilds every layer.
miabi apps rm [app] [--yes]Delete an application.
miabi pipeline lsList the workspace's pipelines.
miabi pipeline run <pipeline> [--branch <ref>] [--commit <sha>] [--no-cache]Start a run (pipeline by name, UID, or id).
miabi pipeline rerun <run-id> [--no-cache]Run the same pipeline again at the ref and commit that run built.
miabi volumes …Manage volumes, their files, and their backups (see below).
miabi db …Manage database instances + logical databases (see below).
miabi secrets …Manage the workspace secret vault (see below).
miabi configs …Manage the workspace's configuration files (see below).
miabi apply -f <file|dir> [--prune] [--dry-run]Converge to declarative manifests. A directory reads every .yaml and .yml file under it, the same files a Git source pointed at it reads.
miabi delete -f <file> [--dry-run]Delete exactly the resources a manifest bundle names.
miabi completion <shell>Shell completion (tab-completes app slugs).

Databases​

Managed instances (PostgreSQL, MySQL, MariaDB, Redis, MongoDB, libSQL) and the logical databases on them. Instances are addressed by slug (or numeric id).

miabi db ls                                   # list instances
miabi db engines # engines + default versions
miabi db create shop --engine postgres [--version 16] [--size-mb 2048] [--node <id>]
miabi db get shop
miabi db start | stop | restart shop
miabi db logs shop [--follow] [--tail 200]
miabi db credentials shop # reveal admin connection (admin)
miabi db upgrade shop --to 17 [--stop-apps]
miabi db rm shop [--yes]
# logical databases on an instance:
miabi db databases shop # list
miabi db databases create shop app_prod [--app web] # optionally attach to an app
miabi db databases connection shop app_prod # reveal connection (admin)
miabi db databases rm shop app_prod [--yes]
# link to an app (injects DB_URL, DB_HOST, … ; Redis injects REDIS_*):
miabi db link shop app_prod --app web [--prefix ANALYTICS]
miabi db link shop app_prod --app web --env url=SPRING_DATASOURCE_URL --env database_url=
miabi db link cache --app web # Redis: link the whole instance
miabi db links --app web # what is linked, and the vars it injects
miabi db unlink shop app_prod --app web

Volumes​

Persistent volumes, addressed by name (alias: vol).

miabi volumes ls
miabi volumes get web-data # details and the apps mounting it
miabi volumes create web-data [--size-mb 5120] [--node <id>]
miabi volumes create shared --driver nfs --driver-opt device=:/export --driver-opt o=addr=10.0.0.5,rw
miabi volumes attach web-data --path /var/lib/data [--app web]
miabi volumes detach web-data [--app web] # unmount; the data is kept
miabi volumes storage # workspace usage: declared vs measured
miabi volumes rm web-data [--yes] # refused while an app mounts it

--driver is local (the default: node-local, one node mounts it), nfs or cifs (shared storage every replica can mount), or host (an operator-managed path, privileged workspaces only). Driver options are write-only; pass anything holding a password with --driver-opt-file key=path (- reads stdin) to keep it out of your shell history.

Files inside a volume — one side of cp is <volume>:<path>, and - is stdin/stdout:

miabi volumes ls-files web-data [--path uploads]
miabi volumes cp ./nginx.conf web-data:/conf/nginx.conf # upload (overwrites)
miabi volumes cp web-data:/dump.sql - | gzip > dump.sql.gz # download; --force overwrites a local file
miabi volumes rm-file web-data uploads [--yes] # a directory is removed recursively

The panel rejects uploads over 512 MiB, and listings stop at 5000 entries.

Backups go to the workspace's S3 backup target; without one every backup command is refused. Backups are addressed by the numeric ID the listing shows.

miabi volumes backups web-data                        # list
miabi volumes backups run web-data [--wait] [--timeout 30m]
miabi volumes backups restore web-data 42 [--yes] # overwrites the volume's data
miabi volumes backups logs web-data 42
miabi volumes backups rm web-data 42 [--yes]

restore does not stop the apps mounting the volume — stop them first unless the workload tolerates its files changing underneath it.

Secrets​

The workspace secret vault: values encrypted at rest, write-only over the API, referenced from an app's env as ${{ secrets.NAME }}. Addressed by name. Supply a value with --from-file (or stdin) rather than --value, which lands in your shell history.

miabi secrets ls                              # list (no values)
miabi secrets get API_KEY # description, version, timestamps
miabi secrets set API_KEY --from-file api.key # create, or rotate if it exists
miabi secrets set API_KEY --description "Stripe live key" # update only the description
cat api.key | miabi secrets set API_KEY --from-file -
miabi secrets reveal API_KEY # print the value (admin; audited)
miabi secrets usage API_KEY # apps referencing it
miabi secrets rm API_KEY [--yes]

seal encrypts a value locally to the workspace's public key and prints a kind: SealedSecret manifest you can commit. See Sealed secrets.

echo -n "$API_KEY" | miabi secrets seal API_KEY >> secrets.yaml
miabi secrets seal API_KEY --from-file api.key --raw # only the sealed value
miabi secrets seal-key > .miabi/sealing.pub # the public key, safe to commit
miabi secrets seal API_KEY --from-file api.key --public-key-file .miabi/sealing.pub # offline
miabi secrets seal -f secrets.yaml --in-place # turn every plaintext Secret into a SealedSecret

Configs​

The workspace's configuration files — file sets mounted into applications read-only, encrypted at rest. Addressed by name; files come from disk with --from-file ([key=]path, repeatable) or --from-dir. --mode sets the default octal file mode (e.g. 0644), --delimiters "<<,>>" changes the interpolation delimiters for files whose own syntax uses {{ }}, and --description labels the config.

miabi configs ls                                    # names, file counts, size, version
miabi configs get prom-conf # files and digest (no content)
miabi configs set prom-conf --from-file prometheus.yml # create, or replace the file set
miabi configs set prom-conf --from-file rules/alerts.yml --merge # patch one file, keep the rest
miabi configs set nginx --from-dir ./conf.d --recursive
miabi configs set app --from-file app.conf=- < app.conf
miabi configs cat prom-conf prometheus.yml # print one file
miabi configs edit prom-conf prometheus.yml # edit in $EDITOR
miabi configs usage prom-conf # apps mounting it
miabi configs rm prom-conf [--yes]

set replaces the whole file set unless you pass --merge, so it stays idempotent in CI. Saving redeploys every app mounting the config (unless it sets reloadPolicy: none) — --yes skips the confirmation. Reading content (cat, edit, and --merge) is admin-only and audited; a config marked --sensitive additionally requires --reveal to print.

Mounting a config into an app is declarative — see the manifest reference.

AI agents​

miabi mcp runs a Model Context Protocol server, so an AI agent (Claude Desktop, Claude Code, Cursor, …) can inspect and operate your panel. Each tool call becomes one authenticated API request, so the agent inherits your token, workspace, and RBAC — no model runs inside miabi.

claude mcp add miabi -- miabi mcp                 # read-only
claude mcp add miabi -- miabi mcp --allow-write # also deploy, restart, roll back

See AI Agents (MCP) for the tool catalog, transports, and how to scope what an agent is allowed to do.

Common flags​

  • --wait — block on the deploy and exit non-zero when it ends failed (CI gating).
  • -o, --output table|json|yaml (or the --json shorthand) — machine-readable output for jq/yq-friendly scripting; human tables otherwise.
  • -w, --workspace <name-or-id> — override the active/bound workspace for one command.
  • --context <name> — use a saved context for one command (env MIABI_CONTEXT).
  • --certificate-authority <file> — trust a CA bundle for the server's certificate (env MIABI_CA).
  • --insecure-skip-tls-verify — skip certificate verification (env MIABI_INSECURE_SKIP_TLS_VERIFY). The CLI warns on every command that uses it; prefer --certificate-authority.
  • --no-color — plain output (also auto-disabled off a TTY or when NO_COLOR or MIABI_NO_COLOR is set).
  • --verbose — log every HTTP request to stderr.
  • --version — print the CLI version.

Managing the host​

One group of commands is the exception to "pure API client": setup, upgrade and stack … act on the machine they run on, through its Docker socket, and never touch the HTTP API. They are what installs and operates a Miabi host — see Installation and Upgrades.

CommandWhat it does
miabi setup [-d, --domain <host>] [--version <x.y.z>] [--image <ref>] [--yes]Install the stack on this host, or converge an existing install. Idempotent. A fresh install defaults to the latest published release.
miabi upgrade [component] [--version <x.y.z>] [--image <ref>] [--yes]Roll the stack forward, rolling back automatically if the new image never becomes healthy. --version swaps only the tag (keeping a private registry); --image replaces the whole reference. Also available as miabi stack upgrade.
miabi stack statusWhat is running, its health, and any drift from the manifest.
miabi stack apply [--yes]Bring the running stack in line with the manifest: lists the components whose spec changed, then recreates only those. Nothing changed means nothing restarts.
miabi stack restart [component] [--yes]Restart in place so containers re-read their on-disk config. A restart does not apply manifest changes — use stack apply.
miabi stack uninstall [--volumes] [--yes]Remove the stack's containers; --volumes also destroys the database.
miabi stack migrate-configRename the legacy /etc/miabi/stack.yaml to /etc/miabi/miabi.yaml.
miabi stack env ls / get KEYShow the environment the manifest carries. --gateway reads the gateway's instead of the control plane's.
miabi stack env set KEY=VALUE […] [--apply]Write variables to the manifest and show what changes. The running stack keeps the old values until miabi stack apply; --apply does both in one step.
miabi stack env unset KEY […] [--apply]Remove variables. A variable Miabi seeds (TZ, MIABI_LOG_LEVEL) comes back at its default rather than disappearing, and the output says so.

Edits are saved, not applied, so several of them cost one recreate per component:

sudo miabi stack env set MIABI_SMTP_HOST=smtp.example.com MIABI_SMTP_PORT=587
sudo miabi stack env set GOMA_LOG_LEVEL=debug --gateway
sudo miabi stack apply

stack env is also reachable as miabi setup env … — the same command under the verb an operator reaches for when configuring an install. Settings the manifest models with their own field (the registry, the networks, the backup destination) are refused there, and the error names where the value actually lives.

They all need root (they write /etc/miabi and use the Docker socket) and a Linux or macOS Docker host. -f, --file points at a manifest other than /etc/miabi/miabi.yaml; so do MIABI_CONFIG_FILE and the older MIABI_STACK_FILE.

setup also takes --admin-email, --acme-email, --control-url, --registry, --registry-host, --subnet, --internal-subnet, --gateway-image, --runner-image, --goma-config, and --no-host-proc. Each one overwrites the matching manifest field when given and leaves it alone otherwise — see Install options.

A fresh setup, and upgrade with no component, install the latest published Miabi release, resolved from versions.miabi.io when the command runs (GitHub is the fallback) — the CLI does not carry a platform version, because it releases on its own cadence. Re-running setup on an existing install keeps the image its manifest pins. MIABI_RELEASE_API points that lookup at a mirror for a host with no route out, and --version/--image skip it entirely.

On upgrade, --version accepts 1.8.0 or v1.8.0 and swaps only the tag on the component's current reference, so a private registry and non-Miabi components (the gateway) keep working; --image replaces the reference outright. On setup, --version sets the control-plane image to miabi/miabi:<version>, replacing a private-registry reference — pass --image there, or use upgrade. Pinning matters: a floating tag such as latest warns, because a failed rollout has no distinct previous image to roll back to. See Upgrades.

In CI/CD​

The CLI is the recommended way to deploy from a pipeline. Set MIABI_SERVER and a deploy token as MIABI_TOKEN, then call apps deploy --wait:

- name: Deploy to Miabi
run: |
docker run --rm -e MIABI_SERVER -e MIABI_TOKEN \
miabi/cli:latest apps deploy web --tag "${{ github.sha }}" --wait
env:
MIABI_SERVER: ${{ vars.MIABI_SERVER }}
MIABI_TOKEN: ${{ secrets.MIABI_DEPLOY_TOKEN }}

Because --wait exits non-zero on a failed rollout, a broken deploy fails the pipeline step. (A prebuilt release binary works the same way if the runner has no Docker.)

On GitHub Actions you do not need any of that — miabi-io/deploy-action installs the CLI and runs the same command:

- uses: miabi-io/deploy-action@v1
with:
app: web
tag: ${{ github.sha }}
server: ${{ vars.MIABI_SERVER }}
token: ${{ secrets.MIABI_TOKEN }}

If you'd rather not install anything, the same deploy is one HTTP call. The {workspace} segment is a real workspace — its numeric id, its UID, or its handle. There is no current alias on the API (the CLI resolves that client-side):

curl -fsS -X POST "$MIABI_SERVER/api/v1/workspaces/acme/apps/web/deploy" \
-H "Authorization: Bearer $MIABI_TOKEN" \
-d '{"tag":"'"$GIT_SHA"'"}'

The request body accepts registry_id, tag, strategy, and no_cache (rebuild every layer, for Git-source apps). There is no wait field and no Idempotency-Key header — the server does not de-duplicate retried deploys. Poll the deployment's status to gate a pipeline on the rollout.

  • AI agents (MCP) — expose the panel to Claude, Cursor, or any MCP client via miabi mcp.
  • API tokens — create the token the CLI authenticates with.
  • GitOps — the declarative counterpart driven by miabi apply / miabi delete.
  • GitHub Actions — the official action that wraps miabi apps deploy.
  • Volumes — the storage managed by miabi volumes.
  • Secrets — the vault managed by miabi secrets.
  • Configuration files — the file sets managed by miabi configs.
  • Pipelines and Deploy on push — in-platform build/deploy automation.