Skip to content
bits
Build the front end with agents · Lesson 11 of 11 · 25 min

Checkpoint: Klippy on the web

Desk: best at a computer, with a terminal

Verified remix 3.1.0agents 0.33.0wrangler 4.157.0

Start from d-10 on GitHub. Starting here, or behind? Get the code at that tag:

Shell
git clone https://github.com/ryanyogan/klippy
cd klippy
git checkout d-10
Tutor:

Klippy has a web app: GitHub sign-in, your notes, and a live chat with Approve and Deny. One last prompt makes it gradeable, then you ship both Workers and let bits check them.

Tutor:

1. The prompt

bits will call your web app's /klippy/check, which answers through the agent. That proves both Workers and the binding between them.

Plain text
Goal: get Klippy's web app ready to deploy and gradeable: a public /klippy/check on the web app that answers through
the agent, so bits can prove both Workers and the binding between them work.
Use the remix skill (routes, controllers, data-schema) and the cloudflare skill for the Rate Limiting binding.
Constraints:
- GET /klippy/check?nonce= in its own controller, no sign-in. Validate nonce with data-schema (8–64 of A-Z a-z 0-9 _ -).
- Rate limit it per address with a new binding (10 a minute); forward to the agent's /klippy/check with agentFetch.
- Set TAG to 'd-11' in apps/agent/src/check.ts and its test. Don't deploy anything.
Plan first, then wait for my go-ahead.
Done when typecheck, tests and remix doctor pass, both `wrangler deploy --dry-run`s build, and the local check
returns the nonce and tag d-11. Report the files and outputs, then list the deploy steps for me to run.
  • Its own controller, no sign-in. The grader isn't signed in. Every other page stays behind requireUser.

  • Rate limited, forwarded. The agent's check already caches its probe for five minutes; the web route adds a limit per address in front.

  • "Don't deploy anything." Deploying is yours to do.

Tutor:

2. What to expect

A new controller, a schema for the nonce, a route, and a rate-limit binding:

export default createController(routes.check, {
actions: {
async index(context) {
const query = parseSafe(CheckQuery, context.url.searchParams);
if (!query.success) return Response.json({ error: 'Send ?nonce= (8 to 64 letters, digits, - or _)' }, { status: 400 });
const address = context.request.headers.get('cf-connecting-ip') ?? 'local';
if (!(await env.CHECK_LIMITER.limit({ key: address })).success) {
return Response.json({ error: 'Too many checks. Wait a minute.' }, { status: 429 });
}
// Through the service binding, as everything else: proof the web app really reaches your agent.
const reply = await agentFetch(`/klippy/check?nonce=${query.value.nonce}`);
return new Response(reply.body, {
status: reply.status,
headers: { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' },
});
},
},
});
TypeScriptUTF-8at d-11● lines 6–9: apps/web/app/actions/check/controller.tsx
Tutor:

Our local checks (real; the Workers AI fallback answered the probe, and the probe says so):

recorded output
curl -i "localhost:8802/klippy/check?nonce=bits-d11-check"
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
{"nonce":"bits-d11-check","tag":"d-11","probe":{"answer":"Hi bits!","model":"@cf/zai-org/glm-4.7-flash"}}
Tutor:

A bad or missing nonce gets a 400 before any call to the agent. Of ten more calls in a minute, the tenth got a 429. Signed out, / still redirects to /login. All tests pass: the agent's 64, the web app's 3 and the driver's 24.

Tutor:

3. Review it

  • The check controller has no requireUser, and nothing else became public.

  • A bad nonce is a 400 before any call to the agent; the 11th call in a minute is a 429.

  • JSON with Cache-Control: no-store; the agent's body passes through.

  • No secret, account id or real GitHub id in wrangler.jsonc.

  • Reject: a probe that calls the model from the web app, a check that writes anything, wrangler deploy run by the agent.

Steer prompts:

Plain text
You put /klippy/check inside the root controller, which has requireUser, so the grader gets a 302. Give it its own controller without it.
Plain text
Don't run wrangler deploy. List the steps and I'll run them.
Tutor:

4. Ship both Workers

What we recorded, and what we didn't. We haven't deployed the reference web app, so there's no recorded live deploy or live sign-in. Here are the steps, in order:

  1. A GitHub OAuth app for the live site: Homepage https://klippy-web.<your-subdomain>.workers.dev, callback https://klippy-web.<your-subdomain>.workers.dev/auth/github/callback.

  2. In apps/web/wrangler.jsonc, set APP_ORIGIN to that address and ALLOWED_GITHUB_IDS to your id (gh api user --jq .id).

  3. The agent first (the web app binds to it). From klippy/: pnpm deploy. Its token and database are already set from earlier courses.

  4. The web app's secrets, in apps/web, one at a time:

Shell
pnpm exec wrangler secret put GITHUB_CLIENT_ID
pnpm exec wrangler secret put GITHUB_CLIENT_SECRET
pnpm exec wrangler secret put SESSION_SECRET
pnpm exec wrangler secret put KLIPPY_TOKEN

SESSION_SECRET is a new random value (openssl rand -base64 32); KLIPPY_TOKEN is the same value the agent has.

Last, from klippy/: pnpm deploy:web. Then sign in, send a message, approve a saveNote, and find the note on /notes.

Our dry runs show both build: the agent at 3,684 KiB (713 KiB gzip), the web app at 986 KiB (197 KiB gzip).

Tutor:

5. Let bits check it

Paste your web app's address. bits calls /klippy/check on it and looks for this checkpoint's tag.

deploy check+60 neurons

Goal Your Klippy web app is live: its /klippy/check answers through the agent with bits' nonce and tag d-11 (or a later one)

Paste the https://klippy-web….workers.dev address that pnpm deploy:web printed.

bits calls /klippy/check?nonce=bits-checkpoint-d11 on your Worker, from bits’ server

  • /klippy/check?nonce=bits-checkpoint-d11 answers 200 OK, not yet
  • Answers the check, not yet
  • Echoes bits' nonce, not yet
  • Is at d-11 or later, not yet

Sign in to check your deploy: the check is saved to your account, and a certificate can link it.

Tutor:

A pass proves a web app at that address reaches an agent that answers the way this course asks. It doesn't prove who wrote it.

quick check+20 neurons
Tutor:

Which of these is your job, not the coding agent's?

    Pick one option

    Pick one, then Check.

    Tutor:

    That's Klippy on the web, built by directing an agent. Your code matches tag d-11 (changes from d-10). Next, Klippy learns to answer from your own documents.