All jobs

Review Pull Requests on a Hono API

Yes. An agent checks out the pull request, runs the touched example's Vitest suite and tsc in its sandbox, and posts one review on middleware and validation.

Run this on RushIn a Project that has your repository.

What the agent does

The agent first works out which example the diff touches, because honojs/examples is one npm workspace with many small apps that run on different runtimes. The root package.json lists basic, blog, durable-objects, jsx-ssr, pages-stack, nextjs-stack, hono-vite-jsx, env-vars and stytch-auth as workspaces and pins packageManager to npm@10.0.0; the deno, bun and serve-static directories sit outside the workspace and are run with deno run or bun run as the README describes. There is no GitHub Actions workflow, only .github/dependabot.yml checking npm daily, so whatever the agent runs is the only check the pull request gets.

Only two examples have tests. basic/src/index.test.ts calls app.request('http://localhost/') and expects a 200 with x-powered-by: Hono, under a vitest.config.ts that sets globals: true; basic/package.json runs it with vitest --run. blog/src/api.test.ts drives the Worker through worker.request(path, init, env) with env from cloudflare:test, creating, reading, updating and deleting a post, and blog/vitest.config.ts uses defineWorkersConfig with isolatedStorage: false and wrangler: { configPath: './wrangler.toml' }. That file is not committed: wrangler.example.toml declares the BLOG_EXAMPLE KV namespace with placeholder ids, so the agent copies it to wrangler.toml before npm test -w blog can start. For every workspace it runs npx tsc --noEmit -p <example> against the example's tsconfig.json, which in blog types vitest/globals, @cloudflare/workers-types/experimental and @cloudflare/vitest-pool-workers.

