Tutorial

QuickStart / Cursor · Codex · Claude Code · OpenCode

Build a calculator and API with your agent.

Adapt an event budget with your agent, see how each result was calculated, then give it an API and deploy it. Your agent writes the Bosatsu; you don’t need to know it to start.

1. Open this workspace and connect your agent

A small local relay connects this page’s tools to your coding agent, so it can edit and run the example you see.

Enable WebMCP on this page

Open the enabled page in a browser on the same computer as your agent. Keep that tab open. A page on your phone cannot reach the relay on your laptop.

You need Git, Node.js 20 or newer, pnpm, and one of the local coding clients below. The browser runs the compiler; this walkthrough does not require Java, Scala, or Nix.

Build the browser relay once

The relay is currently installed from the repository. Run these commands in a terminal, or ask your agent to run them:

git clone https://github.com/snoble/yichus.git
cd yichus
pnpm install --frozen-lockfile
pnpm run yichus-mcp:build
node -p "require('node:path').resolve('packages/yichus-mcp/dist/cli.js')"

Already have this checkout? Start with pnpm install in its root. The last command prints the absolute relay path. Replace /absolute/path/to/yichus/packages/yichus-mcp/dist/cli.js below with that output. Use the full path to node too if your client cannot find it.

Choose your client. Add the entry to any existing configuration; keep the other servers you already use.

Cursor

In your project, add this server to .cursor/mcp.json. Enable it in Cursor’s MCP settings, then start an Agent chat.

{
  "mcpServers": {
    "yichus-browser": {
      "command": "node",
      "args": ["/absolute/path/to/yichus/packages/yichus-mcp/dist/cli.js"]
    }
  }
}

Cursor’s MCP setup reference

Codex

With the Codex CLI installed, run:

codex mcp add yichus-browser -- node /absolute/path/to/yichus/packages/yichus-mcp/dist/cli.js
codex mcp list

The local clients share MCP configuration on the same host. Start a new local session after adding the server. If you configure it through MCP settings instead, choose STDIO, command node, and the absolute relay path as its argument.

Codex’s MCP setup reference

Claude Code

From the project directory where you’ll use Claude Code, run:

claude mcp add --transport stdio yichus-browser -- node /absolute/path/to/yichus/packages/yichus-mcp/dist/cli.js

Start Claude Code in that directory and use /mcp to check the connection. These steps are for Claude Code, the local coding client.

Claude Code’s MCP setup reference

OpenCode

Add this to your project’s opencode.json, then start OpenCode there:

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "yichus-browser": {
      "type": "local",
      "command": ["node", "/absolute/path/to/yichus/packages/yichus-mcp/dist/cli.js"],
      "enabled": true
    }
  }
}
Using OpenCode V2?

V2 uses mcp.servers. Use its CLI to add the local server instead:

opencode mcp add yichus-browser -- node /absolute/path/to/yichus/packages/yichus-mcp/dist/cli.js
opencode mcp list

OpenCode’s MCP setup reference · V2 reference

No browser tools showing up?

Look at the agent control at the top right of this page. Waiting for agent means no relay has answered: your client starts the relay, so start the client (or a new session in it) and keep it running. The tab keeps looking and connects when the relay answers, with no reload. Agent on means this tab is connected; ask the agent to call webmcp_list_sources again. Agent refused means the relay was started for another site; its menu names the --base-url to start it with.

Approve the local connection if your browser asks. If the control still says Waiting for agent a minute after the client started, open this page with ?webmcp=1 in a new tab. If several tabs appear, the agent should choose this QuickStart’s URL and inspect its tool list.

A remote or cloud coding session cannot use a relay on your laptop without additional networking. Use a local session for this walkthrough. See the connection reference for native browser hosts and other setups.

2. Give your agent this prompt

The starting budget omits booking fees. Ask your agent to add one as a control, so you can compare venues without editing a formula each time. It will change both the calculation and the control configuration.

