CLI reference
Every vibehost command. All accept --json for machine-readable output.
The CLI is the canonical interface for VibeHost. The dashboard, MCP server, and SDKs are conveniences over the same REST API the CLI uses. Anything you can do here, an agent can do too, and the other way round.
Install
curl -fsSL -o vibehost-install.sh https://vibehost.com/install.sh
less vibehost-install.sh
sh vibehost-install.sh && rm vibehost-install.shInvoke-WebRequest -UseBasicParsing https://vibehost.com/install.ps1 -OutFile vibehost-install.ps1
Get-Content .\vibehost-install.ps1
& .\vibehost-install.ps1
Remove-Item .\vibehost-install.ps1The installer puts a single static binary in ~/.vibehost/versions/<version>/, with ~/.vibehost/cli symlinked at the active version and a vibehost shim in a bin directory on your PATH. You don't need a Node runtime.
If no suitable directory is already on your PATH, the installer uses ~/.local/bin and appends an export line to the profile your shell reads.
| Shell | Files written |
|---|---|
| zsh | ~/.zshenv (or $ZDOTDIR/.zshenv) |
| bash | ~/.bashrc, plus the first of ~/.bash_profile / ~/.bash_login / ~/.profile that exists. If none do, it creates ~/.profile |
| fish | ${XDG_CONFIG_HOME:-$HOME/.config}/fish/conf.d/vibehost.fish |
| csh / tcsh | Nothing (see below) |
| anything else | ~/.profile |
It prints the line it added, so you can paste it into your current shell instead of opening a new terminal. Set VIBEHOST_NO_PATH_EDIT=1 to skip the edit and manage PATH yourself, or VIBEHOST_PREFIX=<dir> to choose the bin directory. The installer creates that directory if it does not exist. Its path must not contain a colon, since that is the PATH separator.
zsh gets ~/.zshenv rather than ~/.zshrc on purpose: zsh reads .zshrc only for interactive shells, so a coding agent running zsh -c "vibehost deploy" would not see a PATH written there. .zshenv is read by every zsh invocation.
csh and tcsh get no profile written. They read ~/.cshrc / ~/.tcshrc with their own syntax, which would mean a fourth dialect to generate and test for a shell almost nobody drives a coding agent from. The installer says so and prints a line you can add yourself:
# ~/.tcshrc — csh/tcsh syntax, not written for you
setenv PATH "$HOME/.local/bin":"$PATH"bash has no equivalent of .zshenv. A plain bash -c "vibehost deploy" is neither interactive nor a login shell, so bash reads none of the files above and vibehost will not be found. Interactive terminals (.bashrc) and login shells (bash -l, bash -lc, every macOS Terminal tab) are covered. If you drive the CLI from non-interactive bash, either use bash -lc instead of bash -c, or set PATH in the script itself, with export PATH="$HOME/.local/bin:$PATH" under bash or zsh and set -gx PATH "$HOME/.local/bin" $PATH under fish. In a script that should not depend on PATH at all, call ~/.vibehost/cli/vibehost directly: that symlink always points at the active version.
Config lives at ~/.config/vibehost/config.json (chmod 600). Multi-account setups use named profiles (--profile <name> / $VIBEHOST_PROFILE). The CLI never logs plaintext tokens. When the server issues a token, it stores only a hash and returns the plaintext once.
Upgrade:
vibehost updateThis replaces the binary in place. CI should pin a version by downloading the install script with a version param (https://vibehost.com/install.sh accepts a VIBEHOST_VERSION env var) and then running the reviewed file.
JSON output and exit codes
Every command takes --json. Success returns {ok: true, data}, error returns {ok: false, error: {code, message, details?}}. Exit codes:
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Unknown error (bug, panic) |
| 2 | Auth (login required, EMAIL_NOT_VERIFIED, REAUTH_REQUIRED) |
| 3 | Validation (bad input, missing field, malformed cursor) |
| 4 | Upstream (API returned 5xx, runtime down, SERVICE_UNAVAILABLE, RELEASE_GONE) |
| 5 | Network (DNS, timeout, cert) |
| 6 | Rate-limited (RATE_LIMITED). Back off and retry |
LLM clients should branch on error.code (stable SCREAMING_SNAKE_CASE), not error.message. See Errors reference for the full list.
Global flags
Any command accepts:
| Flag | Effect |
|---|---|
--json | Emit JSON on stdout/stderr (scriptable) |
--workspace <slug> | One-off workspace override; doesn't persist. Resolves the slug against your workspace list, so it costs one extra request. Not available to vh_pat_* tokens, because a PAT is bound to a single workspace when it is created |
--team <slug> | One-off team override |
--profile <name> | Use a named profile for this command (see Profiles) |
--help / -h | Show command help |
--version / -V | Print CLI version |
Env vars:
| Var | Effect |
|---|---|
VIBEHOST_TOKEN | PAT for auth (overrides vibehost login) |
VIBEHOST_API_URL | Base URL (default https://api.vibehost.com) |
VIBEHOST_PROFILE | Named profile to use (same as --profile; flag wins) |
VIBEHOST_TELEMETRY | on / off for one-off telemetry override |
NO_COLOR | Disable ANSI colors |
Auth
Sign in, register, and manage your CLI session. vibehost login runs a device flow (supports Google); pass --email and --password to skip it in CI.
vibehost init https://api.vibehost.com
vibehost register --email you@x.com --password <pw>
vibehost login
vibehost login --email you@... --password <pw>
vibehost whoami
vibehost auth resend-verification
vibehost auth change-password
vibehost logoutvibehost init sets the API base URL for the selected profile. vibehost whoami returns identity, workspace, team, and abilities. vibehost auth change-password requires re-auth within 5 minutes; vibehost logout revokes the active profile's token on the server, clears it locally, and lists any other profiles that still hold credentials.
Example whoami --json:
{
"ok": true,
"data": {
"userId": "usr_...",
"email": "you@example.com",
"workspaceId": "ws_...",
"workspaceSlug": "acme",
"teamId": "tm_...",
"teamSlug": "web",
"abilities": ["apps:read", "apps:write", "apps:deploy", "..."]
}
}Profiles
Named profiles keep separate accounts, workspace/team selections, and tokens, so a personal and a team account can live on one machine. The profile you've always used is the default profile, and nothing changes until you create a named one.
vibehost --profile work login # logging in creates the profile
vibehost profile list # stored profiles + which is active
vibehost --profile work deploy # any command accepts --profile
vibehost --profile work logout # revoke + clear ONE profile
vibehost profile remove work # delete the entry (asks you to logout first)Selection is per invocation only. --profile <name> beats $VIBEHOST_PROFILE, and with neither you get the default profile. There is deliberately no persistent profile use switch, because a sticky current profile is how a "staging" command ends up hitting production. For a long session, export VIBEHOST_PROFILE=work (or direnv) scopes the selection to that shell. An unknown profile name is an error (exit 3) that lists the stored names. It never falls through to the default profile.
Notes:
telemetryconsent is device-global; everything else (server URL, tokens, email, workspace/team, capability cache) is per-profile.VIBEHOST_TOKEN(PAT) still overrides the selected profile's stored token for that invocation.profile removeis local-only and refuses a profile that still holds credentials unless you pass--force; runvibehost --profile <name> logoutfirst so the server-side tokens are revoked.
Apps
Create, inspect, and manage apps. New apps default to the static runtime; app list is aliased ls and shows the newest 50 apps (--limit up to 100, --cursor for the next page, --all for every app), and visibility is one of public | workspace | private.
vibehost app create my-site
vibehost app create my-site --display-name "Acme Marketing Site" --description "Landing pages for the spring campaign"
vibehost app list
vibehost app inspect my-site
vibehost app update my-site --display-name "Acme Site v2"
vibehost app update my-site --description "Refreshed spring campaign pages"
vibehost app update my-site --clear-display-name
vibehost app update my-site --clear-description
vibehost app delete --app my-site
vibehost app delete my-site --force
vibehost app visibility my-site public
vibehost app qr --app my-site
vibehost app qr https://example.com --png ./qr.pngapp create optionally takes --display-name (1 to 100 characters) and --description (1 to 500 characters). Both are display metadata for the dashboard. You can change them, they don't have to be unique, and the dashboard shows the name when they are unset. The name itself is the unique slug used in URLs, and it can't be changed. app update edits the metadata later: --display-name / --description set a new value, --clear-display-name / --clear-description reset to unset. When an app is created without a display name, the CLI prints a one-line stderr tip suggesting the flags.
app delete prompts interactively; pass --force for CI / non-TTY. app qr renders a terminal QR of the deployed URL, or any URL you pass, optionally to a PNG with --png.
app inspect returns the app's full state in one call, and it is the command agents should read from. Run it before any non-trivial decision.
vibehost app inspect my-site --json | jq '.data | {visibility, passwordSet, channels: [.channels[].name], grants: [.teamGrants[].role]}'Link + deploy
link saves an app reference to .vibehost/project.json in the current dir. After linking, --app is optional.
vibehost link --app my-site
vibehost unlink
vibehost deploy
vibehost deploy ./public
vibehost deploy --channel pr-42
vibehost deploy --no-chunked
vibehost deploy --build server
vibehost deploy --runtime staticdeploy packs the cwd (or an explicit dir), uploads chunked by default (--no-chunked for a raw tar), and auto-detects the runtime (--runtime to override). --channel targets a preview channel; --build server opts into the sandboxed builder.
Deploy response (truncated):
{
"ok": true,
"data": {
"id": "depl_abc123",
"url": "https://my-site-acme.vibehost.space",
"immutableUrl": null,
"deployKind": "static",
"status": "healthy",
"warnings": []
}
}--build defaults to auto. A static app uploads what you already
built, while nextjs and node apps build inside a sandboxed builder on
the server, which also suits constrained agents in some MCP hosts.
--build client builds a Next.js app on your machine instead; a node
app has no client build.
Channels, promote, rollback
promote launches an already-uploaded deployment into a channel; rollback flips the channel alias back to the previous healthy deployment (production by default).
vibehost promote currently fails for static apps on vibehost.com with an INTERNAL error. Until that's fixed, deploy the same build output to the target channel instead, for example vibehost deploy ./dist --channel production --app my-site. Deploy the directory you tested without rebuilding it, and the files that go live are the files you tested. Uploads are content-addressed, so nothing the server already has is transferred again. vibehost rollback isn't affected.
vibehost channel list --app my-site
vibehost channel delete pr-42 --app my-site
vibehost channel delete pr-42 --app my-site --force
vibehost promote <deploymentId> --to-channel production --app my-site
vibehost rollback --app my-site
vibehost rollback --app my-site --channel pr-42channel list shows all channels plus the current deployment id. channel delete removes a channel and its deployment alias (--force skips the prompt).
Pull (remix a teammate's deploy)
Download a live static artifact to edit and redeploy. vibehost pull my-site writes to ./my-site/, ready to edit and redeploy.
vibehost pull my-site
vibehost pull my-site --channel pr-42
vibehost pull my-site --deployment depl_xyzWith pull, the deployment itself is the source of truth. A teammate with a grant downloads a static deploy, edits it, and redeploys, with no separate repo. It works for static apps only.
Logs
Tail deployment logs. Defaults to the latest deployment's last 100 lines; --since windows the range and --follow streams new lines.
vibehost logs --app my-app
vibehost logs my-app
vibehost logs --app my-app --deployment <id>
vibehost logs --app my-app --since 10m
vibehost logs --app my-app --since 1h --follow
vibehost logs --app my-app --jsonLogs are bound to deployments, not channels. After a rollback, you read the logs of the older deployment that is now current. --json emits one JSON object per line.
Custom domains
Attach and verify custom hostnames. domain add prints DNS instructions; run domain verify after you've set the records.
vibehost domain list --app my-site
vibehost domain add blog.example.com --app my-site
vibehost domain verify blog.example.com --app my-site
vibehost domain remove blog.example.com --app my-site
vibehost domain show blog.example.comdomain show reports the status of any hostname. See Custom domains for DNS provider walkthroughs and verification failure modes.
Environment variables
Set build and runtime env vars. set targets both by default; narrow with --target runtime or --target build. --secret masks the value in env ls unless you pass --reveal.
vibehost env set KEY=value --app my-app
vibehost env set KEY=value --app my-app --target runtime
vibehost env set KEY=value --app my-app --target build
vibehost env set KEY=value --app my-app --secret
vibehost env ls --app my-app
vibehost env ls --app my-app --reveal
vibehost env rm KEY --app my-appYou rarely need --target build, since the CLI builds locally. --secret masks the value in env ls output for casual inspection; the actual value is encrypted at rest (column-level encryption with workspace-scoped keys).
Redirects
Platform-level redirects, applied without a rebuild. The default status is 301 (--status to override); upload and sync apply rules in bulk.
vibehost redirects list --app my-site
vibehost redirects add /old-path /new-path --app my-site
vibehost redirects add /old-path /new-path --app my-site --status 302
vibehost redirects remove <ruleId> --app my-site
vibehost redirects upload ./redirects.json --app my-site
vibehost redirects sync --app my-siteredirects sync diffs the local file against the live rules and applies the delta. Static apps can also ship a _redirects file in the deploy dir (Netlify syntax); platform redirects override _redirects if there's a conflict.
Grants, visibility, password, share links
App access lives under vibehost app …. There are two kinds of grant (team and email), visibility (public, workspace, or private), an optional password gate, and optional share-link cookies. Every active gate must pass, and share-link cookies are the documented bypass.
Team + email grants
grants ls shows both axes; grants self grants your own user (audited).
vibehost app grants ls --app my-site
vibehost app grants add-team <team-slug> deployer --app my-site
vibehost app grants remove-team <team-slug> --app my-site
vibehost app grants add-email teammate@x.com viewer --app my-site
vibehost app grants remove-email teammate@x.com --app my-site
vibehost app grants self admin --app my-siteVisibility
Both forms work, because the positional arguments are accepted in either order. Visibility is one of public | workspace | private.
vibehost app visibility my-site public
vibehost app visibility public --app my-sitePassword gate
vibehost app password set <password> --app my-site
vibehost app password clear --app my-site
vibehost app password status --app my-siteShare links
vibehost app share-link create --app my-site --label "Acme review" --expires-in 7d
vibehost app share-link ls --app my-site
vibehost app share-link revoke <idOrPrefix> --app my-siteshare-link revoke accepts an id or a unique prefix. See Grants and visibility for the decision tree and access matrix.
OG card (link previews)
Customize the link-preview card. Free tier carries a powered by VibeHost watermark; turning it off with --off requires a paid plan.
vibehost app og --app my-site
vibehost app og set --title "..." --description "..." --app my-site
vibehost app og set --image ./og-card.png --app my-site # Business plan
vibehost app og unset --field image --app my-site # any plan
vibehost app og watermark --off --app my-siteOG screenshots are auto-generated by the previewer worker after each deploy.
--image uploads a local PNG, JPEG or WebP file (up to 4 MB, best at 1200 × 630) and needs a Business workspace. An uploaded image is never watermarked, and anyone with the link can see it, even on a private app. An image uploaded on Business keeps showing after a downgrade; removing it works on every plan. You can also upload one from the app's Settings → Share image.
Workspace + team
Workspace
workspace role takes owner | admin | member. workspace delete is owner-only and refuses if apps still exist.
vibehost workspace ls
vibehost workspace use <slug>
vibehost workspace info
vibehost workspace create <slug>
vibehost workspace members
vibehost workspace role <email> <role>
vibehost workspace invite <email> --role admin
vibehost workspace uninvite <id>
vibehost workspace remove <email>
vibehost workspace delete <slug> --force
vibehost workspace domain ls
vibehost workspace domain add yourcompany.com --tier verifiedTeam
Team roles are member | manager. rename-slug changes the URL-visible slug.
vibehost team ls
vibehost team switch <slug>
vibehost team info
vibehost team create <slug>
vibehost team invite <email> --role member
vibehost team members
vibehost team role <email> <role>
vibehost team remove <email>
vibehost team delete <slug> --force
vibehost team rename-slug <new-slug>Audit
Read the workspace audit log (owner / admin only). Defaults to the latest 100 rows; filter by --since, --actor, --target, or --action.
vibehost audit
vibehost audit --since 7d
vibehost audit --since 7d --json
vibehost audit --actor teammate@x.com
vibehost audit --target app:my-site
vibehost audit --action grant_addedEach record has the actor, action, target, a before/after diff, and a timestamp. Records are never deleted and are kept for the life of the workspace. Use --json to feed an external SIEM.
GC (clean up old deployments)
Delete old deployments (owner / admin only). Keeps the last 5 per channel by default; --keep changes retention and --dry-run previews without deleting.
vibehost gc --app my-app
vibehost gc --app my-app --keep 10
vibehost gc --app my-app --dry-runOlder deployments are deleted and their storage freed. You can still download a kept one with pull --deployment <id>.
Doctor + telemetry + referral + redeem
Diagnostics and account utilities. Run vibehost doctor first when something's off; vibehost redeem <code> exchanges a code for N months of Business.
vibehost doctor
vibehost doctor --json
vibehost telemetry
vibehost telemetry on
vibehost telemetry off
vibehost referral
vibehost referral claim
vibehost redeem <code>doctor reports auth state, API reachability, version skew, common config gotchas, DNS resolution, and system time skew. vibehost referral shows your referral link and stats; referral claim claims a credit you've earned. Referrals covers how you earn one.
Full command list
Run vibehost --help or any vibehost <cmd> --help for the authoritative list. Every command supports --json and --help. --workspace <slug> applies to every workspace-scoped command; team-scoped commands (vibehost team …) reject it, because the active team belongs to the workspace you pinned with workspace use.
See also
- Errors reference lists every error code, what triggers it, and how to handle it.
- Personal access tokens covers auth for CI and calling the same API over HTTP.