03Docs
Quickstart
Build and deploy a web app with Bounded. This guide uses a spending log to show sign-in, data storage, and an hourly limit. You can follow the steps yourself or use a coding agent.
The one-paste flow
Hand the whole setup to a coding agent (Claude Code, Codex, Cursor, or anything that can run commands), the same prompt the homepage uses:
Paste into a Claude Code session (the Code tab of the desktop app), Codex, or any agent that can run commands; a chat-only surface cannot run the install.
The agent writes the app, deploys it, and tests the user flow. The steps below explain the same process so you can follow or run it yourself.
Step by step
Install the CLI
npm install -D @bounded-sh/cliA project dev dependency on macOS, Linux, and Windows (Node 20 or later); every command below runs as
npx bounded. No project API key. Without Node, on macOS or Linux:curl -fsSL https://get.bounded.sh/install.sh | shinstalls a globalboundedinstead.It does not start a background dashboard or development process.
Sign in and initialize
npx bounded initThe command installs the Bounded agent skill. The command opens browser sign-in if you need it. It writes project settings to
bounded.json. Your session token stays outside the project.Define the data and rules
Creates
policy.json, the single file that defines your collections, auth rules, and invariants. Here is a starter policy with an hourly spending cap:{ "agents/$agentId/spend/$spendId": { "fields": { "amount": "UInt", "memo": "String?" }, "rules": { "read": "@user.id != null && $agentId == @user.id", "create": "@user.id != null && $agentId == @user.id", "update": "false", "delete": "false" }, "tier": "durable", "invariants": [ { "type": "rollingSum", "name": "spend_cap", "field": "amount", "windowSeconds": 3600, "limit": 100, "scopeVariable": "$agentId" } ] } }Build the client flow
npm i @bounded-sh/clientBuild the sign-in, spend-history, add-spend, remaining-budget, loading, and boundary-refusal states. Initialize the client with the app id from
bounded.json; use@user.idas the authenticated path identity.Check the policy
$ npx bounded verify policy.json, 1 collection, 1 invariant create rule is satisfiable PROVED (38ms) create requires authentication PROVED (41ms) read requires authentication PROVED (40ms) transaction postcondition spend_cap append-only rolling limit algebra PROVED (106ms) 4 obligations · 0 failed · blocking proof gate passedRead each result's
proofStatus.PROVEDmeans the checker proved that supported condition.DISPROVEDincludes an example that breaks it. Fix blocking failures before deployment. Review advisories separately because they are not proofs. See verification for the full report format.Deploy
$ npx bounded deploy --create --name lucid-prairie-41 --with-source ✓ policy deployed to lucid-prairie-41 (revision 3) recorded project defaults in bounded.json (safe to commit) Next: npx bounded site deploy ./dist --with-source npx bounded data set --path agents/<your-id>/spend/s1 --data '{"amount":60}' npx bounded apps inspect --app-id <id> --jsonDeployment checks the policy again on the server. Invalid policies and blocking proof failures cannot deploy. After deployment, Bounded checks the applicable rules and invariants on every write.
Publish the web app
npm run build npx bounded site deploy ./dist --app-id <id> --with-source npx bounded domains slug my-app --app-id <id>Bounded serves the built static client at
https://my-app.bounded.page. SPAs and prerendered exports work; request-time SSR/ISR or framework server routes need an external frontend host. React Native follows the same SDK and policy flow but keeps native binary release in the mobile toolchain.Write, and watch the cap hold
# Use the authenticated principal required by $agentId == @user.id. $ USER_ID="$(npx bounded whoami --json | jq -r .id)" # Local/staging uses full error disclosure; production defaults to the same # stable code with policy details hidden. $ npx bounded data set --path "agents/$USER_ID/spend/s1" --data '{"amount": 60}' ✓ committed $ npx bounded data set --path "agents/$USER_ID/spend/s2" --data '{"amount": 60}' ✗ 409 postcondition failed: invariant "spend_cap" requires rolling sum(agents/$agentId/spend/$spendId.amount) <= 100 rollingSum(amount) over 3600s: 60 + 60 = 120 > limit 100 nothing committedRejections are atomic and fail-closed. See For agents for the full failure-semantics table and
set-manycomposition. Repeat the allowed and over-cap cases through the deployed UI and confirm it renders the 409 as an intentional product outcome rather than retrying it.
Where to go next
- Client SDK and hosting & domains, wire and publish the complete web app.
- Policy reference, every key in
policy.json: rules, fields, tiers, hooks, roles, constants, environments. - Invariants, the six boundary types (
conserve,rollingSum,flowBound,bound,tenantTag,tenantEdge) plus thewindowSumderived aggregate, with real syntax and coverage details. - Verification, the full obligations table, counterexamples, and the two-layer coverage model.
- For agents, failure semantics, atomic
set-many, in-batch composition. - Functions, AI & managed services, realtime, files & search, and auth, build the full server-side and client data path.
- Payments and Action Boundaries & PII, add money and external actions at their explicit settlement and enforcement seams.