Build me an event-budget calculator in the Yichus QuickStart browser tab. Use the browser's WebMCP compiler and feedback tools; keep the visible source and running result in sync.

Connect first: use webmcp_list_sources to find /start/quickstart.html, then webmcp_list_tools. Match each tool’s sources to that tab and use its returned public name in webmcp_call_tool, with an arguments object. Names can gain a tab suffix when several pages are open; rediscover them if needed. Read yichus_example_guide and yichus_example_read for exampleId "event_budget". If the tab is missing, tell me the connection step that failed before writing code.

Read both Bosatsu files and the guide's language/package references. Add booking_fee as a fifth Int argument to calculate and a slider labeled "Booking fee ($)", range 0–500, step 10, default 50. Include it once in total_cost. Keep the other defaults, the balance chart, and generated Why buttons. Update the assumptions to say the fee is included. Use named intermediate calculations and <- for the configuration's continuation chains.

Use yichus_example_update with the revision you just read. Compile using yichus_example_run (action "run"). If running is true, poll yichus_example_feedback until running is false, check the revision still matches, and fix compiler errors from that feedback. Read yichus_example_feedback until previewReady is true; use yichus_example_preview with that revision, previewId, and current control IDs to test the actual controls. Never substitute a hand-written result or explanation.

With ticket price 25, venue cost 600, and per-guest cost 5, check these cases:
- 40 guests, booking fee 50: balance 150.
- 60 guests, booking fee 50: balance 550.
- 0 guests, booking fee 50: balance -650.
- 40 guests, booking fee 100: balance 100.
Open Why for Amount left over, follow total_cost, and confirm booking_fee appears in the generated calculation. Check that the balance chart renders and feedback reports no runtime errors. Restore 40 guests and fee 50 for me to inspect.

Call the relay’s yichus_save_calculator directly. Set exportToolName to this tab’s public yichus_example_export name from discovery, exampleId to event_budget, expectedRevision to the tested revision, and outputDirectory to an absolute path for a new event-budget folder under my current project. The tool saves both Bosatsu files and event-budget.html and returns their paths without sending the full generated HTML into our chat. The export uses configured defaults and needs its hosted supporting assets. Add a README with the model assumptions, tested inputs/results, and local run instructions. Serve that folder on localhost with a static server, check that its calculator loads, and give me the local URL and file paths. Report what you actually checked and any step you could not complete.

Your shared calculator workspace The agent opens this drawer; you can also edit and run it yourself

The compiler loads when you run the example. Edits stay in this tab until you or your agent save them. The local relay carries tool requests between the browser and your agent; your agent’s usual data-handling settings still apply.

3. Check what changed

At the starting inputs, 40 guests pay $25 each. The venue costs $600, each guest costs $5, and the new booking fee costs $50. That leaves $150. Move Guests to 60 and the balance should become $550.

Open Why? beside Amount left over, then follow total_cost. The booking fee should appear in the calculation. The agent changed the source; Yichus derived the updated explanation from compiled dependencies and values from the current run.

This is the useful loop: you can inspect the program the agent wrote, try a boundary case such as zero guests, and ask it to fix what you find. Compilation checks types. The examples above check particular results. Neither establishes that the budget includes every real-world cost.

4. Run your copy locally

The prompt asks your agent to save two Bosatsu files, event-budget.html, and a README, then give you a localhost URL. You can also select Save calculator HTML in the workspace after a successful compilation.

Open the saved HTML in your browser, or serve its directory with a static server. The calculations run in that browser. Supporting scripts and styles still load from the site recorded in the export, so keep an internet connection; the export is not an offline bundle.

Recompile saved sources later

Bring your source changes back into this workspace and compile again, or build the local CLI and run this in the directory containing both source files:

yichus simapp --compute event_budget.bosatsu --output event-budget.html event_budget.sim.bosatsu

That CLI route has its own toolchain setup. It isn’t required to run the browser-compiled export.

