feat(dev): own the local Workflow World in the CLI parent process#790
Open
ctgowrie wants to merge 10 commits into
Open
feat(dev): own the local Workflow World in the CLI parent process#790ctgowrie wants to merge 10 commits into
ctgowrie wants to merge 10 commits into
Conversation
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| compiledArtifactsBootstrapPath: string; | ||
| configuredWorld: AgentWorkflowWorldDefinition | undefined; | ||
| }): string { | ||
| const packageName = getWorldImport({ WORKFLOW_TARGET_WORLD: input.configuredWorld ?? "local" }); |
Contributor
a69e44e to
ad41594
Compare
fea3670 to
a5e3770
Compare
a5e3770 to
d5183f3
Compare
ad41594 to
2eec894
Compare
2eec894 to
98c9d48
Compare
d5183f3 to
126af1c
Compare
98c9d48 to
51ba184
Compare
126af1c to
38695d1
Compare
Instantiate the vendored local World once in the dev CLI parent so child Workflow runs survive worker replacement. Workers reach the World through an RPC codec over the public listener guarded by a per-process secret, and queue deliveries resolve their generation server-side from run records — turns keep their generation's authored modules while executing in the current worker. Generation pruning now retains only generations still referenced by active Workflow work. Co-Authored-By: Claude Fable 5 <[email protected]> Signed-off-by: Casey Gowrie <[email protected]>
The World begins redelivering persisted queue messages the moment it starts, but the parent registered its control handler only after the authored-source watcher was up. Deliveries in that window reached the worker, whose World calls back to the parent fell through to the worker app and 404ed. Register the control handler before the listener binds, late-binding the watcher; rebuild requests before the watcher exists answer 503. Co-Authored-By: Claude Fable 5 <[email protected]> Signed-off-by: Casey Gowrie <[email protected]>
The generated worker plugin selects the parent RPC World client whenever the configured world resolves to the vendored local package — including an explicit `world: "local"` — but the parent only created its World when the config was absent, so explicitly-local apps failed every World call in dev. Share one predicate between the parent and the generated plugin so the two sides cannot disagree. Co-Authored-By: Claude Fable 5 <[email protected]> Signed-off-by: Casey Gowrie <[email protected]>
Document the intent behind the parent-owned World and its worker shim: the World's lifetime must match run data rather than the disposable worker, the already-async World interface is what makes an interface-faithful HTTP client transparent to the runtime, deliveries ride the public listener so drained replacement covers them, and the worker plugin's world selection shares one predicate with the parent. Also document the rebuild coordinator's worker-first commit ordering and the codec's reason to exist. Co-Authored-By: Claude Fable 5 <[email protected]> Signed-off-by: Casey Gowrie <[email protected]>
Move the parent World's run store from <appRoot>/.workflow-data to <appRoot>/.eve/workflow-data so eve-owned development state lives in one directory. The top-level path remains gitignored for apps that configure the stock local World explicitly, which still uses its own default. Co-Authored-By: Claude Fable 5 <[email protected]> Signed-off-by: Casey Gowrie <[email protected]>
- Requests forwarded to the worker carry the accepted socket's peer address as parent-signed metadata; forged public copies are stripped, and channel context.requestIp resolves the verified value instead of the proxy's loopback hop. - A delivery whose recorded generation no longer exists is acknowledged and dropped with an explicit error instead of redelivering for the full retry budget, and boot quarantines such runs instead of refusing to start over one poisoned record. Recently enqueued generations are protected from pruning for a horizon so a delivery that has not yet persisted its run record cannot lose its snapshot. - Transport comparisons are timing-safe, an unusably short secret is rejected at construction, generation ids reject dot segments, and the direct-handler gate shares the same world predicate as the parent and the generated plugin. - Paused pruning (protect-all) is reported once per cause instead of silently retaining every generation, boot failures reading run records carry the workflow-data hint, and stream-route errors serialize like every other World operation. Co-Authored-By: Claude Fable 5 <[email protected]> Signed-off-by: Casey Gowrie <[email protected]>
Co-Authored-By: Claude Fable 5 <[email protected]> Signed-off-by: Casey Gowrie <[email protected]>
Replace the client's hand-written method forwards and the server's enumerated dispatch switch with generic forwarding driven by a single DEVELOPMENT_WORLD_OPERATIONS table in the protocol module. Adapting to a vendored-world interface change becomes one table entry, the two sides cannot drift, and the server validates calls against the same allowlist. The deliberate exceptions stay explicit: deployment identity and queue enqueueing carry eve semantics, streams.get rides its own route, and createQueueHandler runs entirely in the worker. Co-Authored-By: Claude Fable 5 <[email protected]> Signed-off-by: Casey Gowrie <[email protected]>
Durable Workflow payloads serialized every dev disk source as a logical generation selector keyed off EVE_DEV alone, but only parent-owned World deliveries install the context that resolves the selector — a custom World's first execution threw resolving its own payload. The durable strategy is now an explicit property of the artifact source, derived from the same predicate that decides World placement: parent-owned Worlds store logical selectors, custom Worlds store the exact snapshot path and replay without any eve-specific delivery context, as before the parent World existed. Pruning already protects every generation when the World is opaque, so pinned paths cannot dangle within a session. Co-Authored-By: Claude Fable 5 <[email protected]> Signed-off-by: Casey Gowrie <[email protected]>
Signed-off-by: Casey Gowrie <[email protected]>
77777e1 to
3f332ff
Compare
8986b8c to
af73197
Compare
AndrewBarba
approved these changes
Jul 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of the stock-Nitro dev server route (stacked on #787, which is stacked on #782, based off #759).
What
Moves the default local Workflow World out of the dev worker and into the CLI parent process, so child Workflow runs survive worker replacement without any bespoke transport:
@workflow/world-localonce and serves it to workers over an RPC codec on the public listener, guarded by a per-process secret (EVE_DEV_WORKFLOW_TRANSPORT_SECRET). Explicitly configured Worlds stay inside the worker, untouched.runs.get→deploymentId), then loads that generation's modules from itsgeneration.json.Tests
development-world-server.integration.test.tsrewritten as two-sided in-memory tests: a real client queue handler wired to the real parent World via a patched fetch, covering pin-until-terminal, driver-to-active routing, untrusted-delivery rejection (401), and missing-generation startup failure.start-development-server.tssplit (dev-workflow-world-setup.ts,dev-server-url.ts) to stay under the file-length cap.🤖 Generated with Claude Code