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

  1. Install the CLI

    Code
    npm install -D @bounded-sh/cli

    A 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 | sh installs a global bounded instead.

    It does not start a background dashboard or development process.

  2. Sign in and initialize

    Code
    npx bounded init

    The 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.

  3. 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:

    policy.json
    {
      "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"
          }
        ]
      }
    }
  4. Build the client flow

    Code
    npm i @bounded-sh/client

    Build 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.id as the authenticated path identity.

  5. Check the policy

    bounded verify, proof report
    $ 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 passed

    Read each result's proofStatus.PROVED means the checker proved that supported condition.DISPROVED includes 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.

  6. Deploy

    Code
    $ 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> --json

    Deployment 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.

  7. Publish the web app

    Code
    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.

  8. Write, and watch the cap hold

    Code
    # 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 committed

    Rejections are atomic and fail-closed. See For agents for the full failure-semantics table and set-many composition. 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