Getting Started
This guide walks you through shipping your first Vibe app — from an empty machine to a live URL.
Prerequisites#
- Node.js ≥ 20 and npm. If you don't have them, see Installing Node below.
- A Facilio account with permission to create Vibe apps.
- A modern browser for the one-time OAuth approval during
vibe login.
The four-step workflow#
1. vibe login # once per machine2. vibe app create (first time only) # writes vibe.json with the app linkName3. <your build command> # e.g. npm run build, vite build, etc.4. vibe deploy # zips build.publish, uploads, publishesRepeat steps 3–4 to ship new versions. Every vibe deploy produces an incrementing versionNumber and a stable live URL plus an immutable versionedUrl.
The only step that needs a human is vibe login — it opens a browser, shows a code, and waits for you to click Approve. Everything else can be fully automated.
0. Install Node.js and npm#
Skip if node -v reports v20 or newer.
# macOS / Linux — nvm (no sudo, installs into $HOME)curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bashexport NVM_DIR="$HOME/.nvm"[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"nvm install --lts && nvm use --ltsnode -v && npm -vWindows (PowerShell): nvm-sh doesn't work. Use winget install OpenJS.NodeJS.LTS or install scoop and run scoop install nodejs-lts.
1. Install the CLI and SDK#
# CLI — install globally so `vibe` is on PATHnpm install -g @facilio/vibe-cli
# SDK — install per-project (when you scaffold your app below)npm install @facilio/vibe-sdkIf npm install -g fails with a permissions error, do NOT run sudo. Reconfigure npm's global prefix to live in your home dir, or use npx:
# Option A — install globals under ~/.npm-globalmkdir -p ~/.npm-globalnpm config set prefix ~/.npm-globalexport PATH="$HOME/.npm-global/bin:$PATH"npm install -g @facilio/vibe-cli
# Option B — skip global install; run via npx every timenpx @facilio/vibe-cli loginnpx @facilio/vibe-cli app create --name "My App"npx @facilio/vibe-cli deployIf you installed Node via nvm, npm install -g already works without sudo.
2. Authenticate#
vibe loginA browser tab opens with an approval code. Click Approve to finish signing in. The CLI polls until approval lands and prints Logged in as <email>..
If the browser didn't open (headless box, SSH session), the CLI prints a URL and a code — open the URL on any device and enter the code.
Sanity check:
vibe whoami# you@yourcompany.com • https://app.facilio.com3. Scaffold the project#
Vibe accepts any framework. The example below uses Vite + React, but plain HTML or any other framework works the same.
mkdir -p ~/vibe-apps && cd ~/vibe-appsnpm create vite@latest my-dashboard -- --template reactcd my-dashboardnpm installnpm install @facilio/vibe-sdk4. Wire the SDK#
Edit src/App.jsx:
import { useEffect, useState } from 'react';import { createVibe } from '@facilio/vibe-sdk';
const vibe = createVibe();
export default function App() { const [me, setMe] = useState(null); const [assets, setAssets] = useState([]); const [error, setError] = useState(null);
useEffect(() => { (async () => { const user = await vibe.getCurrentUser(); if (!user) { vibe.login(); // redirects to identity-service return; } setMe(user); try { const { response } = await vibe.executeAction('facilio-cmms', 'list-assets'); setAssets(response?.data ?? []); } catch (err) { setError(err.message); } })(); }, []);
if (error) return <p style={{ color: 'crimson' }}>{error}</p>; if (!me) return <p>Loading…</p>;
return ( <main style={{ fontFamily: 'system-ui', padding: 24 }}> <h1>Hello, {me.user.name}</h1> <p>Org: {me.org.orgId}</p> <h2>Assets ({assets.length})</h2> <ul> {assets.map(a => <li key={a.id}>{a.name} #{a.id}</li>)} </ul> </main> );}Key patterns
getCurrentUser()is the single source of truth for "signed in?". If it returnsnull, callvibe.login().- Do not wire
vibe.login()into the catch block ofexecuteAction. A 401 from a data call is just an error — surfaceerr.message. - All Facilio data access goes through
vibe.executeAction(connectionSlug, actionSlug, payload). Slugs and payload shapes come from the MCP catalog.
5. Create the app#
vibe app create --name "My Dashboard"This is non-interactive when --name is passed. The CLI writes vibe.json to the project root with the assigned linkName:
{ "name": "my-dashboard", "app": "my-dashboard", "build": { "publish": "dist" }}You only run this once per app. Subsequent deploys read app from vibe.json.
If your bundler emits to a folder other than dist/ (e.g. build/, out/), edit build.publish accordingly.
6. Build and deploy#
npm run build && vibe deployThe CLI:
- Reads
vibe.json→ finds thebuild.publishdirectory. - Zips its contents (level-9 deflate).
- Uploads, triggers publish, polls until
DEPLOYED. - Prints the live URL and the immutable versioned URL.
✔ Deployed v1 Live: https://my-dashboard.vibe.facilio.com Archive: https://my-dashboard.vibe.facilio.com/v/1Open the live URL in a browser. The first load redirects you through identity-service (because getCurrentUser() returned null); after approval you land back on the app with the assets list rendered.
7. Iterate#
For every change after the first deploy: edit source, build, deploy. No further login or app create.
npm run build && vibe deployEach deploy bumps the version. The live URL stays the same; the versioned URL (/v/N) is immutable.
Without a bundler (vanilla HTML)#
If you just want a one-page tool, skip the bundler entirely:
my-app/├── vibe.json└── dist/ ├── index.html └── app.jsdist/index.html:
<!doctype html><html> <head><meta charset="utf-8"><title>Asset list</title></head> <body> <button id="load">Load assets</button> <ul id="list"></ul> <script src="https://unpkg.com/@facilio/vibe-sdk"></script> <script src="./app.js"></script> </body></html>dist/app.js:
const vibe = VibeSDK.createVibe();document.getElementById('load').onclick = async () => { const user = await vibe.getCurrentUser(); if (!user) return vibe.login(); const { response } = await vibe.executeAction('facilio-cmms', 'list-assets'); document.getElementById('list').innerHTML = (response?.data ?? []).map(a => `<li>${a.name} #${a.id}</li>`).join('');};vibe.json:
{ "name": "asset-list", "app": "asset-list", "build": { "publish": "dist" } }Then vibe login → vibe app create --name "Asset list" → vibe deploy. No bundler, no transpile.
Checklist before vibe deploy#
-
vibe loginsucceeded (vibe whoamiprints your email). -
vibe app createhas been run at least once;vibe.jsoncontains"app": "<linkName>". - The folder named in
vibe.jsonbuild.publishexists and containsindex.htmlat its root. - Any Facilio data access in the code uses
vibe.executeAction(...)with slugs discovered fromhttps://mcp.facilio.com/mcp— not invented. - Login flow is wired:
getCurrentUser()checked on load,login()/logout()available to the user.
Next steps#
- CLI Reference — every command, every flag.
- SDK Reference — full SDK API surface and response shapes.
- Building with AI Agents — let Claude, ChatGPT, or Cursor build and ship Vibe apps for you.
- llms.txt — the full agent build-and-deploy guide.