CLI Reference
The @facilio/vibe-cli is the command-line tool that authenticates you, creates Vibe apps, and ships builds to a live URL.
Install#
# Install globally so `vibe` is on PATHnpm install -g @facilio/vibe-cli
# Or run via npx without a global installnpx @facilio/vibe-cli <command>If npm install -g fails with a permissions error, reconfigure npm's global prefix into your home dir (don't use sudo):
mkdir -p ~/.npm-globalnpm config set prefix ~/.npm-globalexport PATH="$HOME/.npm-global/bin:$PATH"npm install -g @facilio/vibe-clivibe.json — project config#
Place at the project root. The CLI reads and writes this file.
{ "name": "my-app", "app": "my-app", "build": { "publish": "dist" }}| Field | Required | Notes |
|---|---|---|
name | optional | Human-readable name. Shown in vibe app list. |
app | yes (after first deploy) | The linkName of the app on the server. Written automatically by vibe app create. |
build.publish | yes | Folder containing built static files. Must contain index.html. Default: dist. |
vibe app create scaffolds or patches this file for you — you don't need to write it by hand.
vibe login#
Authenticate with Facilio using OAuth2 device flow. Works on laptops, over SSH, and inside containers.
vibe loginFlow:
- The CLI prints a code and opens a browser tab.
- You click Approve in the browser. (This is the one human action in the whole workflow.)
- The CLI polls until approval lands, then prints
Logged in as <email>.
Run once per machine.
Where credentials are stored#
The CLI persists the token to the OS-provided secret store by default, with a 0600 file fallback only when no OS store is available:
| Platform | Storage | Mechanism |
|---|---|---|
| macOS | Keychain | security CLI — service facilio-vibe-cli, account default |
| Linux | Secret Service / libsecret | secret-tool (needs libsecret-tools) |
| Windows | Credential Manager (DPAPI) | Per-user encrypted ciphertext written to ~/.vibe/credentials.dpapi |
| Fallback | ~/.vibe/credentials.json (mode 0600) | Used when no OS store is available (headless Linux without libsecret, etc.) |
vibe whoami reports which sink is in use. To force the file fallback (e.g. in CI without a session keyring), set VIBE_NO_KEYCHAIN=1.
Headless / SSH / Docker: if no browser opens, the CLI prints a URL and a code — open the URL on any device.
vibe whoami#
Print the email and server of the active session. Use in scripts to sanity-check login state.
$ vibe whoamiyou@yourcompany.com • https://app.facilio.comExits non-zero if not logged in.
vibe logout#
Remove the stored token from the OS keychain (or the file fallback, whichever holds it).
vibe logoutvibe app create#
Create a new Vibe app on the server. Writes (or patches) vibe.json in the current directory.
For agent / scripted use, always pass --name so the command is non-interactive:
vibe app create --name "My App"# optional flags:vibe app create --name "My App" --description "Workorder triage dashboard" --logo ./logo.pngIf run with no flags, falls back to interactive prompts (name, description, logo, output directory). Skip the interactive path in automation.
Flags#
| Flag | Required | Notes |
|---|---|---|
--name | yes (for non-interactive) | Human-readable name. Server derives the linkName (subdomain) from this. |
--description | no | Optional description shown in vibe app list. |
--logo | no | Path to a png/jpg/svg/webp/gif/ico file, ≤ 750 KB. |
Output directory#
Only prompted in interactive mode. Defaults to dist. If your bundler emits elsewhere (build/, out/, public/), edit vibe.json build.publish after the create call.
Result#
vibe.jsonis created (or patched) with"app": "<linkName>"so subsequentvibe deploycalls don't need any flags.- The app's live URL is printed.
Run this once per app. If you're shipping a new version of an existing app, skip this step.
vibe app list#
List all Vibe apps in the org.
$ vibe app listLINK NAME NAME STATUS LAST PUBLISHED URLmy-dashboard My Dashboard DEPLOYED 2026-06-25 10:14 https://my-dashboard.vibe.facilio.comasset-list Asset list DEPLOYED 2026-06-24 18:02 https://asset-list.vibe.facilio.comvibe deploy#
Zip the publish folder, upload it, and publish it as a new version.
# In the project root, after running your buildvibe deployWhat it does:
- Reads
vibe.json→ finds thebuild.publishdirectory. - Zips its contents (level-9 deflate).
- POSTs to vibe-server, uploads the zip, triggers publish, polls until
DEPLOYEDorFAILED. - Prints the live URL and the immutable versioned URL.
✔ Deployed v3 Live: https://my-dashboard.vibe.facilio.com Archive: https://my-dashboard.vibe.facilio.com/v/3The live URL is stable across deploys. The versioned URL is immutable — useful for rollback links or sharing a snapshot.
Flags#
| Flag | Notes |
|---|---|
--prod | Mark this deployment as production. |
--app <linkName> | Override the app value from vibe.json (e.g., shipping the same build to a different app). |
You run your build, not the CLI#
The CLI does not invoke npm run build, vite build, etc. Build first, then deploy:
npm run build && vibe deployHard constraint on the publish folder#
The folder named by build.publish must contain index.html at its root. JS, CSS, and asset files alongside it are fine and expected — they're loaded by <script src=...> / <link rel=...> tags inside index.html as your bundler emits them. No index.html in the publish folder → the deploy succeeds but the URL serves nothing useful.
Common errors#
| Error | Cause | Fix |
|---|---|---|
Not logged in | No token in the OS keychain or file fallback | Run vibe login |
vibe.json not found | Running vibe deploy outside the project root | cd into the project root, or run vibe app create first |
index.html missing in dist/ | Build didn't emit an entry point | Check your bundler config; ensure the output dir matches build.publish |
EACCES on npm install -g | Node was installed via system package manager | Reconfigure npm prefix (see Install) — do not use sudo |
App with linkName already exists | Re-running vibe app create for an app that already exists | Skip this step; subsequent deploys use vibe.json |
Env vars#
| Variable | Purpose |
|---|---|
VIBE_NO_KEYCHAIN | Set to 1 / true / yes to skip the OS secret store and use ~/.vibe/credentials.json (0600) instead. Useful in CI without a session keyring. |
VIBE_SERVER_URL | Override the API server. Defaults to the server picked at login. |
VIBE_IDENTITY_URL | Override the identity-service base URL. Defaults are set per environment. |
VIBE_CLIENT_ID | Override the OAuth client id (default: vibe-cli). |
VIBE_SERVICE | Override the identity-service service key (default: vibe). |
End-to-end script#
For an agent shipping an app on a fresh machine:
# 0. Bootstrap Node if missingcommand -v node >/dev/null 2>&1 || { curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash export NVM_DIR="$HOME/.nvm"; \. "$NVM_DIR/nvm.sh" nvm install --lts && nvm use --lts}
# 1. Scaffold the projectmkdir -p ~/vibe-apps && cd ~/vibe-appsnpm create vite@latest my-dashboard -- --template reactcd my-dashboardnpm installnpm install @facilio/vibe-sdk
# 2. Install the CLI (fall back to npx if global install fails)npm install -g @facilio/vibe-cli 2>/dev/null || echo "Falling back to npx"
# 3. Authenticate — ONLY step where a human clicks oncevibe login
# 4. Create the app non-interactivelyvibe app create --name "My Dashboard"
# 5. Edit src/ to use createVibe(), executeAction(), etc.
# 6. Build and deploynpm run build && vibe deploySee Getting Started for the walkthrough with code, and Building with AI Agents for the full agent recipe.