A curated library of author-voice specifications for AI agents — served from a single Cloudflare Worker.
The Worker exposes a read-only REST API at /v1/* and a React SPA catalog. Each guide is a structured voice profile (persona, lexicon, syntax, rubric, exemplars) that can be rendered against an input via POST /v1/apply, with model calls routed through Cloudflare AI Gateway.
The runnable app lives in apps/quill/. This is a pnpm workspace.
- Runtime — Cloudflare Workers (Wrangler v4,
wrangler.jsonc) - Backend — Hono with REST API at
/v1/*, Zod validation at the boundary - Frontend — React 19 + Vite, served as static assets from the same Worker
- Routing — TanStack Router (file-based, code-split)
- Data — TanStack Query, Drizzle ORM targeting D1
- UI — Strand design tokens (Tailwind v4) + bespoke editorial primitives, with
@cloudflare/kumowired in for incremental migration - Auth — Better Auth (scaffolded; full wiring deferred)
- Secrets — Doppler in development, mirrored to Wrangler secrets in production via
apps/quill/scripts/bootstrap.sh
pnpm install
pnpm --filter postpilot devVite serves the SPA on http://localhost:5173 and the Worker handles /v1/* on the same port.
GET /v1/health— runtime + envGET /v1/guides[?era=...&useCase=...&voice=...&q=...]— list with filtersGET /v1/guides/:slug[?format=json|yaml|prompt]— single guideGET /v1/guides/:slug/exemplarsGET /v1/guides/:slug/rubricGET /v1/presets— use-case presetsPOST /v1/apply— render a guide+preset against an input. Returns generated text plus a deterministic rubric snapshot. Routes through AI Gateway whenAI_GATEWAY_BASE_URL+AI_GATEWAY_TOKENare set; otherwise returns a deterministic stub.
You'll need:
- A Cloudflare account with API token (
CLOUDFLARE_API_TOKEN,CLOUDFLARE_ACCOUNT_ID) - A Doppler project with a service token (
DOPPLER_TOKEN) wrangler,doppler,jq,nodeon your PATH
Then:
cd apps/quill
doppler setup # link to your Doppler project once
./scripts/bootstrap.sh # creates D1 + KV + R2, patches wrangler.jsonc,
# generates BETTER_AUTH_SECRET, applies migrationsThe script is idempotent.
cd apps/quill
pnpm cf-typegen # regenerate worker-configuration.d.ts
pnpm cf-deploy # vite build && wrangler deployUse pnpm cf-deploy, not pnpm deploy — the latter is a pnpm built-in for workspace deploys.
apps/quill/
src/
index.ts Hono Worker entry
routes/ Hono route modules (guides, presets, apply, health)
middleware/ per-request context + error handling
db/schema.ts Drizzle schema (D1)
lib/
guides/ seed guide JSON-as-TS files
types.ts presets.ts rubric.ts export.ts utils.ts
client/
main.tsx entry
index.css Tailwind v4 + Strand tokens + Kumo @source
routes/ TanStack Router file-based routes
components/ editorial primitives + page components
lib/api.ts TanStack Query client + typed fetchers
routeTree.gen.ts generated by router plugin (committed)
scripts/
bootstrap.sh provisions D1/KV/R2 + secrets via Doppler
patch-wrangler.mjs fills resource ids into wrangler.jsonc
drizzle/ migrations (generated)
wrangler.jsonc Worker config
vite.config.ts Vite + Cloudflare + TanStack Router + Tailwind
Catalog, library, detail view, read-only API, and playground stub are shipped. The following are scaffolded but not wired:
- Auth — Better Auth via
better-auth-cloudflare(Drizzle schema is ready) - AI Gateway —
POST /v1/applycalls the gateway only whenAI_GATEWAY_BASE_URL+AI_GATEWAY_TOKENare set; otherwise returns a stub - Eval harness — judge scoring is the deterministic snapshot only
- Composer / forks / collections / API keys — UI not built yet
- Kumo migration — Kumo dep is wired with Tailwind
@source; bespoke editorial primitives still in use. Runnpx @cloudflare/kumo doc Buttonand swap incrementally.