CLI reference, completion, and compatibility¶
ShinyHub's CLI is designed to remain discoverable after the first successful deploy and predictable when a workstation and remote server are upgraded at different times.
Every command¶
This is the complete top-level list, the same one shinyhub --help prints.
Each command carries its own --help with the flags and subcommands, and
shinyhub schema prints the whole tree as machine-readable JSON.
Set up a workstation or a CI job:
| Command | What it does |
|---|---|
connect |
Connect this CLI to a ShinyHub server, through the browser or with credentials |
ci |
Run a command with a short-lived deployment credential from trusted CI identity |
login |
Authenticate with a username, password or token you already hold |
logout |
Sign out of the current ShinyHub server |
hosts |
List saved ShinyHub servers and show which one is current |
use |
Switch the current ShinyHub server to a saved host |
whoami |
Show the current login: username, role, and server |
completion |
Generate or install shell completions |
schema |
Print a machine-readable description of this CLI (clispec v0.3) |
connect and login overlap, so: prefer connect. It does everything login
does, takes the same --username/--password and a token via --token-file,
and adds browser authorization, which is the only way in when a server's
sign-in is SSO. It is also safe to re-run, because a saved credential that
still authenticates is reused untouched. Reach for login when you already
hold a credential and want it saved without any of that.
Build and ship an application:
| Command | What it does |
|---|---|
dev |
Develop an app locally or on an explicit remote host |
run |
Run a Shiny app bundle locally in the foreground |
doctor |
Check whether an app and remote are ready to deploy |
manifest |
Work with the bundle manifest (shinyhub.toml) |
plan |
Preview one app deployment (read-only, no changes) |
apply |
Apply an exact saved plan |
deploy |
Deploy an application or API to ShinyHub |
drafts |
List, preview, promote, or delete retained deployment drafts |
fleet |
Declaratively reconcile a fleet of apps from a manifest |
Operate what is running:
| Command | What it does |
|---|---|
apps |
Manage apps |
projects |
Manage app projects (grouping) |
env |
Manage app environment variables |
data |
Manage an app's persistent data dir |
cache |
Clear an app's result cache |
share |
Manage shared-data mounts between apps |
schedule |
Manage scheduled jobs for an app |
top |
Live CPU, memory and session usage for every app |
Run and administer the server:
| Command | What it does |
|---|---|
init |
Set up ShinyHub for its first run |
serve |
Run the ShinyHub server |
validate-config |
Validate server configuration before restarting; see configuration preflight |
worker |
Run ShinyHub as a remote worker that joins a control plane |
healthcheck |
Exit successfully when a ShinyHub server is ready |
users |
Manage user accounts (admin) |
service-accounts |
Manage non-interactive deployment identities (admin) |
tokens |
Manage API tokens |
backup |
Write a consistent snapshot of all durable state to an archive |
restore |
Restore durable state from a backup archive (server must be stopped) |
migrate-backend |
Copy all data from the current SQLite database to a fresh Postgres database |
rotate-secret |
Re-encrypt all at-rest secrets under a new auth.secret |
resolve-legacy-schedule-writers |
Resolve the fail-closed fence left by schedule writers from an older server |
backup and restore are the pair to reach for before an upgrade or a host
move; see Configuration for what durable state they cover.
Go from deployment to the app¶
For an interactive deployment, use the complete success-to-use flow:
--open implies --start and --wait. ShinyHub waits for the deployed version
to become healthy, smoke-tests the actual /app/<slug>/ route when the app is
public, then opens the canonical URL in the default browser. Private and shared
apps enter the normal browser sign-in flow; the CLI credential is never sent to
an app route.
A missing browser or graphical session does not turn a healthy deployment into
a failure. The command prints a copyable URL and structured JSON reports
"opened": false. A failed public route check does exit non-zero, but states
clearly that the deployment itself succeeded and points to the app logs.
Open an existing app without redeploying it:
Redeploy without interrupting the current version¶
For a supported running native app, shinyhub deploy starts the complete new
replica pool beside the current pool, checks readiness, and only then sends new
visits to it. Existing HTTP streams and WebSockets remain attached to the old
version until they finish or the configured drain deadline expires. Tabs still
using the old version get a version-update indicator in the app switcher and
can move deliberately with Switch now.
Multiplex handoffs require memory for the entire replacement pool alongside the current one, plus the configured host memory floor. For 16 replicas, budget for 16 additional replicas; the one-replica surge used by scheduled data rolls is a separate operation. Grouped apps use the grouped worker handoff.
A handoff is deferred when memory cannot be proven, an older generation is still
draining or awaiting cleanup, the app uses a non-native provider or clustered
control plane, worker isolation does not match multiplex or grouped across
both versions, or shared producer state requires a deploy-time write. A bundle
with shinyhub.toml can hand off when its parsed manifest matches the previous
bundle, it declares no hooks, and its reconciled app settings already match the
live app. Changed manifest declarations require stop-first. The working version
remains available on refusal and the CLI returns a conflict with the reason.
If interruption is acceptable, opt in explicitly:
shinyhub deploy . --allow-downtime
shinyhub apply release.plan --allow-downtime
shinyhub fleet apply fleet.yaml --allow-downtime
--allow-downtime permits the stop-first fallback when handoff is unavailable;
it still uses handoff when safe. The fallback disconnects active sessions. Omit
the flag in CI when preserving availability is required: insufficient capacity
or another handoff refusal then fails the deploy with the working version still
serving. fleet apply defaults to this behavior too.
After an interrupted cleanup, ShinyHub retains the old process identity for startup recovery and defers another handoff until cleanup is confirmed.
Running, sleeping, waking, deploying, and degraded apps follow the same launch
behavior as the dashboard. Sleeping apps wake through the route. Stopped,
crashed, and never-deployed apps are not launched; the CLI gives the exact
start, log, or deploy command that resolves their state. --output json always
includes url, opened, and the observed app_status.
Install shell completion¶
The installer detects zsh, bash, fish, or PowerShell from the current shell:
Or name the shell explicitly, which is useful from setup scripts or an unusual terminal environment:
shinyhub completion install zsh
shinyhub completion install bash
shinyhub completion install fish
shinyhub completion install powershell
Installation is per-user and safe to rerun. Bash, zsh, and PowerShell receive one clearly marked source block in their normal startup file. Fish uses its native completions directory and needs no startup-file edit. Existing file permissions and all content outside ShinyHub's marked block are preserved.
Preview the exact paths without changing anything:
Start a new shell after installation, or follow the printed one-line reload
instruction. Completion includes commands and flags plus locally saved host
aliases and URLs for shinyhub use and --host. Host suggestions are read from
the credentials file without network access, and credentials are never emitted.
Remove only the files and marked block managed by ShinyHub:
Package maintainers can still generate a script without installing it:
shinyhub completion zsh > _shinyhub
shinyhub completion bash > shinyhub.bash
shinyhub completion fish > shinyhub.fish
shinyhub completion powershell > shinyhub.ps1
Understand client/server compatibility¶
Every current server advertises an integer protocol_version from the
unauthenticated /api/server-info endpoint. The protocol changes only for an
incompatible API contract. Additive features use capability flags, allowing a
newer CLI or server to keep the common command set working safely.
shinyhub connect checks compatibility before it authorizes or verifies a
credential. shinyhub doctor --remote exposes the same decision as a dedicated
version-compatibility check.
| Situation | Behavior |
|---|---|
| Same release line, including patch drift | Compatible; no upgrade warning |
| Older CLI, compatible newer server | Continue; suggest upgrading the CLI |
| Newer CLI, compatible older server | Continue with capability-gated features; suggest upgrading the server |
| Server protocol newer than the CLI understands | Stop before an authenticated request; upgrade the CLI |
| Legacy server without a protocol field | Continue through capability negotiation and report the uncertainty |
Before ShinyHub 1.0, the minor version defines a release line because minor releases may contain compatibility changes. Starting at 1.0, the major version defines it. The explicit protocol remains authoritative in either case.
The connection's JSON result includes cli_version, server_version,
protocol_version, and compatibility, so automation can record the decision
without parsing prose.
Ordinary shinyhub connect <url> is idempotent. It validates an existing saved
credential first and returns status: current without browser authorization or
key rotation when that credential is usable. Explicit command-line credentials
take precedence over SHINYHUB_TOKEN, which takes precedence over the saved
credential. Only a rejected saved credential falls through to authorization;
network, rate-limit, and server failures remain errors. --refresh is the
explicit exception and always rotates through browser approval.
Keep workstation credentials healthy¶
The server reports safe metadata about the credential used for each identity request: its type, optional name, creation time, prior last use, and expiry. It never returns the credential value or hash. Inspect it directly with:
Doctor warns when 14 days or less remain. Rotate a saved workstation credential through the same browser pairing flow without waiting for an outage:
The new credential must authenticate before the owner-only credentials file is
atomically replaced. Other hosts and the current alias are preserved. ShinyHub
then revokes the old API key; if only that cleanup fails, the new credential is
kept and the command provides a manual revocation command. --refresh ignores
SHINYHUB_TOKEN by design so an inherited CI secret cannot be written into the
workstation store.
Upgrade the side that is behind¶
For the Python-distributed CLI:
uv tool upgrade shinyhub
# or, when installed into a Python environment:
python -m pip install --upgrade shinyhub
For another installation method, upgrade through the same package manager or release artifact used originally. Upgrade the server through its existing deployment mechanism. Then verify the result without changing remote state:
Version warnings do not make Doctor fail when the advertised protocol is still compatible. An unsupported protocol is a blocker because guessing across a breaking API boundary would be less useful, and less safe, than stopping with the exact upgrade command.
Maintain the release contract¶
Before a release, run the complete long-lived CLI gate:
It combines two independent test groups:
make test-cli-compatibility-e2edownloads two exact, checksum-pinned releases. Thepreviouslane is the immediate predecessor and runs the full bidirectional upgrade journey: each released/current CLI connects to and deploys against the other server. The deliberately olderlegacylane runs the same journeys while also proving that a server withoutprotocol_versionremains safely capability-gated.make test-shell-completion-e2einstalls, loads, reinstalls, and uninstalls completion in real Bash, zsh, fish, and PowerShell processes. SetSHINYHUB_COMPLETION_SHELLS="bash zsh"for a smaller local subset.
The immediate compatibility baseline lives in
testdata/compatibility/previous-release.txt; advance it and add the new
release's published checksum manifest before the next release. The stable
no-protocol baseline lives separately in legacy-release.txt and changes only
when the legacy contract itself is deliberately retired or replaced. Never
regenerate either binary from a tag: the gate intentionally tests the artifacts
users actually installed.
The required /api/server-info shape for each protocol is recorded in
internal/protocol/testdata/server-info-vN.json. Additive response fields do
not require a bump. Removing a required field or changing its JSON type does:
increment protocol.CurrentVersion, add the new fixture, and keep the previous
fixture as the historical contract. CI fails if the implementation and the
declared fixture diverge.