Continue below to add the API and deploy the complete app. If you only want the calculator, use the GitHub Pages option in step 6.

Try the next change

Ask your agent to add a sponsor contribution, or adapt the model for a workshop with materials costs. Keep the same cycle: edit the source, compile, exercise the controls, inspect Why, and save the tested revision.

For a different problem, use lenses to examine duplicated logic and access checks, or build a service whose rules are Bosatsu and whose server is Node.js. The agent reference covers those tools and their feedback.

5. Add an API that uses the same calculation

Give another program a way to calculate a budget: POST /budget accepts the input fields and returns revenue, total cost, and balance. The endpoint calls the same Bosatsu calculate definition as the browser. A small Node server handles HTTP and serves the calculator; it contains no budget formula.

This example is a public, stateless calculator with whole-dollar inputs. It returns the model’s Float64 results as decimal strings, including signed zero; the inputs remain whole-dollar integers. It needs no account or database. The route is explicitly anonymous, and Yichus checks that declaration against the handler’s effects. The API does not generate a second Why explanation: Why stays with the browser’s calculation.

Your API source & diagram The agent adds booking_fee here to match your calculator

Open the API workbench with WebMCP enabled in another tab. Keep both tabs open, then give your agent this follow-up:

Continue the event-budget app we just built. Add its API, using the same tested computation source rather than rewriting the formula in JavaScript.

Rediscover the QuickStart and /api-mcp.html tabs with webmcp_list_sources and webmcp_list_tools; match each tool’s sources to its tab and call the returned public tool name. Read the QuickStart's event_budget and event_budget_api examples. In event_budget_api, replace event_budget.bosatsu with the exact tested calculator source. Extend BudgetInput, its pattern, and the call to calculate with booking_fee in the fifth position. Keep the public_route declaration: this endpoint computes a public result and has no database operations. The handler takes BudgetInput directly; api_verify must establish storage absence before AccessSpec can be omitted. Return the existing EventBudgetResult directly. Its Float64 fields use quoted decimal strings on the wire; keep those strings through the server’s schema-directed field mapping. The current input sliders still use bounded whole-dollar Int values.

Update event_budget_api with its current revision. Run quote with req containing all five fields and rebuild the diagram. Follow quote to calculate in the map. Use the API workbench's api_guide, api_compile and api_verify on those exact two sources. Require verdict.proven to be true; inspect every property and fix findings instead of ignoring them. Call api_deploy on those sources; require ok:true and save its js field exactly as budget-engine.mjs. Keep the returned verification result as verification.json. Save the two source files, including event_budget.api.bosatsu. The engine is generated in the browser; Render does not need the Bosatsu compiler.

Download the five linked deployment templates from the QuickStart's /quickstart-app/ directory: server.mjs, index.html, app.js, package.json, render.yaml. Put them next to budget-engine.mjs and the current saved event-budget.html. Read the templates before running them. The Node host serves a fixed list of files, validates the generated input schema and calls handlePublic, which rejects non-public routes. Keep this boundary; do not fabricate a user ID or enable development authentication.

Run npm run build and npm start. Test POST /budget with JSON bodies for the same four cases: 40 guests/fee50 -> balance150; 60/50 ->550; 0/50 ->-650; 40/100 ->100, with ticket_price25, fixed_cost600, cost_per_guest5. Require a 400 for missing fields, extra fields, fractional or negative inputs. Open the local app, use Send current inputs to API, change inputs and check again. Confirm Why still works in the calculator. Verify GET /health returns 200 and source/config files are not served.

Add a README with these checks and the Render settings below. Prepare a Git repository containing the generated artifacts, sources, templates and verification.json, and give me the local app URL. Explain that after a model edit both browser HTML and API engine must be regenerated. Prepare the deployment for review; ask before creating hosted resources or publishing the repository.
Deployment templates and file layout

These are the files the agent downloads. The application code is small enough to read before running:

