03Docs

Quickstart

From nothing to a complete web app with a proven spending cap. The fastest path is one paste to your coding agent; every step below is what the agent does across client, policy, deployment, and testing.

The one-paste flow

Hand the whole setup to a coding agent (Claude Code, Codex, Cursor, or anything that can run a shell), the same prompt the homepage uses:

Paste into Claude Code, Codex, or your preferred AI agent.

The agent builds the client UI, installs the SDK and CLI, declares a policy with your boundaries as invariants, fixes counterexamples, deploys the governed runtime and web site, then tests the complete flow. The rest of this page is that sequence by hand.

Step by step

  1. Install the CLI

    curl -fsSL https://get.bounded.sh/install.sh | sh

    One binary plus the Bounded agent skill. No project API key.

    It does not start a background dashboard or development process.

  2. Sign in and initialize

    bounded init

    Init reuses your saved Bounded web session or opens hosted browser login and returns to the terminal. It writes public bounded.json; no session token is stored in the project. A separate login or link step is not part of normal setup.

  3. Model the governed backend

    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

    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. Verify, the proof report

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

    Supported policy declarations generate proof obligations checked by an SMT solver (Z3); read each item’s proofStatus. A blocking DISPROVED item includes a concrete counterexample and fails deploy. Advisories remain explicitly non-proven. Read the report, strengthen the policy, and re-run. verify is your fast feedback loop before the deploy gate.

  6. Deploy

    $ 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:
      bounded site deploy ./dist --with-source
      bounded data set --path agents/<your-id>/spend/s1 --data '{"amount":60}'
      bounded apps inspect --app-id <id> --json

    deploy is a separate command. It validates and compiles your policy (a malformed policy, an impossible tier/invariant pairing, or an uncompilable rule is rejected), and the server re-runs the prover’s deploy gate before the policy ships. A blocking DISPROVED obligation is rejected, fail-closed. From there the runtime enforces every rule and invariant atomically (see the loop).

  7. Publish the web app

    npm run build
    bounded site deploy ./dist --app-id <id> --with-source
    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

    # Use the authenticated principal required by $agentId == @user.id.
    $ USER_ID="$(bounded whoami --json | jq -r .id)"
    
    # Local/staging uses full error disclosure; production defaults to the same
    # stable code with policy details hidden.
    $ bounded data set --path "agents/$USER_ID/spend/s1" --data '{"amount": 60}'
    ✓ committed
    
    $ 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