CLI Reference
Every Facilio product ships as part of a single CLI — @facilio/cli (binary: facilio). One login covers every product; every product's commands live under its own namespace.
The command surface splits into three groups:
| Group | Namespace | What it does |
|---|---|---|
| 1. Facilio | facilio <cmd> | Auth commands shared across every product: login, logout, whoami. |
| 2. Vibe | facilio vibe <cmd> | Build and deploy Vibe apps: deploy, app, db, function, jobs. |
| 3. Connections | facilio connections <cmd> | Discover and run actions across 1000+ integrated apps: search, schemas, list, link, unlink, wait, execute. |
Coming from @facilio/vibe-cli?
The old package (binary: vibe) is deprecated. Mental model for the migration: prefix facilio before every vibe command, and drop the vibe prefix from login / logout / whoami since those are now shared across products. See Migrating from @facilio/vibe-cli.
Install#
# Install globally so `facilio` is on PATHnpm install -g @facilio/cli
# Or run via npx without a global installnpx @facilio/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/cliMigrating from @facilio/vibe-cli#
The old package is deprecated. To migrate:
npm uninstall -g @facilio/vibe-clinpm install -g @facilio/cliYour existing vibe.json files keep working unchanged — only the binary name and command layout changed. On first facilio login, the CLI reads any credentials left behind by the old vibe binary (keychain service facilio-vibe-cli, or ~/.vibe/credentials.json) and migrates them into the new locations (service facilio-cli, or ~/.facilio/credentials.json) — you don't need to re-authenticate.
1. Facilio commands#
Auth commands shared across every Facilio product. One facilio login covers Vibe, Connections, and everything else — you never re-authenticate per product.
facilio login#
Authenticate with Facilio using OAuth2 device flow. Works on laptops, over SSH, and inside containers.
facilio 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.
Flags#
| Flag | Notes |
|---|---|
--api-key <key> | Log in with an API key instead of the browser flow. Use - to read from stdin. Preferred for CI. |
--region <key> | Region for --api-key logins (US, UK, AE, AU, …). Resolves the right server URLs. Defaults to US. |
--server <url> | Pin the vibe-server URL for this session (overrides the region table). |
--client-id <id> | Override the OAuth client id (default: FACILIO_CLIENT_ID). |
--identity-url <url> | Identity-service base URL (default: FACILIO_IDENTITY_URL). |
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-cli, account default |
| Linux | Secret Service / libsecret | secret-tool (needs libsecret-tools) |
| Windows | Credential Manager (DPAPI) | Per-user encrypted ciphertext written to ~/.facilio/credentials.dpapi |
| Fallback | ~/.facilio/credentials.json (mode 0600) | Used when no OS store is available (headless Linux without libsecret, etc.) |
facilio whoami reports which sink is in use. To force the file fallback (e.g. in CI without a session keyring), set FACILIO_NO_KEYCHAIN=1.
Headless / SSH / Docker: if no browser opens, the CLI prints a URL and a code — open the URL on any device.
facilio whoami#
Print the email and server of the active session. Use in scripts to sanity-check login state.
$ facilio whoamiyou@yourcompany.com • https://app.facilio.comExits non-zero if not logged in.
facilio logout#
Revoke the session server-side (best effort) and remove the stored token from the OS keychain (or the file fallback, whichever holds it).
facilio logout2. Vibe commands#
Build and deploy Vibe apps. Every Vibe command lives under facilio vibe <cmd> and is scoped to the app in your current directory's vibe.json.
vibe.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 facilio vibe app list. |
app | yes (after first deploy) | The linkName of the app on the server. Written automatically by facilio vibe app create. |
build.publish | yes | Folder containing built static files. Must contain index.html. Default: dist. |
facilio vibe app create scaffolds or patches this file for you — you don't need to write it by hand.
facilio vibe app create#
Create a new Vibe app on the server. Writes (or patches) vibe.json in the current directory.
facilio vibe app createThe command prompts interactively for name, description, logo, and output directory. Every field except name is optional — press Enter to skip.
Flags#
All flags are optional; anything you don't pass is prompted for.
| Flag | Notes |
|---|---|
--name | Human-readable name. Server derives the linkName (subdomain) from this. |
--description | Optional description shown in facilio vibe app list. |
--logo | 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 subsequentfacilio vibe 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.
facilio vibe app list#
List all Vibe apps in the org.
$ facilio 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.comfacilio vibe deploy#
Zip the publish folder, upload it, and publish it as a new version.
# In the project root, after running your buildfacilio vibe 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 && facilio 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.
Database — facilio vibe db#
Each app can have its own dedicated database: a Postgres schema plus a scoped role and login user, provisioned on demand. All vibe db commands are app-scoped — they resolve the target app from --app or vibe.json, and add --app <linkName> to override.
facilio vibe db create#
Provision the database for the current app. Idempotent — re-running returns the existing schema/role/user rather than creating a second one. Run this once before importing tables.
facilio vibe db create✓ Database ready. Schema: vibe_ab12cd… Role: vibe_ab12cd…_rw User: vibe_ab12cd…_usrThe schema is named after the app and is isolated — no other app can see it.
facilio vibe db import#
Create a table by importing a CSV file. Columns are inferred from the CSV header and data server-side. Requires facilio vibe db create first.
facilio vibe db import --file customers.csv --table customers✓ Imported 128 rows into vibe_ab12cd….customers Columns: 5| Flag | Required | Notes |
|---|---|---|
--file <path> | yes | Path to the CSV file. Prompted if omitted. |
--table <name> | no | Target table name. Defaults to a sanitized form of the file name. |
--app <linkName> | no | Override the app target from vibe.json. |
The import is not atomic (CREATE TABLE followed by chunked INSERTs) — a mid-way failure can leave a partially populated table.
facilio vibe db tables (alias ls)#
List the tables in the app's database.
facilio vibe db tablesNAME TYPE ROWS--------- ----- ----customers table 128orders table 512facilio vibe db describe <table> (alias desc)#
Show a table's columns (name, type, nullable) and its total row count.
facilio vibe db describe customers→ vibe_ab12cd….customers (128 rows)COLUMN TYPE NULLABLE------ ------- --------id integer noname text yesemail text yesFunctions — facilio vibe function (alias fn)#
Functions are server-side handlers you author, compile to WASM, and invoke. They can run SQL against the app's database and call Facilio connections. Functions are app-scoped: the logical name you choose (e.g. workorderlist) is unique within your app, and the backend uploads it under an app-unique physical name so functions in different apps never collide or see each other. Every command resolves the app from --app or vibe.json.
Lifecycle: create → build → run. Updating re-uploads the source and requires a rebuild.
Writing a function#
For the authoritative, always-current version of this format, run facilio vibe function instructions — it prints the guide straight from ai-studio, so it never drifts from a hand-copied template.
A function is a JS/TS module built on @facilio/studio-functions. Register one or more named handlers, then call server.execute():
import StudioFunctions, { secret } from "@facilio/studio-functions";
const server = new StudioFunctions({ name: "workorderlist", version: "1.0.0" });
server.addHandler({ name: "list", description: "List open work orders", parameters: { limit: { description: "Max rows", type: "number" }, }, execute: async (args) => { const schema = secret("SCHEMA"); // this app's DB schema const dbUser = secret("DB_USER"); // its DB login user // ...run SQL / call connections, then return any JSON-serializable value return { rows: [] }; },});
server.execute();Secrets are injected by the backend at run time and read with secret("KEY") — the caller never passes them:
| Secret | What it is |
|---|---|
CONNECTIONS_TOKEN | Token to reach Facilio connections. |
AGENTS_TOKEN | Token to reach the agents (ai-studio) service. |
SCHEMA | The app's provisioned DB schema (present once facilio vibe db create has run). |
DB_USER | The app's DB login user. |
facilio vibe function instructions (alias guide)#
Print the authoritative guide for writing a function. vibe-server fetches it from ai-studio (the same source the platform uses), so it's always current — prefer this over any static example when authoring. Org-level; takes no --app.
facilio vibe function instructions# capture it to a file, or hand it to an AI agent:facilio vibe function instructions > function-guide.mdfacilio vibe function create <name>#
Upload a new function from a code file. Fails if a function with that name already exists in the app.
facilio vibe function create workorderlist --code ./workorderlist.js --description "List open work orders"| Flag | Required | Notes |
|---|---|---|
--code <path> | yes | Path to the function source file. Prompted if omitted. |
--package <path> | no | Optional package.json for the function's dependencies. |
--description <text> | no | Stored with the function; shown in facilio vibe function list. |
--app <linkName> | no | Override the app target from vibe.json. |
facilio vibe function update <name>#
Replace an existing function's source. Fails if it doesn't exist. Re-uploading invalidates the previous build — run facilio vibe function build again afterward. Same flags as create.
facilio vibe function update workorderlist --code ./workorderlist.jsfacilio vibe function build <name>#
Compile the uploaded source to WASM. Synchronous — may take a while. On success it lists the discovered handler names.
facilio vibe function build workorderlist✓ Built "workorderlist". Built at: 2026-07-03T09:14:02Z WASM size: 480321 bytes Handlers: list Run one with `facilio vibe function run workorderlist <handler>`.facilio vibe function run <name> <handler> (alias exec)#
Execute one handler of a built function. --args is a JSON object of the handler's arguments. Secrets are injected by the backend (see above) — you never pass them. Prints the handler's return value.
facilio vibe function run workorderlist list --args '{"limit": 20}'| Flag | Notes |
|---|---|
--args <json> | Handler arguments as a JSON object. Defaults to {}. |
--app <linkName> | Override the app target from vibe.json. |
facilio vibe function list (alias ls)#
List the app's functions.
facilio vibe function listNAME BUILT DESCRIPTION------------- ----- ---------------------workorderlist yes List open work ordersfacilio vibe function get <name> (alias show)#
Show a function's build state, description, and source. Pass --code-only to print just the code — handy for redirecting to a file.
facilio vibe function get workorderlistfacilio vibe function get workorderlist --code-only > workorderlist.jsfacilio vibe function delete <name> (alias rm)#
Delete a function and all its artifacts.
facilio vibe function delete workorderlistRunning from a deployed app: functions can also be invoked from the browser at runtime via
vibe.executeFunction. The backend resolves which app you're in from the subdomain, so browser calls run only that app's functions.
Scheduled Jobs — facilio vibe jobs (alias job)#
Scheduled jobs run one of your app's built functions on a recurring schedule — cron or fixed interval — without a browser being open. Every fire executes as the app's dedicated public user (the one facilio vibe app create provisions), so the function's identity, tokens, and DB access work exactly like an authenticated request. Jobs are app-scoped — resolved from --app or vibe.json.
Typical loop: create a job → it fires on schedule → observe Last run on the CLI, or the row it writes in your app's DB / UI.
Product-level bounds#
Two hard bounds the server enforces on every create and update — they're a product decision, not a technical limit:
| Bound | Value | Why |
|---|---|---|
| Min interval between fires | 15 minutes | Consecutive fires of the same job cannot be closer than this. For interval schedules, intervalSeconds >= 900. For cron, the CLI parses your expression and rejects it if two consecutive slots are under 15 min apart. |
| Max timeout per fire | 15 minutes (900 s) | A single fire cannot claim more than 15 min of wall clock — after that the runner is cancelled and the fire is recorded as failed. Also the default when --timeout is omitted. |
Prerequisites#
Before you can schedule a job:
- The app must exist (
facilio vibe app create). - The function must be built (
facilio vibe function build <name>). - The app must have been promoted to production — scheduled jobs run against the prod function name (
<name>_<uuid>), never against preview. If you schedule a job on an app that only exists on preview, every fire will fail with "function not found".
facilio vibe jobs create <name>#
Schedule a new job. Requires --function and exactly one of --cron or --interval.
# Cron — every day at 9 AM (in the org's timezone; falls back to UTC)facilio vibe jobs create daily-report \ --function sendDailyReport \ --handler default \ --cron '0 0 9 * * *' \ --payload '{"recipients":["ops@example.com"]}' \ --timeout 300
# Interval — every 30 minutes, minimal flagsfacilio vibe jobs create healthcheck \ --function pingUpstream \ --interval 1800
# Create as PAUSED — no scheduler row until you `resume`facilio vibe jobs create monthly-cleanup \ --function purgeStale \ --cron '0 0 3 1 * *' \ --paused| Flag | Required | Notes |
|---|---|---|
--function <name> | yes | Logical function name from facilio vibe function list. Must be built. |
--handler <name> | no | Entry point inside the function. Omit → SDK default. |
--cron <expr> | one of these | Spring 6-field cron: second minute hour day-of-month month day-of-week. Consecutive fires must be ≥ 15 min apart. |
--interval <seconds> | one of these | Fixed-delay in seconds. Must be ≥ 900. |
--timeout <seconds> | no | Wall-clock per fire, 1..900. Defaults to 900 (15 min). |
--payload <json> | no | JSON object forwarded verbatim as the function's args at every fire. |
--paused | no | Create in paused state; scheduler row is written only when you resume. |
--app <linkName> | no | Override the app target from vibe.json. |
Cron vs interval — which to pick#
| Reach for cron when... | Reach for interval when... |
|---|---|
| Timing matters to the outside world — "9 AM daily", "1st of the month", "Monday 8 AM". | The exact moment doesn't matter — "roughly every N minutes". |
| You want fires aligned to wall-clock ticks. | You want guaranteed spacing regardless of how long the last run took. |
| You care about "which day" or "which weekday". | Health checks, polling, periodic sync. |
Same 15-min floor and 900-s timeout ceiling apply to both. Cron expressions are interpreted in the org's configured timezone (from your Facilio account settings), falling back to UTC.
facilio vibe jobs list (alias ls)#
List every job configured for the app. Newest-first.
facilio vibe jobs listNAME FUNCTION SCHEDULE STATUS LASTRUN------------ -------------- ------------- ------- ---------------------------------daily-report sendDaily... cron 0 0 9... active 2026-07-17T03:00:04Z (success)healthcheck pingUpstream every 1800s active —facilio vibe jobs get <name> (alias show)#
Full detail — schedule, timeout, payload, and last-run outcome including any error.
facilio vibe jobs get daily-reportdaily-report (id 1, status=active) Function : sendDailyReport › default Schedule : cron 0 0 9 * * * Timeout : 300s Payload : {"recipients":["ops@example.com"]} Last run : 2026-07-17T03:00:04Z — successIf a fire failed, Last run shows failed and Error shows the failure reason (truncated to ~2 KB). That's the single most useful signal for debugging.
facilio vibe jobs update <name>#
Partial PATCH — pass only the flags you want to change. Everything else stays as it was. Immutable fields (name, functionName) can't be updated — delete + recreate to change either.
# Change the schedulefacilio vibe jobs update daily-report --cron '0 30 9 * * *'
# Replace the payloadfacilio vibe jobs update daily-report --payload '{"recipients":["ops@example.com","cto@example.com"]}'
# Bump the timeoutfacilio vibe jobs update healthcheck --timeout 60| Flag | Notes |
|---|---|
--handler <name> | Change the handler entry point. |
--cron <expr> | Switch to a cron schedule. Rejects --interval on the same call. |
--interval <seconds> | Switch to an interval schedule. Rejects --cron on the same call. |
--timeout <seconds> | Change the wall-clock timeout. Same 1..900 bound. |
--payload <json> | Replace the payload (JSON object). |
--status <active\|paused> | Enable / disable firing without deleting the row. |
--app <linkName> | Override the app target from vibe.json. |
Passing no flags is rejected — nothing to update.
facilio vibe jobs pause <name>#
Sugar for update --status paused. Stops firing but keeps the row so you can resume later without losing the schedule or payload.
facilio vibe jobs pause daily-reportBehind the scenes: cancels the scheduled_tasks row so a paused job incurs zero scheduler wakeups. The Vibe_App_Jobs row stays intact.
facilio vibe jobs resume <name>#
Sugar for update --status active. Re-creates the scheduler row using the job's current schedule; first fire is at "now + interval" (interval jobs) or the next cron slot (cron jobs).
facilio vibe jobs resume daily-reportfacilio vibe jobs delete <name> (alias rm)#
Remove the job and cancel its scheduler row.
facilio vibe jobs delete daily-reportFailure model — keep it simple#
- A failed fire keeps firing on schedule. No exponential backoff, no max-retries pause — the job stays
activeand fires again next slot.LAST_RUN_STATUS+LAST_RUN_ERRORon the row (visible viajobs get) record the last outcome. - Broken job? Pause it manually.
facilio vibe jobs pause <name>. Fix the function or the payload, thenresume. - Wall-clock timeout hits? The runner is cancelled with an interrupt, the fire is recorded as
failed: timed out after Ns, and the job reschedules to its next slot as usual.
Common rejection reasons#
| Message | Cause |
|---|---|
intervalSeconds must be at least 900 | Interval schedule shorter than 15 min. |
cronExpression must schedule fires at least 15 minutes apart | Cron expression whose consecutive slots are too close. |
timeoutSeconds must be at most 900 | Timeout above the 15-min ceiling. |
function '<name>' not found in app <linkName> | Function doesn't exist. Build it first. |
app has no public user provisioned | Legacy app that predates the public-user feature — redeploy the app to provision one. |
job '<name>' already exists in app <linkName> (409) | Job name isn't unique per app. Pick a different name or update the existing one. |
3. Connections commands#
Facilio Connections is Facilio's integration layer: a catalog of 1000+ external apps (Xero, Salesforce, HubSpot, Slack, …) and 5000+ actions across them, all callable through one authenticated interface. From the CLI, you can discover actions, authorize accounts, and run those actions directly — using the same facilio login session you use for Vibe.
Every Connections command lives under facilio connections <cmd>. The typical loop is:
search— find actions by natural-language description ("create xero invoice").schemas— look up the input/output JSON Schemas for the actions you found.link— authorize the account (once per connection per user).execute— run the action with a JSON payload.
list, unlink, and wait are used less frequently to inspect and manage connected accounts.
Global flags#
These flags apply to every facilio connections <cmd> invocation:
| Flag | Notes |
|---|---|
--mcp-url <url> | Override the Connections MCP endpoint. Defaults to FACILIO_MCP_URL / the region default. |
--app <slug> | Scope every call to one connection (uses the /<slug>/mcp endpoint). Faster than searching across all 1000+ apps when you already know which one you're targeting. |
--json | Print raw JSON payloads. Use in scripts and agents. |
facilio connections search#
Find actions by use case. The query is free-form natural language; the server ranks matching actions across every connection.
facilio connections search create xero invoicefacilio connections search list open workorders --app facilio-cmmsfacilio connections search send slack message --jsonReturns action slugs of the form <connection>.<action> (e.g. xero.create_invoice). Use those slugs with schemas and execute.
facilio connections schemas <action_slugs...>#
Show the input (and optionally output) JSON Schemas for one or more actions.
facilio connections schemas xero.create_invoicefacilio connections schemas xero.create_invoice salesforce.create_lead --with-output| Flag | Notes |
|---|---|
--with-output | Also fetch the output schema so you know how to parse the response. |
Feed the input schema to an LLM or read it yourself to build the --params payload for execute.
facilio connections list <connections...> (alias ls)#
Show your connected accounts for one or more connections. Use to check whether you've already authorized an app and to look up the account_slug for execute --account.
facilio connections list xerofacilio connections list xero salesforce hubspotfacilio connections link <connection>#
Authorize a connection. Opens the OAuth URL for the target app in your browser (or prints it, so you can complete the auth on another device).
facilio connections link xerofacilio connections link salesforce --wait --timeout 120facilio connections link hubspot --no-open # prints the URL only| Flag | Notes |
|---|---|
--no-open | Don't auto-open the browser. Useful on headless machines. |
--wait | Block until the connection becomes ACTIVE. |
--timeout <seconds> | With --wait, give up after this many seconds. |
facilio connections unlink <connection>#
Remove your authorization for a connection. Prompts to confirm.
facilio connections unlink xerofacilio connections unlink xero --yes # skip confirmationfacilio connections wait <connections...>#
Poll until one or all of the named connections become ACTIVE. Handy after link --no-open when the OAuth handshake happens on a different device.
facilio connections wait xerofacilio connections wait xero salesforce --mode all --timeout 300| Flag | Notes |
|---|---|
--mode <mode> | any (default — exit as soon as one becomes active) or all (wait for every named connection). |
--timeout <seconds> | Give up after this many seconds. |
facilio connections execute [action_slugs...] (alias exec)#
Run one or more actions. Pass the JSON payload with --params — repeat --params once per slug to run several actions in parallel.
# Run one actionfacilio connections execute xero.create_invoice --params '{"amount":100,"contactId":"abc"}'
# Read the payload from stdin (safer for secrets and long payloads)cat payload.json | facilio connections execute xero.create_invoice --params -
# Target a specific connected account (from `connections list`)facilio connections execute xero.create_invoice --params '{"amount":100}' --account xero-us
# Validate without executing — prints the request that would be sentfacilio connections execute xero.create_invoice --params '{"amount":100}' --dry-run
# Just show the input schema and exit (equivalent to `connections schemas`)facilio connections execute xero.create_invoice --get-schema
# Batch mode — read {action_slug, arguments, account_slug?} tuples from a JSON filefacilio connections execute --file batch.json
# Run multiple actions in parallel — one --params per slug, in orderfacilio connections execute xero.create_invoice salesforce.create_lead \ --params '{"amount":100}' \ --params '{"name":"Acme"}'| Flag | Notes |
|---|---|
--params <json> | Action arguments as a JSON object. Use - to read from stdin. Repeat once per slug to run several actions in parallel. |
--account <slug> | Target a specific connected account (from facilio connections list). Only relevant when you have multiple accounts for the same connection. |
--file <path> | Batch mode. Reads a JSON array of {action_slug, arguments, account_slug?} objects. |
--dry-run | Validate arguments against the action schema and print the request without executing. |
--get-schema | Print the input schema for the given action slugs and exit — no execution. |
Common errors#
| Error | Cause | Fix |
|---|---|---|
Not logged in | No token in the OS keychain or file fallback | Run facilio login |
vibe.json not found | Running facilio vibe deploy outside the project root | cd into the project root, or run facilio 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 facilio vibe app create for an app that already exists | Skip this step; subsequent deploys use vibe.json |
Env vars#
All env vars use the FACILIO_ prefix. Legacy VIBE_ names from the old @facilio/vibe-cli are still honored as silent fallbacks so existing setups keep working.
| Variable | Purpose |
|---|---|
FACILIO_API_KEY | Log in via API key without the browser flow. Set once and every command authenticates from it. Preferred for CI. |
FACILIO_REGION | Region key for API-key logins (US, UK, AE, AU, …). Resolves the right server URLs. Defaults to US. |
FACILIO_NO_KEYCHAIN | Set to 1 / true / yes to skip the OS secret store and use ~/.facilio/credentials.json (0600) instead. Useful in CI without a session keyring. |
FACILIO_VIBE_SERVER_URL | Override the vibe-server API URL. Defaults to the server picked at login. |
FACILIO_IDENTITY_SERVER_URL | Override the identity-service base URL. Defaults are set per environment. |
FACILIO_CONNECTIONS_SERVER_URL | Override the Connections MCP endpoint. Overridable per-command via --mcp-url. |
FACILIO_CLIENT_ID | Override the OAuth client id. |
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/cli 2>/dev/null || echo "Falling back to npx"
# 3. Authenticate — ONLY step where a human clicks oncefacilio login
# 4. Create the appfacilio vibe app create
# 5. Edit src/ to use createVibe(), executeAction(), etc.
# 6. Build and deploynpm run build && facilio vibe deploySee Getting Started for the walkthrough with code, and Building with AI Agents for the full agent recipe.