Getting started
Install ib-apps, create an app, and keep a folder on your computer in sync with its development environment.
Install the CLI
The CLI needs Node.js 20 or later.
npm i -g @inferencebureau/apps
ib-apps --helpThe app's Settings → API keys page shows the same commands.
Sign in
ib-apps login opens the dashboard in your browser. You approve the sign-in and pick a team; the CLI receives a session that acts as you in that team (OAuth with PKCE to a loopback address, so no key is copied anywhere). It is saved in your user config folder (~/.config/inferencebureau/apps.json, or under %APPDATA% on Windows), readable only by you. ib-apps logout revokes it.
In CI, skip login and set IB_API_KEY to a key linked to the app; it takes precedence over a saved sign-in. See API keys. IB_BASE_URL points the CLI at another API origin.
Create an app
Create one from the dashboard (Apps → New app, which then walks through setup) or from the terminal:
ib-apps create "Inference Bureau Wholesale" --platform shopify
cd inference-bureau-wholesale
ib-apps devcreate makes the app with its development environment and downloads the starter files into a new folder named after the slug. Creating apps needs a sign-in or a key with Apps Permissions. A web app starts as a Members app, or with --starter site as a site with no sign-in; --recipe <id> starts either platform's app from one of the example apps instead. create makes a custom Shopify app; a public one is created in the dashboard (choose Public on New app) or with POST /v1/apps and distribution: "public", then pulled. A Shopify app also needs its Shopify apps, which are created in the dashboard: see Connect to Shopify.
Sync with development
ib-apps dev syncs once, then watches the folder: local saves are pushed, and changes from the dashboard editor or a teammate are pulled every two seconds. For team owners and admins it also runs the dev server on your computer (below); otherwise a save under web/ is written straight into development's hosted dev server, which hot-reloads it. Either way it prints the address to open the app at. A save under extensions/ releases the storefront blocks to development's Shopify app.
While it runs, the dashboard's Terminal panel (in Logs) shows your computer as connected, with each file it sent and received.
- Conflicts. A file changed both here and on the server since the last sync is never overwritten. In a terminal you choose: keep yours, keep the server's, see a diff, or skip. Outside a terminal it is skipped; rerun with
--prefer localor--prefer remote. - What isn't synced.
.git,.ib,node_modules,.next,.vercel,.turbo,.DS_Store, files over 50 MiB, and anything listed in.ibignore(one entry per line; a bare name matches anywhere, an entry with a slash matches that path). - Limits. An environment holds up to 2,000 files, with paths up to 512 characters. A push carries up to 200 changes; the CLI splits bigger ones.
- Large files. Files over 1 MiB, up to 50 MiB (images, fonts, video), are uploaded to storage on their own, then pushed by their hash; the CLI does both. A file is stored once per team however many environments hold it, and counts toward storage at its size. Builds, the dev server and extension releases get its bytes as usual; the dashboard's editor shows it as binary.
- Sync state.
.ib/sync.jsonremembers the last synced version and hashes. Keep it out of git; the starter.gitignoredoes. Git is optional: the environments run from Inference Bureau's copy, not from a repository.
Run the dev server on your computer
Development has a hosted dev server that wakes when needed (Limits), and it serves everyone who isn't at a terminal: the dashboard editor and assistant, Preview, Shopify installs and webhooks, development schedules, a teammate opening the address. While you work, ib-apps dev runs the dev server on your own computer instead when you're a team owner or admin, so you get your debugger, your tools and no wake, and everything else stays the same: the app is still opened at its development address, actions, Shopify webhooks, the app proxy and jobs still reach it, and your folder still syncs both ways. When it can't (you're a member, no tunnel could be opened, next dev didn't start), it says so in one line and syncs with the hosted dev server as before.
ib-apps dev # on this computer when it can, else hosted
ib-apps dev --hosted # only sync; the hosted dev server serves the app
ib-apps dev --local # must run here; fails rather than falling back
ib-apps dev --port 3100
ib-apps dev --url https://my-tunnel.example.com # a tunnel you run yourself- What runs. The CLI mirrors your folder into
.ib/locallaid out as a build is (web/at the root,api/underib/) and takes the generated files from the server: the SDK, the actions registry and route, the Next.js config andpackage.json. Then it installs and runsnext devthere with the environment's variables. Every save updates the mirror, and a changedpackage.jsonreinstalls and restarts it. - How it's reached. A Cloudflare quick tunnel (downloaded once, no account) gives your computer a public address; pass
--urlto use a tunnel of your own. Visitors, Shopify and the API use the environment's own address as always; the tunnel's is only shown in your terminal. Every connection report (each 5 seconds) tells the server your computer is serving the environment. Ctrl-C (or closing the terminal) hands it back to the hosted dev server, and so does a minute without a report if the CLI is killed; the tunnel andnext devend with the CLI either way. The CLI also checks, every half minute and as soon as your computer wakes from sleep, that the tunnel still reaches it: a quick tunnel that closed while the computer slept is handed back at once and opened anew (next devrestarts behind it), and a tunnel of your own is served again once it answers. - Who can. It reveals the environment's variables, so it takes a team owner or admin, or a key with Apps Permissions, and each start is in the audit log. Members sync with the hosted dev server. The variables are read when it starts: after changing them in the dashboard, restart it.
- While it runs, the hosted dev server isn't written to or woken, no dev server hours are used, and Settings shows the dev server as running on a developer's computer. If a second computer starts serving the same environment, the newer one takes over, so give each developer their own development environment (Settings → Environments).
Commands
ib-apps login # sign in with your browser (once per computer)
ib-apps logout # sign this computer out
ib-apps whoami # who and which team this computer is signed in as
ib-apps list # the team's apps
ib-apps create <name> # create an app and download its starter files into ./<slug>
ib-apps pull # download the app's files into this folder (a fresh copy)
ib-apps push # sync once: take the server's changes, then send yours
ib-apps status # what changed here and on the server since the last sync
ib-apps dev # sync both ways while you work; owners and admins get the dev server on this computer
ib-apps dev --hosted # the same, served by the hosted dev server
ib-apps deploy # sync, then ship development to production
ib-apps test # run the app's tests (Vitest) against in-memory recordspush and status work in a linked folder (one with .ib/sync.json). pull refuses to overwrite local changes without --force. Production's files can be pulled (--env production) but not pushed. deploy is described in Deploys.
Every command exits 0 when it's done, 1 when it failed (a refused deploy, a failed build, a conflict left unresolved) and 2 when it couldn't run (not signed in, not a linked folder, a bad option), so it can run in CI.
Project layout
settings.ib.ts # the platform
accessControl/permissions.ib.ts # roles and what each may read and run
api/
models/
<model>/
schema.ib.ts # the model's fields
actions/<action>.ts # run, onSuccess, options
actions/<action>.ts # global actions
web/
app/ # Next.js App Router: pages and route handlers
proxy/ # Shopify: the storefront's app proxy routes
proxy.ts # Shopify: the frame-ancestors header for the embedded pages
tests/ # tests of the actions (ib-apps test); never built
extensions/
<handle>/ # Shopify: a theme app extension
package.json
vitest.config.ts # for ib-apps test
.ibignore # optional: more paths never to sync| Path | What it is |
|---|---|
settings.ib.ts | The app's settings: { type: "ib/settings/v1", platform: "shopify" }. |
api/models/<model>/schema.ib.ts | A model. The folder name is the model's name. See Models. |
api/models/<model>/actions/*.ts | The model's actions, one per file, named by the file. See Actions. |
api/actions/*.ts | Global actions, which don't belong to one model. |
web/ | A Next.js App Router app. Its package.json dependencies come from the root package.json. |
extensions/ | Shopify theme app extensions. See Storefront blocks. |
accessControl/ | Roles and their grants (permissions.ib.ts). See Access control. |
Code imports @inferencebureau/apps-sdk (and @inferencebureau/apps-sdk/browser in client components). Every build installs the SDK for you, so the starter's package.json lists it like any dependency.
The starter files
Every app starts with README.md, .gitignore, package.json (Next.js, React and the SDK, with Vitest and an npm test script), vitest.config.ts, settings.ib.ts, accessControl/permissions.ib.ts, web/app/layout.tsx and web/app/globals.css, and the coding agent files. A web app is one of two starters, chosen under Starter on New app, with ib-apps create --starter site or with starter: "site" to POST /v1/apps: a Members app (accounts, sign-in and members-only pages) or a Site (no sign-in: a front page led by the latest post, posts written in the dashboard's record editor and served at /blog and as RSS, a contact form whose messages become lead records and an email to you, and a newsletter list with double opt-in). Then, by platform and starter:
| Shopify | Web: Members app | Web: Site |
|---|---|---|
|
|
|
Coding agents
The starter includes an AGENTS.md (with a CLAUDE.md that points Claude Code at it) and skills in .agents/skills/<name>/SKILL.md: models-and-schemas, actions, records-api, web-routes, security, testing and debugging, plus web-sign-in for a Members app, web-content for a Site, and shopify-admin-pages, shopify-storefront and shopify-data for Shopify apps. They are short guides that tell a coding agent (Claude Code, Codex, Cursor) how an Inference Bureau app is laid out and the practices to follow when it writes models, actions, admin pages and storefront blocks. They sync like any other file, so edit them to suit the app. An agent without a checkout connects to the environment's MCP server instead: development's has the app's files, models and actions as tools alongside its records, and tells the agent to read AGENTS.md and the matching skill before it changes code. Tests run only from a checkout.