Then it reads the diff with the three questions the prompt names. Middleware order: in basic/src/index.ts the X-Response-Time middleware is registered on * after basicAuth on /auth/* and etag on /etag/*, notFound and onError are set once for the whole app, and /api/* ends in a catch-all 404 that any new /api route must be registered before. In blog/src/index.ts the auth middleware on /posts/* only wraps non-GET methods with basicAuth built from c.env.USERNAME and c.env.PASSWORD, and the middleware and api sub-apps are both mounted at /api, so a route added to one but not matched by the other's path pattern silently skips auth. Validation: pages-stack/functions/api/[[route]].ts is the only example that validates input, with zValidator('query', z.object({ name: z.string() })) and c.req.valid('query'), and it exports AppType for the hc client; blog/src/api.ts calls await c.req.json() with no guard before model.createPost. Runtime-specific APIs: durable-objects/src/counter.ts extends DurableObject from cloudflare:workers and wrangler.toml carries a migrations entry with tag = "v1" and new_classes = ["Counter"]; env-vars/src/index.ts builds a Stripe client per request from LIVEMODE, STRIPE_RK and STRIPE_TK bindings; stytch-auth/api/TodoAPI.ts uses Consumer.authenticateSessionLocal() for reads and authenticateSessionRemote() for writes.

For each candidate finding the agent checks whether an existing test pins the behaviour and, where it can, writes a short Vitest case in the sandbox to confirm it before posting, without adding that case to the branch. One GitHub review is posted per run: the summary quotes the vitest --run and tsc --noEmit results for each touched example, separates blocking issues from suggestions, and every finding cites file and line. A middleware registered after the route it was meant to protect is blocking; a // @ts-ignore like the one on /type-error in the basic example is a suggestion unless the pull request added it. The agent pushes nothing.

Start it with one API call

POST https://api.prix.dev/o/{org}/sessions with this body:

{
  "agent": "claude",
  "input": "Review this pull request on a Hono API. Check it out, run npm install at the root, and for every workspace the diff touches run npx tsc --noEmit -p <example> and npm test -w <example> where a test script exists; for blog, copy wrangler.example.toml to wrangler.toml first so the Workers test pool can start. Read the diff with the surrounding src/index.ts, the sub-apps it mounts and the wrangler config. Look for middleware registered after the routes it should wrap or on a path pattern that misses a new route, routes under /api added after the catch-all 404, request bodies read with c.req.json() and no validation where the example already uses zValidator, Durable Object classes changed without a migrations entry, and bindings read from globals instead of c.env. Confirm a finding with a short Vitest case in the sandbox where you can, but do not add it to the branch. Post one GitHub review that quotes the test and type-check results, separates blocking issues from suggestions, and cites file and line for every finding. Do not push commits.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app/pull/42"
    }
  ]
}
  1. Get an API key. In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
  2. Send the request. POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
  3. Read what came back. Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

What comes back

What comes back is a review on the pull request. Its summary quotes vitest --run for basic or blog when the diff touches them, including the Workers pool's own output for blog, and tsc --noEmit for every touched workspace. Findings follow with file and line in the example they belong to, marked blocking or suggestion, and a finding about auth names the path pattern in index.ts that the new route falls outside.

The transcript keeps the npm install, the copied wrangler.toml, every command with its output, and the short test cases the agent wrote to confirm a finding, so when the review says a POST to a new route skips basicAuth, the request that proved it is there to read.

Before merging, a reviewer runs the touched example's test script on the branch, opens each cited line, and decides which suggestions to take. A route that bypasses auth or a Durable Object change without a migration is blocking by default; a request to add validation to an example that never had it is a suggestion.

Run it on every pull request opened

Create an automation in the Project with a github trigger on pull_request.opened and pull_request.synchronize, branch_patterns set to main, and this prompt. The trigger adds the pull request after the prompt, so each pull request and each push to it gets its own sandbox, its own npm install and its own review. Only pull requests by an owner, member or collaborator fire it; one from a fork never does.

Set read_only on the automation so its runs can comment but not push. The review is the result and shows on the pull request; the run is listed in the Project. The automation's max_runs_per_hour, 1 to 30, bounds a Dependabot morning, since this repository takes daily npm updates; a fire past the cap is skipped as rate_limited and that pull request waits for its next push.

The use case this job follows, with its automation and trigger: Review every pull request.

Why run it on Rush?

This repository has no CI, so a pull request is checked only if someone installs the workspace, creates the missing wrangler.toml, starts the Workers test pool and runs tsc against each example's own tsconfig.json. That is the setup a reviewer skips when the diff is twenty lines. On Rush the agent does it in its own sandbox and keeps every command and its output, so the review rests on an executed test rather than a reading, and the author sees what a type error in durable-objects looks like before a Cloudflare deploy would.

One sandbox per pull request means a change to blog and a change to stytch-auth are reviewed at the same time without one install clobbering the other, and nothing is pushed to the branch. The reviewer gets findings with the test output attached and the author keeps their checkout as it was.

Frequently asked questions

Which examples get a test run?

Only basic and blog have test scripts, so those run under Vitest when the diff touches them. Every other touched workspace gets tsc --noEmit against its own tsconfig.json, and the review says which checks ran for which example rather than implying a suite that does not exist.

Why does the blog test need a wrangler.toml?

blog/vitest.config.ts points the Workers pool at ./wrangler.toml for the BLOG_EXAMPLE KV binding, but only wrangler.example.toml is in the repository. The agent copies it, which is enough for the pool's local KV, and leaves the copy out of the branch.

Does it review the Deno and Bun examples?

It reads them, since they are plain Hono apps, and the sandbox can run deno run --allow-net hello.ts and bun run hello.ts as the README shows to confirm they start. They are outside the npm workspace, so there is no tsc project or test script for them, and the review labels those findings as read rather than executed.

What does it do with the hard-coded basic-auth password in the basic example?

basic/src/index.ts registers basicAuth({ username: 'hono', password: 'acoolproject' }) on /auth/*, which is fine for an example. The review raises it only if the pull request copies that pattern into blog or stytch-auth, where credentials already come from bindings.