event-budget/
  event_budget.bosatsu
  event_budget.sim.bosatsu
  event_budget.api.bosatsu
  event-budget.html       # browser compiler export
  budget-engine.mjs       # api_deploy's js output
  verification.json
  index.html
  app.js
  server.mjs
  package.json
  render.yaml
  README.md

The server accepts whole integers from 0 to 1,000,000 for each generated input field. That range keeps this model’s arithmetic exact. The host uses the generated result schema to name the response fields; it does not redo the calculation.

Optional: catch a bug that exposes another user’s budget

A calculation needs no users. Saving budgets introduces a rule: each caller should only read and replace their own saved budget. Ask your agent to add that feature in a browser-only copy, break it, and repair it. Yichus checks whether database operations use the supplied caller’s identity by analyzing the compiled code.

Alice and Bob are test identities. Anyone can switch between them; there are no passwords or accounts. This exercise checks how the code uses an identity, not whether a visitor really is that person. The deployed calculator and API from step 5 stay public and stateless.

Give these prompts to your agent one at a time. It writes the code in your workspace and uses the API workbench to show you the results.

1. Add saved budgets for Alice and Bob
Make a separate permission-lab folder from our tested event-budget API sources. Keep the Render app unchanged. Use the API workbench's discovered WebMCP tools and api_guide to build this exercise, then show me the source and running app.

Add SavedBudget(name: String, inputs: BudgetInput) and a budgets_table(db: Db) returning Table[List[SavedBudget]] named "budgets". Add load_budget(db: Db, p: Principal) and save_budget(db: Db, p: Principal, item: SavedBudget), both returning IO[List[SavedBudget]]. Destructure the supplied Principal(uid, _) and use uid as the db_read/db_write key. Saving writes [item], replacing that caller's previous budget; it does not append. Do not construct a Principal in the handler.

Declare AccessSpec([AccessRule("budgets", OwnerScoped)]). Add authenticated route /budgets with ReadPerm("budgets") for load_budget and /budgets/save with WritePerm("budgets") for save_budget. Keep the existing public /budget calculation. Add a separate FrontendSpec source selecting /budgets as ListView and /budgets/save as Form. Title it "Permission lab — test users only; anyone can switch". Follow api_guide's complete FrontendSpec syntax; derive fields from the handler types.

Call api_compile, api_access_check and api_verify on the exact lab sources. Require the access verdict and composite verdict to be proven; read all findings. Open them with yichus_app_open, auth:"dev", store:"memory", instances:"1". Its sources argument is a JSON-encoded array of {fileName, source}. This app runs inside the browser; do not start a server with development authentication.

Read yichus_app_views and its exampleArgs. Use yichus_app_call to save a budget named "Alice's workshop" as user_id:"alice", then read /budgets as bob and as alice. Bob should get an empty list; Alice should get her saved budget. Label those as tool results: app_call does not refresh the displayed list. Tell me to select the list view, enter alice or bob in User id, and press Use this user to repeat the reads myself. If you have browser controls, do those clicks and inspect the displayed result too. Use yichus_page_feedback to confirm the app is open; it reports the frame's presence, not its contents.

Explain the boundary in the README: the checker proves owner-key usage for the supplied Principal; this test switcher does not authenticate people. All records are in browser memory and disappear when this app is reopened. This lab is separate from our public Render deployment.
2. Introduce a bug and inspect the failure
So I can see the power of the permission verifier, deliberately make Bob read Alice's budget in the permission-lab copy. Save the working sources first.

Change only load_budget: make its Principal parameter unused (_: Principal), remove its destructuring, and use the literal key "alice" in db_read. Leave the OwnerScoped declaration and route permissions intact. Show me that diff. Run api_compile, api_access_check and api_verify on the changed sources. Compilation should succeed, but access checking should report a violated owner-key rule and verification should no longer be proven. Show the actual finding and its code location; do not weaken the rule to get green.

