checkrd

Cloudflare Workers

Run Checkrd at the edge with policy enforcement in workerd at sub-millisecond overhead.

Cloudflare Workers

Checkrd is built to run at the edge. The WASM core is wasm32-wasip1, a clean format Cloudflare Workers' runtime (workerd) loads natively via WebAssembly.compile. No node:* shims, no Node polyfills.

Install

bash
npm install checkrd

Quickstart

typescript
import OpenAI from "openai";
import { withCheckrd } from "checkrd/cloudflare";

interface Env {
  CHECKRD_API_KEY: string;
  OPENAI_API_KEY: string;
}

export default {
  fetch: withCheckrd<Env>(
    async (request, env, _ctx, fetch) => {
      // `fetch` is Checkrd-enforced. Plug it into any vendor SDK
      // that accepts a `fetch` option.
      const openai = new OpenAI({ fetch, apiKey: env.OPENAI_API_KEY });
      const out = await openai.chat.completions.create({
        model: "gpt-4o-mini",
        messages: [{ role: "user", content: await request.text() }],
      });
      return Response.json(out);
    },
    (env) => ({
      apiKey: env.CHECKRD_API_KEY,
      agentId: "01234567-89ab-cdef-0123-456789abcdef",
    }),
  ),
};

withCheckrd(handler, optionsFn) is a HOC that:

  1. Initializes the WASM engine on first request and caches it across the worker's lifetime (Workers reuse isolates).
  2. Resolves options per-request from the bound env. The second argument is a (env) => options factory, NOT a plain object. This lets secrets flow from Cloudflare bindings without process.env.
  3. Passes a Checkrd-enforced fetch as the handler's fourth argument; pipe it into OpenAI / Anthropic / Vercel AI SDK clients.

With the Vercel AI SDK

typescript
import { withCheckrd } from "checkrd/cloudflare";
import { checkrdMiddleware } from "checkrd/ai-sdk";
import { getEngine, getSink } from "checkrd";
import { generateText, wrapLanguageModel } from "ai";
import { openai } from "@ai-sdk/openai";

export default {
  fetch: withCheckrd<Env>(
    async (request, env, _ctx, _fetch) => {
      const model = wrapLanguageModel({
        model: openai("gpt-4o"),
        middleware: checkrdMiddleware({
          engine: getEngine(),
          enforce: true,
          agentId: "01234567-89ab-cdef-0123-456789abcdef",
          sink: getSink(),
        }),
      });

      const { text } = await generateText({
        model,
        prompt: await request.text(),
      });

      return new Response(text);
    },
    (env) => ({ apiKey: env.CHECKRD_API_KEY, agentId: "01234567-89ab-cdef-0123-456789abcdef" }),
  ),
};

Loading the policy

Don't pass policy:. With an apiKey configured (as in every example above), the SDK fetches your agent's currently-published DSSE-signed bundle from GET /v1/agents/:id/control/state on the first request and installs it before your handler runs. The signed-bundle SSE channel streams updates to the long-lived isolate in milliseconds — no redeploy required.

Workers have no filesystem, so the dashboard is the only place a Workers operator should edit policy. The pattern doubles as a way to push hotfixes without re-publishing to Cloudflare.

Telemetry

The default sink in Workers buffers events in memory and flushes via ctx.waitUntil(...) at the end of each request. No daemon thread, no polling; fits the workerd lifecycle.

typescript
(env) => ({
  apiKey: env.CHECKRD_API_KEY,
  agentId: "01234567-89ab-cdef-0123-456789abcdef",
  // sink is auto-configured against env.CHECKRD_API_KEY; override only if needed.
})

Caveats

  • No node:* imports. Don't pass policy: fs.readFileSync(...); that path is Node-only. Pass the policy as a string in policy: after fetching it from R2, KV, or a bundled import.
  • Cold start. First request loads the WASM (~10ms cold). Subsequent requests reuse the compiled module across the isolate's lifetime. For sub-ms p99, keep your worker hot via Cloudflare's Smart Placement.
  • Cloudflare-specific globals. The Cloudflare adapter uses crypto.subtle for SHA-256 (the WASM integrity check) and WebAssembly.compile for module loading; both are workerd built-ins. No polyfill required.