Skip to content

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:

shinyhub deploy . --open

--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:

shinyhub apps open sales
shinyhub apps open sales --no-browser  # SSH, containers, and scripts

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:

shinyhub completion install

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:

shinyhub completion install --dry-run

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:

shinyhub completion uninstall

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:

shinyhub whoami
shinyhub whoami --output json
shinyhub doctor --remote

Doctor warns when 14 days or less remain. Rotate a saved workstation credential through the same browser pairing flow without waiting for an outage:

shinyhub connect --refresh
# remote terminal:
shinyhub connect --refresh --no-browser

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:

shinyhub --version
shinyhub doctor --remote

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:

make test-cli-release-contract

It combines two independent test groups:

  • make test-cli-compatibility-e2e downloads two exact, checksum-pinned releases. The previous lane 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 older legacy lane runs the same journeys while also proving that a server without protocol_version remains safely capability-gated.
  • make test-shell-completion-e2e installs, loads, reinstalls, and uninstalls completion in real Bash, zsh, fish, and PowerShell processes. Set SHINYHUB_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.