Demonstrate the consequence in api_why's isolated evaluation, using the broken load_budget binding. Ask api_world_shape for the input and row shapes first. Read api_why's typed inputs to find the unused Principal parameter's generated name, then explicitly supply Bob for that parameter and seed only Alice's row in budgets with the saved workshop. Confirm the echoed input is Bob and show that this run returns Alice's budget. Separate this observed example from the static finding: the verifier found the invalid key without needing us to run Bob's request.

Keep the broken source and findings in the lab folder. Do not generate or deploy an app from the broken version, or present a previously open app as if it were running that version. Open the failing source in my editor and use the workbench's Why feedback to show its output.
3. Fix the code and repeat the checks
Repair load_budget by taking its key from the supplied Principal again. Keep the OwnerScoped rule and route permissions unchanged. Show the one-function diff, then rerun api_access_check and api_verify on the repaired lab sources; require both verdicts to be proven.

Repeat the same api_why evaluation: Bob with only Alice's row seeded must now get an empty list. Run it as Alice too and require her workshop to be returned. Show me the changed output and the corresponding verifier finding.

Reopen the repaired app with yichus_app_open, auth:"dev", store:"memory", instances:"1". This starts with an empty store, so save Alice's workshop again through yichus_app_call. Repeat the Bob/Alice reads, then save Bob's own budget and check each caller sees only their own entry. Confirm the app is open with page feedback and tell me how to refresh the list and switch users. If you have browser controls, inspect both displayed lists too; otherwise report that you tested the handlers and leave the visible check for me.

Save the repaired sources and the checks in the lab README. Explain what changed: the database key now follows the caller instead of a fixed person. The test identities are still freely switchable; this exercise has not added real authentication or a deployed storage service.

6. Put it online

Use Render for the complete app: it runs Node and serves both the page and the API from one origin. Use GitHub Pages when you only need the browser calculator.

Render: calculator + API
  1. Push the prepared app directory to your own Git repository. Commit the generated budget-engine.mjs and event-budget.html along with their sources and templates.
  2. In Render, choose New → Web Service and connect that repository. If the app is a subdirectory, set Root Directory to it.
  3. Select the Node runtime, build command npm run build, and start command npm start. Use Node 22 or newer. Set the health check path to /health. Choose your compute plan.
  4. Create the service. The supplied host listens on 0.0.0.0 and Render’s PORT. No environment secrets or database are needed for this public calculation.
  5. Open Render’s HTTPS URL, change Guests, and select Send current inputs to API. Check that the result agrees with the calculator and Why still opens. Also try the request below with your service URL.
curl --fail-with-body https://YOUR-SERVICE.onrender.com/budget \
  -H 'Content-Type: application/json' \
  --data '{"guests":40,"ticket_price":25,"fixed_cost":600,"cost_per_guest":5,"booking_fee":50}'

The response should contain "balance":150. You can alternatively create a Render Blueprint from the supplied render.yaml when the app is the repository root. It selects the Free plan; review the plan and its limits before creating resources.

Render’s web service setup and port requirements · Blueprint reference

GitHub Pages: browser calculator only
  1. Copy your tested event-budget.html to docs/index.html in your own Git repository. Add an empty docs/.nojekyll file. Use the calculator export here; the complete app’s index.html expects a Node API.
  2. Commit and push. On GitHub, open Settings → Pages. Under Source, choose Deploy from a branch, choose the branch containing the files, and select /docs. Save.
  3. Open the URL GitHub shows after deployment. Change an input, open Why, and check the chart. Calculations run in the visitor’s browser; GitHub Pages does not run the Node server.

The export still loads supporting scripts and styles from the Yichus site recorded in its base URL. Keep that URL intact. Your source and calculations are in the exported HTML, so use this path for code you intend to make public.

GitHub’s publishing-source instructions

When you change the model, repeat the browser and API checks, regenerate both artifacts from the same sources, and commit them together. A successful upload says the host served the files; the input checks and generated explanations help you inspect what they do.

Where this fits

What this is about: Ask any function why