Skip to content

Catalog workspaces: an isolated Worker for each demo - #4122

Draft
rossnelson wants to merge 1 commit into
mainfrom
catalog-per-example-targets
Draft

rossnelson wants to merge 1 commit into
mainfrom
catalog-per-example-targets

Conversation

@rossnelson

@rossnelson rossnelson commented Nov 5, 2026 •

Copy link
Copy Markdown
Collaborator

Draft. This description is the design note. The code in this PR implements step 1 below in its first form (a per-example grouping on targets). It will be reworked to match this design before review.

Summary

The catalog gets one new concept: the workspace. A workspace is an isolated environment with its own Worker. Examples are entry points into a workspace.

  • Today's catalog corpus becomes one workspace with many examples. Its behavior does not change.
  • A source can also put each folder in its own workspace, so a set of demos run side by side with clear boundaries.
  • Properties that describe a Worker live on the workspace: its controls (crash, stop, start), its eject package, its title and docs. Properties that describe starting a workflow live on the example: its input schema and its scenarios.

Why

The catalog runs one Worker for each target, and today every source registers a single target. That works for many small examples that exercise primitives. It does not work for demos that must stand on their own:

  • Two demos cannot define an activity with the same name.
  • Every demo's workflows are bundled together.
  • There is nowhere to describe the Worker itself: whether it can be crashed or stopped for a demonstration, or exported as a standalone project.

Adding demo fields to each example would put Worker properties in the wrong place and grow the example API with optional fields that only some consumers use. A workspace gives those properties a home that is generic to the catalog.

The model

Concept Is Owns
Workspace One isolated Worker Namespace, task queue, workflow bundle, activities, title, description, docs link, controls, eject
Example An entry point into a workspace Workflow or activity to start, input schema, start options, expected evidence, scenarios

A workspace replaces today's target. It keeps everything a target has and adds optional metadata.

Workspace definition

export const catalogWorkspace = {
  id: 'money-transfer',
  title: 'Money transfer',
  description: 'Move money between accounts, and undo the withdrawal if the deposit fails.',
  docsUrl: 'https://docs.temporal.io/...',
  controls: ['crash', 'stop'],
  eject: { sdks: ['typescript'] },
} satisfies CatalogWorkspaceDefinition;

All metadata is optional. One Zod schema validates it and gives the TypeScript type.

Example scenarios

export const catalogExample = {
  id: 'money-transfer',
  // ...existing fields
  scenarios: [
    { id: 'happy-path', title: 'Happy path', input: { amount: 100 } },
    { id: 'deposit-fails', title: 'Deposit fails', input: { amount: 100, to: 'closed-account' } },
  ],
};

Scenarios are named preset inputs. Generation checks each scenario input against the example's input schema. Any catalog example can use them, including the existing corpus.

Grouping

A source declares how its examples map to workspaces:

Grouping Workspaces Task queue Workflow bundle
shared (default) One for the whole source The source's task queue The generated workflows module
per-folder One for each folder <prefix>-<folder> The folder's own workflow module
demos/
  money-transfer/
    workspace.ts   optional workspace metadata
    example.ts     one or more examples
    workflow.ts
    activity.ts

Generation fails when a derived workspace ID or task queue collides with another workspace.

Controls

Controls let a user crash, stop and start a workspace's Worker to watch Temporal recover.

  • The workspace declares which controls make sense (controls).
  • The runtime declares which controls it can provide. A long-lived process can provide them. A serverless Worker, such as the catalog's Lambda deployment, provides none.
  • The browser shows only controls that appear in both lists.

Each workspace with controls gets a control task queue, <taskQueue>-control, served by a small control Worker in the same process. The browser starts a short control workflow on that queue. The command travels through the namespace the Worker already polls, so there is no new network path.

Control Effect
stop Shuts down the workspace's Worker. Tasks wait on the queue.
start Creates the workspace's Worker again. Waiting tasks complete.
crash Abruptly shuts down the workspace's Worker mid-task, then starts it again. Heartbeats time out and the run continues on the new Worker. When the process hosts exactly one workspace, the runtime may exit the process instead, and the host restarts it.

Controls are off unless the runtime turns them on (for example, CATALOG_CONTROL=on).

Eject

eject names the SDKs a workspace can be exported in. Exporting a workspace produces a standalone project: its folder, shared helpers and a generated worker.ts. The export tooling is a follow-up; this design only reserves the field.

Browser artifact

The generated catalog gains a workspaces list next to descriptors. Each descriptor's execution.workspaceId points into it. The browser can list workspaces (one card per demo) or examples (today's view) from the same artifact.

Naming and compatibility

target becomes workspace in the API: registerWorkspace, CatalogWorkspace, execution.workspaceId. The catalog's tooling is consumed through the published package, so the rename ships in one release with the consumer updated in the same version bump. No generated output changes for a shared source other than the renamed field.

Plan

  1. Workspaces and grouping: rename target to workspace, add per-folder grouping, derived IDs and queues, collision checks.
  2. Workspace metadata: the Zod schema, workspace.ts, the workspaces list in the artifact.
  3. Example scenarios, with schema checks during generation.
  4. Control Worker: control workflows and activities, per-workspace control queues, runtime capability gating.
  5. Follow-ups: import-boundary lint for per-folder sources, a source option for scaffold, a source filter for bundle builds, eject export.

Not in scope

  • How a host runs the Worker process. The catalog provides the Worker and the control Worker; the host provides the process and its restart policy.
  • Any product UI built on the catalog.

An authoring target can now declare grouping: 'per-example'. The generated
registration then registers one target for each example, with its own task
queue, workflow bundle, and activities. The default, 'shared', keeps the
current output unchanged.
@vercel

vercel Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
holocene Ready Ready Preview Nov 5, 2026 12:59am UTC

Request Review

@rossnelson rossnelson changed the title Let a catalog target run each example on its own Worker Catalog workspaces: an isolated Worker for each demo Nov 5, 2026

This branch was successfully deployed

1 active deployment
Preview — 137db3b2 Deployed Nov 5, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant