Your CI, on the edge. Define your pipeline in .anvil.yml, push to trigger, and watch runs execute in isolated containers β all on Cloudflare Workers. No servers to manage, no runners to babysit.
π‘ Container execution requires a Workers Paid plan ($5/mo). D1, Queues, Workflows, KV, and Durable Objects work on Free or Paid with platform-specific limits.
Built with GPT-5.4 and Claude Opus 4.6 agentic workflows. π€β¨
Upgrading an existing deployment from legacy invite/password auth? Follow MIGRATION-OIDC.md before deploying latest.
anvil is a Cloudflare-native CI runner built for personal projects and small teams. If you've ever wanted a simple, self-hosted CI that doesn't require maintaining VMs, Docker daemons, or long-running processes β anvil runs entirely on Cloudflare's managed platform.
Push code β anvil picks it up β runs your steps in an isolated container β streams logs back to your browser in real time. That's it.
# .anvil.yml
version: 1
checkout:
depth: 1
run:
workingDirectory: .
timeoutSeconds: 720
steps:
- name: install
run: npm ci
- name: test
run: npm test
- name: build
run: npm run buildDrop this in your repo root, point anvil at it, and you're running CI. β‘
π§ Repository-defined pipelines β version your CI config in .anvil.yml, right next to your code
π¦ Isolated sandbox execution β every run gets a fresh container. No leftover state, no cross-run contamination
π‘ Live log streaming β watch stdout/stderr flow in real time via WebSocket, with ANSI color support
π Webhook triggers β push to GitHub, GitLab, or Gitea and anvil picks it up automatically. Per-provider secrets with rotation and delivery history
π FIFO run queue β one active run per project, the rest queue up in order. No race conditions, no surprises
π§ Selectable dispatch mode β keep the existing Queue-backed path or use Cloudflare Workflows for durable orchestration
π tessera OIDC access β no anvil passwords or invites. Verified tessera identities auto-provision or bind to existing users by email
π Any HTTPS Git repo β GitHub, GitLab, Gitea, or any repo reachable over HTTPS with optional token auth
π‘οΈ Security baked in β encrypted credentials at rest, automatic secret redaction in logs, strict CSP, same-origin mutation guards, and HttpOnly cookie sessions
- Workers β stateless HTTP frontdoor: routing, auth, dispatch trigger
- ProjectDO β per-project state machine: active run lock, pending queue, dispatch mode, webhook config
- RunDO β per-run state: steps, rolling logs, WebSocket fanout to browsers
- D1 β durable relational index: users, tessera identities, projects, run history
- KV β ephemeral session storage with TTL
- Dispatch β Queue-backed or Workflow-backed run orchestration, both preserving FIFO at the project level
- Sandbox β isolated container per run via
@cloudflare/sandbox
| What | Why | |
|---|---|---|
| π₯οΈ | React 19, React Router 7, Tailwind CSS 4, Vite 7 | Modern frontend with fast HMR |
| βοΈ | Hono on Cloudflare Workers | Lightweight, edge-native HTTP framework |
| πΎ | D1 (SQLite), Durable Objects (SQLite), KV | Right storage for each access pattern |
| ποΈ | Drizzle ORM | Type-safe database access across D1 and DO SQLite |
| π¦ | Cloudflare Containers, Queues, Workflows | Isolated execution with ordered dispatch |
| β | @cloudflare/util-en-garde |
Runtime codec validation at every boundary |
| π€ | TypeScript (strict) throughout | One language, zero escape hatches |
git clone <repo-url>
cd anvil
npm install
cp .dev.vars.example .dev.vars # local encryption and tessera OIDC settings
npm run db:migrate:d1:local # set up local D1
npm run dev # π goPoint the tessera OIDC values in .dev.vars at a reachable tessera issuer, then open the URL from the terminal and sign in with tessera. First sign-in creates or binds the anvil user from the verified OIDC email.
src/
client/ π₯οΈ React frontend (pages, components, hooks)
worker/ βοΈ Cloudflare Workers backend
api/ Route handlers (public + private)
auth/ OIDC, cookie sessions, and auth middleware
db/ D1 and Durable Object schemas (Drizzle)
dispatch/ Queue + Workflow dispatch and shared execution
durable/ ProjectDO and RunDO
sandbox/ Container lifecycle
contracts/ π Shared client/server API types
lib/ π§ Shared utilities
tests/
worker/ β‘ Fast Vitest unit tests
e2e/ π Playwright browser tests
integration/ π Queue and Workflow runner integration tests
drizzle/ π¦ Generated migrations (do not edit)
docker/ π³ Runner container image
reference/ π Specs and design docs
| Command | What it does |
|---|---|
npm run dev |
Start local dev server |
npm run build |
Production build |
npm test |
Fast Vitest suite |
npm run test:e2e |
Playwright browser tests |
npm run test:integration:queue |
Queue-backed live integration test |
npm run test:integration:workflows |
Workflow-backed live integration test |
npm run typecheck |
Full TypeScript type check |
npm run db:generate |
Regenerate Drizzle migrations from schema |
npm run deploy |
Remote D1 migrate, production build, deploy |
npm run format |
Prettier formatting |
See OPERATOR.md for the full script reference, deployment guide, database operations, testing strategy, and Cloudflare binding details.
npx wrangler login
npm run deploynpm run deploy applies remote D1 migrations first, then builds and deploys the Worker. Production deployments need fresh encryption keys plus tessera OIDC client credentials configured as Worker secrets. Existing password/invite deployments should complete the OIDC migration first. For the full deployment guide, environment setup, and binding reference, see OPERATOR.md. π
anvil takes security seriously even at v1:
- π AES-GCM encryption at rest for repo tokens and webhook secrets
- π Automatic secret redaction in all run logs
- π Strict CSP β no inline scripts and no
eval - π tessera OIDC sign-in with verified-email identity binding
- π§ Same-origin guard on cookie-bound mutations
- πͺ KV sessions with TTL, carried in a Secure HttpOnly
__Host-anvil_sessioncookie
anvil is under active development. The codebase uses strict TypeScript throughout, with codec-validated boundaries and a clear separation between Workers (stateless) and Durable Objects (stateful, transactional).
If you're diving in, start with the spec and the operator guide.
MIT β Rachel Chen, 2026