Description
Part of #2326. Moved here from the note in PR #2234 (research, October 2026). Already filed from it: #2235 (bump to beta.84 and telemetry), #2236 (drift, closed), #2237 (postgresState), #2238 (previews).
Still to file or do
-
rustybuns teston Alchemy's test harness (row 4), run against the preview stages. - Read
@alchemy.run/gitnext to codeSplitter's merge code and file what is worth taking (row 6). - Gradual rollout via Worker
version(row 5); AI Gateway as a spend cap (row 10); Access/Turnstile (row 9); the rest as apps need them. - Every row that creates resources costs money at scale: price it first (
packages/cli/src/costs.ts, COSTS.md).
Full note
What Alchemy offers that we don't use
Research, October 2026. Sam Goodwin (Alchemy's author), on hearing we use it as our deployment factory:
"Alchemy is about much more than deployment". This maps that "much more" against what
packages/cli/src/gen/alchemy.ts generates today. Sources: the package we install (alchemy@2.0.0-beta.77, read
under node_modules/.bun/alchemy@2.0.0-beta.77+*/node_modules/alchemy/src), the docs at
alchemy.run (also served to agents as llms.txt), and the
release notes.
The short answer: v2 is an Effect application framework, and deploying is one part of it. It also runs the app
locally against emulators, tests it against real throwaway stages, gives every PR its own preview, notices
when the account drifts, and ships libraries that run on Workers: a git server, Better Auth, typed RPC
between Workers. Everything below is beta; the README says "Expect breaking changes".
What we use now
The generator writes .rustybuns/alchemy.run.ts from rustybuns.config.ts, and the CLI runs alchemy plan,
deploy, destroy and dev on it. In that file:
- Cloudflare:
Worker(domain, routes, crons, observability, placement, limits, assets, workersDev),
DurableObject,D1,KV,R2,Queues(queue and consumer),Vectorize(and metadata indexes),
Hyperdrive,RateLimit,Images,Email.SendEmail,Container,Artifacts,Workflow,WorkerLoader,
AnalyticsEngine,Workers.AI,InferEnvfor the typed env. - Elsewhere:
Command.Build,Hetzner.Server/Volume/Service,Railway.Project/Service/Volume,
Neon.Project/Branch,Alchemy.makeRandomfor minted secrets. - Policies:
AdoptPolicy.adopt,RemovalPolicy.retain(protect: true),renamedFrom. - State:
Alchemy.localState(), whichpackages/cli/src/state.tssymlinks into the git common dir and guards
with its own lock so every worktree on one machine sees one state per app.
That is the classic async-Worker style: our app code never imports Alchemy or Effect. Most of what follows
keeps it that way; the rows that don't say so.
Before anything else: the version
We pin 2.0.0-beta.77; npm's latest is 2.0.0-beta.84 (October 24, 2026). beta.84 is a
breaking package split: Cloudflare, AWS,
Git, Drizzle and others moved to their own @alchemy.run/* packages, so the generator's
import * as Cloudflare from "alchemy/Cloudflare" changes, as does the pin in packages/cli/src/glue/deploy-deps.ts.
beta.78 also took Alchemist out of the root export. The bump is its own PR, with a plan diff on codeSplitter's
stack that shows no replaces.
beta.77 also lists seven exports in package.json with no file behind them (Construct, ContentType,
Endpoint, Process, TUI, Util/Clank, Cloudflare/Live); nothing there to adopt. Nothing called Clank
appears in the repo or docs either.
Worth taking, ranked
| # | Alchemy piece | What it gives us | Replaces / adds | Size |
|---|---|---|---|---|
| 1 | Drift: alchemy drift, Drift.detect/plan/repair |
Re-reads the live account and shows what no longer matches state (a dashboard edit, a wrangler deploy, a deleted bucket); --repair --yes puts it back |
Nothing: rustybuns plan only diffs config against state. Read-only by default, so cheap to add as rustybuns drift |
S |
| 2 | Remote state: postgresState(), Cloudflare.state() |
One state per stage that CI, the cloud office and every machine see. postgresState takes a per-(stack, stage) advisory lock |
Our symlink-into-.git plus lock in state.ts, which only works on one machine. A deploy from CI today starts from empty state. We already make Neon, so postgresState is the natural pick; the Cloudflare store's locking isn't documented, and its Worker sends telemetry even when ours is off (see below). State.Sync/Export move existing state across |
M |
| 3 | Worker Previews (preview: { of: parent }) plus per-PR stages in CI and GitHub.Comment |
Each PR gets its own URL with its own Durable Objects; the comment on the PR is kept up to date; the stage goes when the PR closes | Nothing: we have no preview deploys. Fits codeSplitter's review flow and Agent Office's "show me it running". Needs #2 first so CI sees state | M, plus a manual run for the CI token |
| 4 | Test harness: alchemy/Test/Bun Test.make, Test/Http getWhenReady |
A suite deploys a real stack once (test_$USER or ci-pr-42), hits it, destroys it; dev: true runs the same suite on the local emulators |
ROADMAP item 6 (rustybuns test, "local workerd via Alchemy's test harness"), unbuilt. Also a path to the "one journey through the running app" tests AGENTS.md asks for |
M |
| 5 | Worker version (traffic, alias, tag, message) |
Gradual rollout: a new version at 10% before 100%, and stable preview aliases | Partly drain.ts. A canary is the gentler deploy for codeSplitter's rooms |
S |
| 6 | @alchemy.run/git |
A git server on Workers, DOs and R2: smart HTTP, a typed REST plane with pull requests (server-side merge base, tree diffs, ff and three-way merge) and a GitHub REST v3 facade that gh and Octokit can point at |
codeSplitter's own git plumbing (mirror.ts, merges, its GitHub-shaped API). Not a swap: codeSplitter stands on Cloudflare Artifacts and its own merge rules. Worth reading for the GitHub facade and the merge code, and comparing on the cases codeSplitter's tests already walk |
Read: S. Adopt: L |
| 7 | GitHub.Secrets / Variables / Environment, a minted Cloudflare.ApiToken |
CI credentials as code: the stack mints a scoped Cloudflare token and writes it to the repo's secrets | Hand-set repo secrets. The owner's call (AGENTS.md: secrets and settings are the owner's), so a stack the owner runs | S, owner-run |
| 8 | Workers.Route, DNS.Record, Zone, CustomHostname |
Domains and DNS in the stack | Dashboard DNS for codeSplitter and the demos | S |
| 9 | Access + the Worker access prop; Turnstile.Widget |
Cloudflare Access in front of a preview stage or an admin page; a bot check on public forms | Bearer tokens on human-facing admin routes; hand-made Turnstile widgets | S |
| 10 | AI.Gateway (+ ProviderKey) |
Caching, rate limits and spend caps in front of model calls | Nothing: no app routes model calls through a gateway today. A cost guard (excalibrawl ran its credit dry) | S |
| 11 | Command.Exec, Command.Dev, alchemy logs --tail |
A migration or seed step in the deploy graph; a Vite or Bun dev server inside alchemy dev; every resource's logs in one tail |
Pre-deploy steps the CLI runs by hand; per-Worker wrangler tail |
S |
| 12 | Workers.ObservabilityDestination, Logpush.Job, Axiom.* |
Our app's logs and traces shipped somewhere queryable, dashboards and monitors as resources | Only the Workers dashboard today. Costs money; price first | S-M |
| 13 | Typed RPC (Workers.bindWorker, RpcDurableObject, schemaless RPC) |
One schema on both ends of a Worker-to-DO call | codeSplitter's stub.fetch(new Request(...)) plus JSON bodies (privacy.ts, cuts.ts). Pulls Effect into Worker code, which AGENTS.md keeps at the edges; Cloudflare's own DO RPC (stub.method()) gets most of this with no Alchemy |
L |
Also there, no use yet
- Libraries that run on Workers:
@alchemy.run/better-auth(Better Auth with a D1 layer, six-part tutorial),
@alchemy.run/domain(commands, aggregates, events; beta.84), Effect AILanguageModel, AI Search, Effect SQL. - Cloudflare:
Pipelines,Browser,Flagship(feature flags),Stream,SecretsStore,Pages,
Website.*(Vite, StaticSite, Astro, Next, Nuxt, SvelteKit, TanStack Start),WorkersForPlatforms,Tunnel,
LoadBalancer, WAFRuleset,Alerting, Email Routing, R2 event notifications, MCP Portal. - Other providers: AWS (with local emulation), GCP, Docker, Kubernetes (Helm, kind), Fly, PlanetScale,
Prisma Postgres, Turso, Stripe, and the rest of Hetzner (Firewall, Network, DNS) and Railway (Postgres, Redis,
Bucket, domains). Neon branches per PR go with Fix desktop builds on Windows for apps with "use server" actions #3. - Data: Drizzle and Prisma with committed migrations applied on deploy,
SQL.Migrations,Neon.Migrations. - Tooling:
Alchemist(the CLI as an Effect API: Stack, Drift, Logs, State; the hook for an agent or the office
to drive deploys without shelling out), thealchemy-testrunner (agent-friendly output, one Bun process),
alchemy state list|read,alchemy profile,KeyPair, custom providers and "Actions" for anything missing. alchemy unsafe nukedeletes every resource the providers can list, whatever the stack or state. It is hidden
from--helpso agents don't find it; ours must never run it (--localonly wipes the emulators).
Things to know either way
- Telemetry is on by default. The CLI sends a random id, hashes of the git origin and branch, the repo's root
commit SHA, and the command, resource types and operations tootel.alchemy.run(no secrets, values or source).
DO_NOT_TRACK=1orALCHEMY_TELEMETRY_DISABLED=1turns it off, and our sandbox Dockerfiles already set
DO_NOT_TRACK;rustybunsdoesn't when it runsalchemy. The Cloudflare state store's Worker sends its own
signals even then. (privacy) - Agent mode. The CLI notices
CLAUDECODE,CURSOR_AGENTandCODEX_CLI, prints plain output and needs
--yesto apply.alchemy.run/llms.txtand every page as.mdare written for agents. - No hosted service, no pricing. Everything runs in our own accounts; Alchemy is open source.
Suggested order
- Bump to beta.84 alone (#2235), with the import rename and a plan diff on codeSplitter's stack. Set
DO_NOT_TRACK=1in the envrustybunsgivesalchemy, or say in the docs that it's on. rustybuns drift(updating for hetzner and readme #1), #2236: small, read-only, and it shows whether the bump or anything else moved the account.postgresStateon the Neon we already make (Restore desktop.host, desktop.headers, desktop.native #2) (#2237), then Worker Previews per PR (Fix desktop builds on Windows for apps with "use server" actions #3) (#2238) on top.rustybuns teston the test harness (add plans for things CF just released! #4), run against those preview stages.- Read
@alchemy.run/git(update init #6) next to codeSplitter's merge code and file what's worth taking. - The rest as the apps need them. Every row that creates resources costs money at scale; price it first and
keep the smallest tier (packages/cli/src/costs.ts, COSTS.md).
Activity