Effect customer runtime #
The customer Worker composes application work with Effect while Cloudflare Agents,
Think, Workers AI, Browser Run, and Sandbox retain their native responsibilities.
This implements the migration plan from
945d0cd. Dependency versions, exported Durable Object classes, storage formats,
native callback names, and public payloads remain unchanged.
No additional Distilled package is needed for these paths. Distilled continues to serve Cloudflare management operations in the control plane. Customer operations use native bindings or Flarebot's own publisher protocol; they do not acquire publisher management credentials. Alchemy is not introduced.
Where the code lives #
| Responsibility | Application code | Native boundary |
|---|---|---|
| Routing, sessions, login and update checks | http.ts, session.ts, bridge.ts, update-on-visit.ts |
Worker fetch, socket hooks |
| Domain receipts and bootstrap health | instance-management.ts, server/bridge.ts |
Parent RPC and waitUntil |
| Models, credentials, instructions and memory | personal-models.ts, model-settings.ts, personal-memory.ts |
Validated parent callables/RPC |
| Conversation creation, naming and deletion | personal-conversations.ts |
Parent facet registry and lifecycle |
| Turn preparation, actions and task submissions | conversation-turn.ts, conversation-actions.ts, conversation-tasks.ts |
Think hooks, actions and submission queue |
| Research | web-search.ts, web-read.ts, browser-read.ts, browser-session.ts |
AI binding, Think fetch and native CDP |
| Temporary resources | browser-leases.ts, shell-leases.ts, shell-execution.ts |
Parent leases/alarms and native Sandbox |
| Tasks and reconciliation | task-store.ts, task-execution.ts |
Native schedules and Think receipts |
| Model streams and diagnostics | model-provider.ts, gateway-model.ts, diagnostic-export.ts |
AI SDK middleware, stream callbacks and native observers |
Paths without a prefix are under worker/. Modules accept small capabilities,
not a shared runtime containing every binding. The native parent remains the
composition point. Synchronous SQL transactions, validation, projections, model
factories and metadata hooks stay synchronous.
Execution and resource ownership #
Application programs return Effects. HTTP, RPC, SDK callbacks and async iterators
run them at the native boundary. agent-io.ts supplies a small native RPC adapter,
safe tagged failures, and a pre-abort check. Provider adapters retain HTTP failure
metadata only long enough to classify it; public errors and observations remain
sanitized. Shared server crypto is separate from frontend-safe bridge contracts.
Cancellation does not imply that a native RPC stopped. Conversation deletion gates access before asynchronous cleanup. Browser creation and shell launch continuations remain owned by the surviving parent, with durable leases and native alarms as the restart fallback. A late shell launch still requires another destroy after an earlier close. Pending teardown continues to occupy capacity.
WebDeadline is now an Effect adapter around one absolute browser lifetime. Its
native signal and timer also govern detached acquisition; interrupting only the
waiting fiber would lose that guarantee. CDP connections and remote sessions have
scoped finalizers. Cleanup uses its own budget. HTTP reader cancellation is bounded
and releases its lock even when cancellation never resolves.
Shell output is an Effect Stream exposed through the AI SDK's async-iterator contract. Its scope lasts through consumption, closes on early iterator return, and finishes cleanup before emitting the final result. The native Sandbox SSE parser, incremental output, UTF-8 byte limit, and parent-owned late launch remain intact. Model streams retain their native backpressure and reasoning metadata.
Native Agents still own retries and durable scheduling. Reconciliation reuses the same task/submission identity and rechecks authorization after asynchronous work. Repair batches retain their row limit and now enforce their time budget even when a native observation stalls. There is no additional blanket Effect retry layer.
The remaining async methods are native protocol adapters or synchronous native
hooks whose Promise signatures support SDK/fixture overrides. Remaining Promises
coordinate parent-owned in-flight cleanup, adapt SDK/native results, or carry work
to waitUntil; none is persisted. Ephemeral fibers and scopes are rebuilt after
activation.
Validation #
The migration includes focused type contracts and behavioral tests in
tests/customer-runtime-effect.*. They cover pre-abort without a request, native
body cancellation, stalled finalizers, safe provider failures, native SSE cleanup,
early iterator return, late reservation, and bounded UTF-8 output. Existing native
fixtures exercise version checks, deletion, replay, background work and restart.
Local validation completed against the migrated application:
| Check | Result |
|---|---|
| Application and Worker typechecks; customer release build | Passed |
| Focused customer Effect behavior | 8 passed |
| Native runtime, conversations, memory, tools, diagnostics and tasks | 29 passed |
| Unattended execution, races and restart recovery | 17 passed |
| Packaged chat, settings, domain, tasks and update UI | 30 passed |
| Model provider protocol and stream behavior | 18 passed |
| Publisher OAuth and bundle separation | 4 passed |
| Catalog, deployment, gateway, installation UI and native orchestration | 46 passed |
| Pre-migration artifact upgrade | Passed |
Control-plane Effect, signed bridge, domain, ownership, update and permission manifest regressions also pass. The OAuth fixture closes its HTTP connections because it restarts different Workers behind the same origin; pooled connections could otherwise target the stopped process.
The upgrade gate can compile its first artifact from a separate source checkout:
FLAREBOT_UPGRADE_BASELINE=/path/to/baseline pnpm test:upgrade-state
The checkout needs the pinned dependencies and generated SSR bundle. The gate
compiles both immutable artifacts, replaces the Worker against the same native
storage, checks login, SQLite, facets, encrypted credentials and scheduled execution,
and verifies that the recorded artifact bytes have not changed. This migration
was checked from 945d0cd to the candidate, not just with two builds of new code.
Build measurements on the same ARM workstation:
| Dry-run customer upload | Before | After |
|---|---|---|
| Raw | 11,442.89 KiB | 11,646.76 KiB |
| Gzip | 2,263.87 KiB | 2,306.08 KiB |
The gzip increase is about 42 KiB (1.9%). Wrangler dry-run did not report a startup CPU measurement. These are local build measurements, not production latency data.
Three alternating fresh Miniflare instances per artifact measured the first authenticated parent status request after Worker readiness, then the first conversation-facet creation over the native socket. Median parent readiness was 12.5 ms before and 13.0 ms after; median facet creation was 7.4 ms before and 7.2 ms after. This small local sample checks for an obvious regression and does not measure deployment startup CPU or production cold starts.
Native browser race cases pass, including late creation/connection, registration failure, cancellation and cleanup. Full rendered-browser testing is currently limited by Miniflare downloading an x86 Chrome binary on this ARM host; the FEX launcher fails. The native shell suite reaches the local Podman socket, but its network sidecar cannot start because crun rejects the requested memory-swappiness setting under cgroup v2. The two-site bridge suite reaches bootstrap health and then encounters the same container limitation. The connected golden-path suite was not run because it requires those native services. These are not passing end-to-end container/browser checks. Paid live search was skipped as opt-in.