fusebase-cli
Skill9 starsChanged 27 days agoMITView on GitHub
Complete guide for using the Fusebase CLI (fusebase) tool to initialize, develop, and deploy Fusebase Apps apps. Use when: 1. Initializing new Fusebase Apps projects, 2. Creating or configuring apps, 3. Running apps locally or deploying them 4. Setting up app permissions for dashboards.
- Reads credentials
- Installs packages
In this repository119 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- .cursor/rules/fusebase-flow-always.mdcCursor rule
- .cursor/rules/fusebase-flow-implementation.mdcCursor rule
- .cursor/rules/fusebase-flow-security.mdcCursor rule
- .cursor/rules/fusebase-flow-specs.mdcCursor rule
- .cursor/rules/fusebase-flow-validation.mdcCursor rule
- api-explorationSkill
- app-api-contract-testingSkill
- app-backendSkill
- app-business-docsSkill
- app-dev-practicesSkill
- app-e2e-testsSkill
- app-quality-patternsSkill
- app-routingSkill
- app-secretsSkill
- app-sidecarSkill
- app-ui-designSkill
- business-logic-guardianSkill
- client-vs-internalSkill
- code-reviewSkill
- comment-policySkill
- communicationSkill
- design-discovery-ideationSkill
- dev-debug-logsSkill
- documentation-budgetSkill
- file-uploadSkill
- find-wasted-codeSkill
- find-wasted-effortSkill
- fusebase-dashboardsSkill
- fusebase-flow-health-checkSkill
- fusebase-gateSkill
- fusebase-portal-specific-appsSkill
- git-history-diagnosticSkill
- git-workflowSkill
- handling-authentication-errorsSkill
- handoffSkill
- implementation-planningSkill
- invite-with-passwordSkill
- lightweight-laneSkill
- liveness-disciplineSkill
- managed-integrationsSkill
- mcp-gate-debugSkill
- module-size-disciplineSkill
- north-starSkill
- phase-auditSkill
- product-apps-decompositionSkill
- product-docs-firstSkill
- product-ownerSkill
- project-onboardingSkill
- release-deploy-reportingSkill
- remote-logsSkill
- repo-onboarding-context-mapSkill
- requirements-specificationSkill
- role-disciplineSkill
- security-permissions-reviewSkill
- skill-authoringSkill
- smoke-testingSkill
- task-delegationSkill
- The first 60 shown.
The file
Show its rules and text
We split this skill into the rules it gives an agent
28 rules. About 0 are common, 7 are distinctive, and 21 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈7
Distinctive · estimate
This author's own choices. Worth a look.
21
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 28
Before using the CLI, authenticate with your API key:
- Very specific: line 38
Every Fusebase Apps project requires a fusebase.json file in the project root.
- Very specific: line 102
Only use app update --permissions when:
- Very specific: line 108
Do NOT: use app update to set permissions that should have been set at creation time.
- Distinctive: line 145
Create a new app with the specified name
- Distinctive: line 149
If the current directory is not empty and you decline the confirmation prompt, initialization stops without creating the app or local …
- Very specific: line 195
Use fusebase init --git to run the same flow automatically after app setup.
- Distinctive: line 223
When debugging local runtime issues after starting the dev server, load skill dev-debug-logs.
- Distinctive: line 271
Update settings for an existing app.
- Very specific: line 296
If that output carries a !
- Very specific: line 377
use --skip-product to force CLI-only mode even inside an app directory.
- Very specific: line 397
Default Dashboards MCP grants (see lib/mcp-token-policy.ts): discover/read existing dashboards, write row data (data.write), write …
- Very specific: line 420
If an app has an isolated SQL store (isolatedStores.sql[]), deploy also provisions it in the target env — create-or-get the store, apply …
- Very specific: line 438
When converting an existing app, follow the local guide App Environment Migration Guide: normalize fusebase.json, run fusebase env init …
- Very specific: line 452
Add a custom MCP by URL (checks reachability with HTTP GET unless --skip-check):
- Very specific: line 493
After declaring the secrets, run fusebase deploy (or fusebase dev start).
- Very specific: line 565
Use this for app-owned isolated SQL schema work.
- Distinctive: line 596
When debugging isolated-store access:
- Very specific: line 598
call Gate me / whoami first and use the actual resolved client scope.
- Very specific: line 600
if runtime SQL or migration status/apply fails with 403 Token cannot access isolated store, check for a missing sourceScopes entry before …
- Very specific: line 601
if authorized, fix by adding the exact resolved client scope with attachIsolatedStoreSourceScope.
- Very specific: line 603
Do not attach a guessed child app id when whoami shows a different product/client scope.
- Very specific: line 721
After changing app code, run fusebase app update <appId> if any of these need to be updated:
- Very specific: line 728
If runtime code calls other apps via Gate AppApisApi.callAppApi(...), refresh local cross-app dependency metadata and optionally sync it:
- Very specific: line 749
Use the unresolved/manual flow when AppApisApi.callAppApi(...) is dynamic by design and static analysis cannot resolve the target operation.
- Very specific: line 791
Run fusebase auth to set your API credentials.
- Distinctive: line 795
Ensure the app is:
- Very specific: line 809
All dependencies are installed in the app directory (npm install --include=dev)
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Fusebase CLI (fusebase)
This skill describes how to use the Fusebase CLI tool to manage and deploy Fusebase Apps apps.
For environment migrations, pair this skill with the local project guides App Environments Guide and App Environment Migration Guide. When e2e tests are part of the work, also load skill app-e2e-tests and local guide E2E Playwright Setup Guide; when backend runtime env or Gate access is involved, also load app-backend and fusebase-gate as applicable.
Overview
The Fusebase CLI (fusebase) is a command-line tool for:
- Initializing new Fusebase Apps projects
- Managing app development with hot reload
- Deploying apps to the Fusebase platform
Installation & Authentication
The fusebase CLI is installed globally. Always invoke it as fusebase <command> — never use npx fusebase.
Before using the CLI, authenticate with your API key:
fusebase authThis stores credentials in ~/.fusebase/config.json.
Project Configuration (fusebase.json)
Every Fusebase Apps project requires a fusebase.json file in the project root. This file defines the app and its apps.
For details on the fusebase.json schema, see references/fusebase-json-schema.md.
Declarative manifest — never invent an app id
apps[] is declarative: an app entry carries subdomain + name and omits the
platform app id. fusebase deploy reconciles each entry against the platform — it binds
to the app with a matching subdomain, or creates it if missing. The product id
(productId) is always required; only the per-app id is omitted.
⚠️ Never invent or hand-write an
apps[].id. The platform owns app ids. Writing your ownidand then runningfusebase app createcauses a double-registration conflict — the platform creates a brand-new app whose id no longer matches the one you wrote. Add a declarative record (noid) and runfusebase deploy(orfusebase app create); old apps that already carry a realidkeep working unchanged.
Canonical declarative app record (add this to apps[] by hand — note: no id):
{
"subdomain": "my-app",
"name": "My App",
"path": "apps/my-app",
"dev": { "command": "npm run dev" },
"build": { "command": "npm run build", "outputDir": "dist" }
}App Permissions
Apps can have permissions that define which dashboard views they can access. This is required when creating apps that interact with specific dashboards.
Permission Format
Permissions are specified as a semicolon-separated string:
dashboardView.dashboardId:viewId.privileges[;dashboardView.dashboardId2:viewId2.privileges2;...]Where:
dashboardView- The permission type (currently onlydashboardViewis supported)dashboardId- The dashboard's global ID (UUID from MCP or Fusebase UI)viewId- The view's global ID (UUID from MCP or Fusebase UI)privileges- Comma-separated:read,write, orread,write
Setting Permissions
Always set permissions during app creation using --permissions. This is the correct time — do not skip it and do app update later.
fusebase app create --name="Sales Report" --subdomain=sales-report --path=apps/sales-report --dev-command="npm run dev" --build-command="npm run build" --output-dir=dist --permissions="dashboardView.dash123:view456.read,write"Only use app update when changing existing permissions (e.g. adding a new view, changing privileges):
fusebase app update <appId> --permissions="dashboardView.dash123:view456.read;dashboardView.dash789:viewABC.read,write"When to Use app update for Permissions
Only use app update --permissions when:
- App already exists and needs access to additional dashboard views
- Changing from read-only to read-write (or vice versa) on an existing app
- Restricting access to fewer views on an existing app
Do NOT use app update to set permissions that should have been set at creation time.
CLI Commands
Version
fusebase version # Print CLI version (from package.json)
fusebase -V # SameInitialize a New Project
fusebase init [options]Options:
--name <name>- App title/name (if not provided, will prompt interactively)--org <orgId>- Organization ID (skips org selection if provided)--ide <preset>- IDE preset:claude-code,cursor,vscode,opencode,codex, orother(single choice; generates all supported IDE configs by default)--force- Overwrite existing IDE config files/folders--git- After setup, initialize local Git and sync with configured GitLab remote (creates/uses remote project, configuresorigin, pushes current branch)--skip-git- Skip local Git initialization and GitLab sync (overrides both--gitand globalgit-init)--git-tag-managed- If app is managed, addmanagedtopic in GitLab during sync- In interactive init, CLI also shows a suggested GitLab repository name and lets you edit it before sync
- Global flag
git-initalso enables the same post-init Git offer automatically (fusebase config set-flag git-init) - Global flag
git-debug-commitsenables strict debug/deploy traceability section in thegit-workflowskill (deploy preflight, commit-per-fix, SHA/tag references) - Global flag
app-business-docsincludes theapp-business-docsskill (Englishdocs/en/business-logic.mdmaintenance) - Global flag
mcp-gate-debugincludes themcp-gate-debugskill (post–Gate MCP debug summary; isolated stores emphasis) - Global flag
isolated-storesenables isolated stores functionality (SQL/NoSQL), including required Fusebase Gate references andisolated_store.*permissions infusebase env create - Global flag
portal-specific-appsincludes portal-specific prompts/guidance (fusebase-portal-specific-appsskill,{{CurrentPortal}}filter references, and/auth/contextportal runtime context notes)
This command always creates a new app on Fusebase and initializes the project. It will:
- Prompt for organization selection (or use
--orgif provided) - Create a new app with the specified name
- Generate
fusebase.jsonconfiguration - Set up the basic project structure with template files
If the current directory is not empty and you decline the confirmation prompt, initialization stops without creating the app or local config.
Examples:
# Initialize interactively (prompts for all values)
fusebase init
# Initialize with app name specified
fusebase init --name="My App"
# Initialize with all options (fully non-interactive, assumes single org)
fusebase init --name="My App" --org=org_abc123Local Git and GitLab sync (optional)
fusebase git
fusebase git sync [--git-tag-managed]fusebase git runs local git init and ensures a baseline .gitignore with common ignores (node_modules/, dist/, .env files, logs, caches, OS/IDE noise).
fusebase git sync connects the current local repo to GitLab (from global config in ~/.fusebase/config.json) and pushes the current branch.
Equivalent flag form: fusebase git --git-sync (with optional --git-tag-managed).
To configure GitLab values in global CLI config:
fusebase config gitlab
fusebase config gitlab --show
fusebase config gitlab --host gl.nimbusweb.co --group vibecode --token glpat_xxx
fusebase config gitlab --clear-tokenRequired global config keys in ~/.fusebase/config.json:
gitlabHostgitlabTokengitlabGroup
GitLab repo naming:
- Format:
app-<base>-<env> - Base priority: app title (with Cyrillic transliteration fallback) → current folder name → app subdomain
Use fusebase init --git to run the same flow automatically after app setup.
Development Mode
Start the Dev Server
fusebase dev start [FEATURE_ID_OR_PATH]FEATURE_ID_OR_PATH - id of the app of relative path to it, for example if an app is in apps/my-app, you can pass my-app or apps/my-app.
Starts the development environment:
- UI Server (port 4173): Displays apps in iframes for testing
- API Proxy (port 4174): Proxies API requests with authentication
The dev server automatically:
- Injects your API credentials
- Delivers app tokens to iframes via
postMessage - Refreshes tokens when apps are selected
- Creates per-session debug logs under the selected app directory's
logs/dev-<timestamp>/:browser-logs.jsonlaccess-logs.jsonlbackend-logs.jsonlfrontend-dev-server-logs.jsonl
When debugging local runtime issues after starting the dev server, load skill dev-debug-logs. It explains which file to inspect for browser errors, proxied API traffic, frontend dev server output, and backend output.
Create and Configure App
fusebase app create --name <name> --subdomain <subdomain> --path <path> --dev-command <command> --build-command <command> --output-dir <dir> [options]This command always creates a new app on Fusebase servers and configures its development parameters. All six core options are required.
Required Options:
--name <name>- Name for the new app--subdomain <subdomain>- Subdomain for the app (e.g.,my-app); the app is served from the root of this subdomain--path <path>- Relative path to the app directory (e.g.,apps/my-app)--dev-command <command>- Dev server command (e.g.,npm run dev)--build-command <command>- Build command (e.g.,npm run build)--output-dir <dir>- Build output directory (e.g.,dist)
Optional Options:
--access <principals>- Set access principals, comma-separated (e.g.,visitor,orgRole:member,visitor,orgRole:guest)--permissions <permissions>- Set dashboard view permissions (format:dashboardView.dashboardId:viewId.read,write;...). Entries that are Gate privileges instead — e.g.app_api.<namespace>.<capability>.<action>ororg.members.read— are added to the app's Gate permissions rather than replacing them.--backend-dev-command <command>- Backend dev command (e.g.,npm run dev). Only if the app has abackend/folder.--backend-build-command <command>- Backend build command (e.g.,npm run build). Only if the app has abackend/folder.--backend-start-command <command>- Backend start command for production (e.g.,npm run start). Only if the app has abackend/folder.--coding-agent <name>- Coding agent identifier (e.g.claude_code,cursor,copilot,codex). Populate this field with your name.--model <name>- Model identifier (e.g.claude-opus-4-6,gpt-5). Populate this field with the model name currently used.
Examples:
# Create an app
fusebase app create --name="Dashboard Widget" --subdomain=dashboard-widget --path=apps/dashboard --dev-command="npm run dev" --build-command="npm run build" --output-dir=dist
# Create app with permissions for specific dashboard views
fusebase app create --name="Sales Report" --subdomain=sales-report --path=apps/sales-report --dev-command="npm run dev" --build-command="npm run build" --output-dir=dist --permissions="dashboardView.dash123:view456.read,write;dashboardView.dash789:viewABC.read"
# Create app with a backend
fusebase app create --name="My App" --subdomain=my-app --path=apps/my-app --dev-command="npm run dev" --build-command="npm run build" --output-dir=dist --backend-dev-command="npm run dev" --backend-build-command="npm run build" --backend-start-command="npm run start"Update App Settings
fusebase app update <appId> [options]Update settings for an existing app.
Options:
--access <principals>- Set access principals, comma-separated (e.g.,visitor,orgRole:member,visitor,orgRole:guest)--permissions <permissions>- Set dashboard view permissions (format:dashboardView.dashboardId:viewId.read,write;...). Entries that are Gate privileges instead — e.g.app_api.<namespace>.<capability>.<action>ororg.members.read— are added to the app's Gate permissions rather than replacing them.--sync-gate-permissions- Analyze Gate SDK calls in the app's runtime code and sync the detected operations as Gate permissions on the app. It merges with the privileges already granted, so a hand-granted capability such asapp_api.<ns>.<cap>.<action>survives a sync. Required before an app that uses@fusebase/fusebase-gate-sdkcan be considered fully published.--prune-gate-permissions- Revoke Gate privileges outside the analyzed set. This is the only way to remove a granted privilege; it prints every removal and also prunes it fromfusebase.jsonso the next deploy does not re-grant it. Requires--sync-gate-permissionsand cannot be combined with--permissions.
Access Principals:
The --access option replaces the entire access principal list. Always run
fusebase app get <appId> first — it is read-only and prints the current
principals in the same syntax, so you can see what the overwrite would drop
instead of silently locking people (or production) out. Add --json for the
raw payload when you want to snapshot the grants first.
fusebase app get аgjg851jguanadi41
# My App
# ID: аgjg851jguanadi41
# URL: https://.../my-app
# Access: visitor, orgRole:memberIf that output carries a ! line, the app has principals --access cannot
express (user:<id>, orgGroup:<id>, granted from the UI). Running
app update --access at all would revoke them — change those grants in the UI.
Principals are comma-separated entries of the form type or type:id:
| Principal | Example | Description |
visitor | visitor | Any unauthenticated visitor (public access). |
orgRole:<id> | orgRole:member | Org members with the given role. Valid ids: guest, client, member, manager, owner. |
portalMember | portalMember | Member of the portal the app is embedded in (portal-scoped, no id). |
portalManager | portalManager | Portal member who is an org manager/owner (portal-scoped, no id). |
portalClient | portalClient | Portal member who is an org client (portal-scoped, no id). |
Portal principals are context-relative: they only match when the app is opened from inside a portal; outside a portal they never match.
Permissions:
The --permissions option specifies which dashboard views the app can access and with what privileges.
Format: dashboardView.dashboardId:viewId.privileges separated by semicolons for multiple views.
dashboardView- The permission type (required prefix)dashboardId- The dashboard's global ID (UUID)viewId- The view's global ID (UUID)privileges- Comma-separated list:read,write, orread,write
Examples:
# Make an app publicly accessible (visitor = any unauthenticated user)
fusebase app update аgjg851jguanadi41 --access=visitor
# Allow org members only
fusebase app update аgjg851jguanadi41 --access=orgRole:member
# Allow multiple roles
fusebase app update аgjg851jguanadi41 --access=orgRole:member,orgRole:client
# Public + org members
fusebase app update аgjg851jguanadi41 --access=visitor,orgRole:member
# Portal-embedded app: only clients and managers of the embedding portal
fusebase app update аgjg851jguanadi41 --access=portalClient,portalManager
# Remove all access principals (pass empty string), it will allow access for every role in organization, but not for visitors
fusebase app update аgjg851jguanadi41 --access=""
# Grant read access to a single dashboard view
fusebase app update аgjg851jguanadi41 --permissions="dashboardView.dashABC:view123.read"
# Grant read/write access to multiple views
fusebase app update аgjg851jguanadi41 --permissions="dashboardView.dash1:view1.read,write;dashboardView.dash2:view2.read"
# Update both access and permissions
fusebase app update аgjg851jguanadi41 --access=visitor --permissions="dashboardView.dash1:view1.read"
# Grant an app API capability so this app may call another app's protected operation
fusebase app update аgjg851jguanadi41 --permissions="app_api.analytics.vse_usage.read"The grant is written back into apps[].permissions in fusebase.json — commit it. Deploy
rebuilds the app's permissions from fusebase.json, so a grant that lives only on the remote
app record is reverted by the next fusebase deploy.
App API policy extensions (
x-fusebase-allowed-callers,x-fusebase-required-permissions) are published and read bycallAppApi, but enforcement is switched on per environment by the platform. Grant the capability now so it is durable and in place when enforcement reaches your environment, but do not rely on the extensions as your only authorization check. A caller id inx-fusebase-allowed-callersis the calling project'sproductId(client:<productId>), not an app id.
Smart update (fusebase update)
fusebase updateSingle update command for both CLI and app:
- in app directory (
fusebase.jsonexists): runs CLI self-update first (skip with--skip-cli-update; local linked/source mode auto-skips), then optional pre-update Git checkpoint, then refreshes agent assets (AGENTS.md,.claude/skills,.claude/agents,.claude/hooks,.claude/settings.json), then runs selective MCP token refresh + IDE MCP config refresh, then syncs managed SDK deps and runs targetednpm install, then optional post-update Git commit when the tree is dirty (always prints changed paths); - outside app directory: runs only CLI self-update;
- use
--skip-productto force CLI-only mode even inside an app directory; --skip-commit/--commitgate both pre- and post-update Git checkpoints.
On Windows the CLI self-update is a cache swap (updates the cached CLI under %LOCALAPPDATA%\FuseBase\CLI\ with no admin elevation and no installer download), so the remaining app stages continue in the same run — just like macOS/Linux.
Windows launcher commands:
fusebase update --launcher— refreshes the stable launcherfusebase.exevia the elevated installer (the only path that prompts for admin). Windows-only; a no-op on macOS/Linux. Run it when the CLI tells you the launcher is too old, or when prompted by the non-blocking "A launcher update is available" nudge.fusebase --previous-version <cmd>— runs the retained previous cached CLI version for that one invocation (escape hatch when a new version misbehaves or a launcher gate is blocking). The next normal run goes back to the active version.
Create or update .env (MCP token)
fusebase env createCreates or overwrites .env with DASHBOARDS_MCP_TOKEN and DASHBOARDS_MCP_URL. Use after fusebase init or when the MCP token has expired. Requires fusebase.json (with orgId) and fusebase auth to be set.
On successful create/update, CLI refreshes both Dashboards and Gate MCP tokens. In interactive terminals, it offers to run fusebase config ide --force immediately for all IDE MCP configs; if declined, it prints that command as the next step.
Default Dashboards MCP grants (see lib/mcp-token-policy.ts): discover/read existing dashboards, write row data (data.write), write relations (relation.write), and mutate existing view schema (view.write). It does not create or delete dashboard DBs/dashboards unless the global flag legacy-dashboards-db is enabled.
App environments (experimental, flag environments)
Named environment profiles let one project target several platform contexts
(e.g. prod customer org, prod-beta beta stage, dev org on the dev
platform). Per environment: environments/<name>.json (committed lockfile —
backend, org, product, resolved app ids, per-env subdomains, store ids,
test-user fixtures, protected marker) plus a gitignored .env.<name>
(MCP tokens/secrets); the active env's dotenv is materialized into .env.
fusebase env init # adopt: current context becomes the first env
fusebase env add dev --backend dev --org <orgId>
fusebase env use dev # switch (offers re-auth + token refresh, and an
# IDE MCP config refresh when they hold the old env's tokens)
fusebase env list # envs, backends, auth state
fusebase env status # active env: ids resolved? tokens fresh? IDE MCP configs in sync?
fusebase env tokens # write MCP tokens into .env.<active>
fusebase deploy --env dev # first deploy bootstraps product/apps + provisions stores
fusebase env provision-store --env dev # (also run by deploy) create store, migrate, verify RLSIf an app has an isolated SQL store (isolatedStores.sql[]), deploy also
provisions it in the target env — create-or-get the store, apply migrations,
verify RLS, and record the storeId in the lockfile — so a fresh env never
serves code against a missing database. Store aliases are unique per org, so the
Gate-side alias is env-suffixed automatically; your app code and the lockfile
keep the logical alias. Provision by hand with fusebase env provision-store, or
skip it with fusebase deploy --skip-store-provision.
Any command accepts --env <name>; CI can use FUSEBASE_ENV +
FUSEBASE_API_KEY. Auth is per backend: fusebase auth --dev and
fusebase auth store separate keys. Never copy platform ids between
environment files — deploy reconcile resolves and records them.
Deployed bundles include fusebase-env.json; the template's EnvPanel
component (?envpanel=1) shows the current stage (red PROD badge for
protected envs) with links to counterpart deployments, and tests can read it
to assert they target the intended stage.
When converting an existing app, follow the local guide App Environment
Migration Guide: normalize fusebase.json, run fusebase env init --strip,
add/clone non-prod envs, remove hardcoded backend/org/app ids from runtime
code, then add readonly e2e smoke tests and CI.
Configure optional MCP integrations
fusebase integrationsThis runs an interactive step to enable/disable optional MCP servers from the CLI integrations catalog and any custom HTTP MCP servers listed under fusebase.json → mcpIntegrations.custom.
required: true servers are always enabled when you run this command.
Add a custom MCP by URL (checks reachability with HTTP GET unless --skip-check):
fusebase integrations add <name> --url <url> [--type http] [--token <token>]
<% if (it.flags?.includes("managed-integrations")) { %>
fusebase integrations list-templates # list Gate MCP manager templates using app .env token
fusebase integrations connect-template --template-name <template-name>
<% } %>
fusebase integrations disable <name> # keep fusebase.json; remove from IDE configs
fusebase integrations enable <name>
fusebase integrations remove <name> # or: deleteDuring fusebase init, only required MCP servers (per the catalog, respecting flags) are written to IDE configs; run fusebase integrations afterward to add optional servers.
Create App Secrets
fusebase secret create --app <appPath> --secret <KEY:description> [--secret ...]Declares secret keys for an app in fusebase.json. This is a local file edit only — no network call, and no URL is printed. The keys are created on the platform (with empty values) by the next fusebase deploy / fusebase dev start, which prints the URL where you set the actual values.
Required Options:
--app <appPath>- App path (fromapps[].pathinfusebase.json) to create secrets for.--featureis accepted as a deprecated alias.--secret <KEY:description>- Secret to create. Format:KEYorKEY:description. Repeatable — pass multiple--secretflags to create several secrets at once.
Examples:
# Create a single secret
fusebase secret create --app apps/my-app --secret "API_KEY:Third-party API key"
# Create multiple secrets at once
fusebase secret create --app apps/my-app \
--secret "API_KEY:Third-party API key" \
--secret "DB_PASSWORD:Database connection password" \
--secret "WEBHOOK_SECRET"After declaring the secrets, run fusebase deploy (or fusebase dev start). When it registers new keys it prints https://{org-domain}/dashboard/{orgId}/apps/features/{appId}/secrets — open that URL to fill in the actual secret values. Nothing is printed if the keys already exist on the platform.
Scaffold an App
Scaffold a new app from a built-in template.
# List available templates (with descriptions)
fusebase scaffold
# Scaffold a template into a directory
fusebase scaffold --template <templateId> --dir <path>Available templates:
| Template | Description |
spa | React + Vite SPA — scaffolds directly into <dir> |
backend | Node.js + Hono backend — scaffolds into <dir>/backend/ |
Rules:
- Errors if any files in the target directory would be overwritten (no partial writes).
- The
backendtemplate can be scaffolded on top of an existing SPA — only thebackend/subfolder must be absent.
Then implement the app. After the code is complete, register and start dev — execute these automatically, do NOT list them as "next steps" for the user:
# Register the app (derive name/subdomain from context)
# add --permissions if dashboard access is needed
fusebase app create \
--name="<App Name>" \
--subdomain=<app-sub> \
--path=apps/<name> \
--dev-command="npm run dev" \
--build-command="npm run build" \
--output-dir=dist \
--coding-agent=<agent> \
--model=<model>
# Start the dev server
fusebase dev start apps/<name>Deploy Apps
fusebase deployDeploys all apps to Fusebase:
- Installs dependencies and runs lint for each app (if the app has a
lintscript inpackage.json) - Runs each app's build command
- Uploads the built files from
outputDir - Activates the new version on Fusebase
Options:
--force— ignore hash matches and re-upload + redeploy every app--app <subdomain|id|name|path>— deploy only the matching app--nocode— only reconcile infrastructure (bind/create apps on the platform), skip code deployment--skip-store-provision— skip automatic isolated-store provisioning (env mode)
The project template includes ESLint (npm run lint) and root npm run typecheck (TypeScript across apps — catches errors ESLint does not). Run both before saying "Done" so deploy succeeds; see AGENTS.md "Final Gate". Claude Code runs lint and typecheck on Stop via .claude/settings.json hooks.
Isolated SQL Bundle / RLS Manifest
fusebase isolated-store sql bundle --app <appPath> [--alias <alias>] [--stage dev|prod] [--json|--status|--dry-run|--apply --yes]Use this for app-owned isolated SQL schema work. It reads apps[].isolatedStores.sql[] from fusebase.json, loads postgres/migrations/manifest.json, and computes Gate-canonical checksums from SQL file bytes.
RLS manifest forwarding is experimental. To attach rlsManifest from either rlsManifestFile, inline config, manifest rlsManifest, or postgres/migrations/rls-manifest.json, enable:
fusebase config set-flag postgres-rlsExamples:
fusebase isolated-store sql bundle --app apps/client-portal --json
fusebase isolated-store sql bundle --app apps/client-portal --stage dev --status
fusebase isolated-store sql bundle --app apps/client-portal --stage dev --dry-run
fusebase isolated-store sql bundle --app apps/client-portal --stage dev --apply --yesGate calls use GATE_MCP_TOKEN from .env. Do --status and --dry-run before any real --apply. --stage defaults to the active environment's backend, so FUSEBASE_ENV=prod targets the prod stage — pass --stage only to override it.
CI store contract. --status/--rls-status report; --assert-migrations/--assert-rls fail the build:
fusebase isolated-store sql bundle --app apps/<app> --assert-migrations --assert-rls--assert-migrations fails on pending migrations, a drifted journal, or a required baseline adoption. --assert-rls fails when the runtime role can bypass RLS (bypassRls/superuser) or when no data table carries a policy. Run this in CI alongside e2e: a Playwright spec cannot tell "RLS is working" from "this user has no rows", so a migration shipped without a policy would otherwise leave the suite green while the data is unprotected.
Gate MCP Token Scope
fusebase env create writes GATE_MCP_TOKEN to .env. For current apps-cli projects, the Gate MCP token is created with the project productId as its client scope, not necessarily with a child apps[].id.
When debugging isolated-store access:
- call Gate
me/whoamifirst and use the actual resolvedclientscope; - compare that value with the store
sourceScopes; - if runtime SQL or migration status/apply fails with
403 Token cannot access isolated store, check for a missingsourceScopesentry before changing migrations; - if authorized, fix by adding the exact resolved client scope with
attachIsolatedStoreSourceScope.
Do not attach a guessed child app id when whoami shows a different product/client scope. Do not recreate the store or rebaseline migrations just to fix a source-scope mismatch.
Manage Sidecar Containers
Sidecar containers are pre-built Docker images deployed alongside an app's backend container, sharing the localhost network namespace. Max 3 sidecars per app.
# Add a sidecar to an app backend
fusebase sidecar add \
--app <appPath> \
--name <name> \
--image <image> \
[--port <port>] \
[--tier small|medium|large] \
[--env KEY=VALUE ...] \
[--secret KEY|KEY:ALIAS ...]
# Remove a sidecar by name
fusebase sidecar remove --app <appPath> --name <name>
# List configured sidecars
fusebase sidecar list --app <appPath>--feature (-f) is accepted as a deprecated alias for --app (-a).
Options for sidecar add:
--name— unique name within the app (used for log filtering and identification)--image— Docker image reference (e.g.browserless/chrome:latest)--port— port the sidecar listens on (accessible via localhost from the backend)--tier— resource tier:small(default),medium, orlarge--env— environment variables as KEY=VALUE pairs (repeatable)--secret— whitelist an app secret key (registered viafusebase secret create) to inject into the sidecar as an env var, repeatable. UseKEYto expose the secret under its own name, orKEY:ALIASto rename it inside the sidecar. On collision between sidecarenvand a whitelisted secret key, the sidecar's staticenvvalue wins. Deploy fails with aValidationErrorlisting every missing key if a referenced secret is not registered for the app. See the app-sidecar skill ("Whitelisting Secrets") for details.
Sidecars are stored in fusebase.json under apps[].backend.sidecars[] and deployed on the next fusebase deploy.
Per-job sidecars (--job <jobName>):
Cron jobs declared under apps[].backend.jobs[] deploy as independent Azure Container Apps Jobs and do not share the backend container app's network namespace. To give a specific cron job its own auxiliary container (e.g. a headless browser used only by a screenshot cron), pass --job <jobName> to all three subcommands:
# Add a sidecar to a job
fusebase sidecar add --app <appPath> --job <jobName> \
--name <name> --image <image> [--port <port>] [--tier ...] [--env ...] [--secret ...]
# Remove a sidecar from a job
fusebase sidecar remove --app <appPath> --job <jobName> --name <name>
# List sidecars on a job
fusebase sidecar list --app <appPath> --job <jobName>When --job is omitted, all three subcommands target backend sidecars exactly as before. Each job has its own 3-sidecar cap, independent of the backend cap. Sidecar names are unique per scope — the same name (e.g. chromium) may exist on the backend and on a job. Per-job sidecars are stored under apps[].backend.jobs[].sidecars[] in fusebase.json and deployed on the next fusebase deploy. See the app-sidecar skill for full details (networking, termination, examples).
Remote Logs (Deployed Backends)
Fetch logs from deployed app backends. Only applicable to apps with a backend/ folder. Use this for production issues, NOT for local development (for local dev, see the dev-debug-logs skill).
Build Logs
fusebase remote-logs build <appId>Fetch the build image logs from the most recent deployment. Shows the container image build output.
Runtime Logs
fusebase remote-logs runtime <appId> [--tail <number>] [--type <console|system>]Fetch runtime logs from the deployed container.
Options:
--tail <number>- Number of log lines to fetch (default: 100, max: 300)--type <console|system>- Log type:consolefor app output,systemfor container system logs (default:console)
Examples:
# Get build logs for an app
fusebase remote-logs build abc123
# Get last 100 runtime console logs
fusebase remote-logs runtime abc123 --tail 100
# Get system logs (container lifecycle events)
fusebase remote-logs runtime abc123 --type systemCreating a New App
- Scaffold the app:
fusebase scaffold --template spa --dir apps/my-new-app(add--template backendfor a backend). - Implement the app code — write all source files, components, and logic.
Register and start dev — execute these automatically after the code is written; do NOT list them as "next steps" for the user:
a. Run
fusebase app create— include--permissionsnow if the app needs dashboard access (do not save it for a separateapp updatestep later):# Without dashboard access fusebase app create --name="My New App" --subdomain=my-new-app --path=apps/my-new-app --dev-command="npm run dev" --build-command="npm run build" --output-dir=dist --coding-agent=codex --model=gpt-5.4 # With dashboard view permissions (preferred: set at creation) fusebase app create --name="My New App" --subdomain=my-new-app --path=apps/my-new-app --dev-command="npm run dev" --build-command="npm run build" --output-dir=dist --permissions="dashboardView.dash123:view456.read,write" --coding-agent=claude_code --model=opus-4.7 # With a backend fusebase app create --name="My New App" --subdomain=my-new-app --path=apps/my-new-app --dev-command="npm run dev" --build-command="npm run build" --output-dir=dist --backend-dev-command="npm run dev" --backend-build-command="npm run build" --backend-start-command="npm run start" --coding-agent=copilot --model=sonnet-4.6This will create the app on Fusebase and add it to
fusebase.jsonb. Run
fusebase dev startto test locally
Updating an Existing App
After changing app code, run fusebase app update <appId> if any of these need to be updated:
--permissions— dashboard view access added, removed, or modified--access— access principals (visitor / org roles) changed--sync-gate-permissions— always include for apps using@fusebase/fusebase-gate-sdkat runtime
<% if (it.flags?.includes("cross-app-api-calls-analysis")) { %>
If runtime code calls other apps via Gate AppApisApi.callAppApi(...), refresh local cross-app dependency metadata and optionally sync it:
fusebase analyze app-apis --feature <appId>
fusebase analyze app-apis --feature <appId> --sync
# repair/reconciliation mode
fusebase analyze app-apis --feature <appId> --sync --forceTo author a consumer-contract draft for those resolved dependencies, then verify it centrally:
fusebase app-api-contracts unresolved --app <appId>
fusebase app-api-contracts add-manual-dependency --app <appId> --provider <providerAppId> --operation <operationId>
fusebase app-api-contracts scaffold --app <appId>
fusebase app-api-contracts validate --app <appId>
fusebase app-api-contracts publish --app <appId>
fusebase app-api-contracts verify-consumer --app <appId>
fusebase app-api-contracts verify-provider --app <providerAppId>Use the unresolved/manual flow when AppApisApi.callAppApi(...) is dynamic by design and static analysis cannot resolve the target operation.
Contracts are authored and validated locally but verified centrally — there is no local runtime verification command. Recommended flow: scaffold + validate (offline) while authoring, publish the validated contracts, then verify-consumer to confirm the published remote set. Run verify-provider for an org-wide provider regression check against the target deployed environment; it verifies the currently deployed provider runtime, not unpublished local changes.
validate is offline: it checks contract structure and dependency linkage only; it does not call the provider.
publish re-validates the consumer app's contracts (same checks as validate) and, only when they all pass, uploads the full set to central storage via the public API; the server replaces the stored set, so re-publishing is idempotent.
verify-consumer --app <consumerAppId> (optional --provider/--operation) and verify-provider --app <providerAppId> operate on the published central contract set, not local files. They call the public API (POST .../app-api-contracts/verify-consumer and .../verify-provider), which runs the verification engine centrally through Gate. verify-consumer covers one consumer's published contracts; verify-provider is the org-wide inbound check across every published consumer targeting that provider in the target deployed environment. Because they read the published set and call the deployed provider runtime, run publish after editing local contracts before re-verifying, and run verify-provider only after the provider version you want to check is deployed to that environment.
validate, verify-consumer, and verify-provider accept --json for machine-readable output in CI: human/colored output is suppressed, a single JSON document is printed to stdout, and a top-level ok flag mirrors the process exit code. publish is an action (not a check) and has no --json report; branch on its exit code.
<% } %>
# Update permissions and sync Gate permissions
fusebase app update <appId> --permissions="dashboardView.dash1:view1.read,write" --sync-gate-permissionsList Portal Embeds
fusebase app portal-embeds <appId>Lists portal pages in the current org where the app is embedded. Output includes portal name, page title when available, and URL. Empty results print No portal embeds found for this app..
Typical Workflow
fusebase auth- Authenticate (one-time setup)fusebase init- Initialize projectfusebase scaffold --template spa --dir apps/<name>- Scaffold app files (dependencies are installed automatically) 3a. Implement the app code- (after code is written)
fusebase app create --name="App Name" --subdomain=app-name --path=apps/app-name --dev-command="npm run dev" --build-command="npm run build" --output-dir=dist [--permissions="..."][--coding-agent=<agent> --model=<model>]- Register app; include--permissionsat this step if the app needs dashboard access. Always include--coding-agentand--model. Execute automatically — do NOT list as next steps for the user. 4a. (after registering)fusebase dev start- Start dev and test locally. Execute automatically. - (if app settings changed)
fusebase app update <appId> [--permissions="..."] [--sync-gate-permissions]- Sync updated settings before deploying fusebase deploy- Deploy to productionfusebase remote-logs build|runtime <appId>- Check logs if deployed app has issues (seeremote-logsskill for more)
Troubleshooting
"Not authenticated" error
Run fusebase auth to set your API credentials.
App not showing in dev server
Ensure the app is:
- Registered via
fusebase app create(so it exists in Fusebase andfusebase.json) - Added to
fusebase.jsonwith correctid - Has a running dev server (the
dev.commandprocess is up)
Build fails during deploy
Check that:
npm run lintpasses in the app directory (deploy runs lint before build)npm run typecheckpasses from project root (or fix TypeScript errors from the app’stscstep — ESLint alone may not report them)build.commandis correctbuild.outputDirexists after build- All dependencies are installed in the app directory (
npm install --include=dev)
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

