chant's Op composite currently requires Temporal for execution — chant run <op> spawns a Temporal worker and submits a workflow. That's the right shape for production deploys, but it's a real barrier in the Quick Start: a new user has to install Temporal (or sign up for Temporal Cloud) before they can run chant run hello.
A small local-only executor closes that gap without competing with Temporal. Single Node process, no durability across restarts, no gates, no schedules — just enough to run *.op.ts files end-to-end so the tutorial works in 30 seconds.
The graduation story: tutorial → local runner; production → Temporal lexicon (or, eventually, Inngest / Restate / etc.). Two clearly-scoped offerings, neither watered down.
Approach
A new mode for chant run that parses the Op directly from *.op.ts (chant already builds an Op IR during chant build) and executes phases sequentially in the current process. No codegen output, no SQLite, no worker, no daemon. Activated by chant run --local <op> and auto-detected when no Temporal lexicon is configured in chant.config.ts.
Lives in packages/core/src/runtime/local/. Reuses pre-built activities from the Temporal lexicon (shell, build, kubectlApply, helmInstall, stateSnapshot, stateDiff, etc. — they're plain Node functions; only the workflow side was Temporal-coupled).
Tasks
Done when
- A user with chant installed but no Temporal can
chant init → write hello.op.ts → chant build → chant run hello and see it work in under a minute
- Existing Temporal-backed Ops continue to work unchanged (no regression)
- Docs make the local-vs-Temporal trade-off explicit
- Test suite covers happy path +
onFailure + retry
Out of scope (intentionally)
- Gates (
gate() step) — require persistence across processes. Local mode errors with "use the Temporal lexicon for gate-based workflows."
- Schedules (
TemporalSchedule) — require an external scheduler. Same error.
- Durable state across process restart — explicitly not supported; if the process dies mid-run, you start over.
- Search attributes /
chant run history — local mode has no persistence layer to query.
- Worker pools / cross-process parallelism.
- Web UI — stdout is the UI.
Why this and not a full internal runtime
A full internal runtime (SQLite-backed, durable, with gates and schedules) would be technically interesting but breaks chant's stated boundary (philosophy.mdx: "chant doesn't deploy"). It also imports permanent maintenance of state-machine edge cases that Temporal has spent years solving. The local executor is deliberately scoped to be a teaching tool, not a production runtime — anyone going to prod uses the Temporal lexicon (or eventually Inngest / Restate / etc. as additional lexicons).
Why now
The audit thread (#21–#67) settled chant's observational-state story. The remaining friction in the Quick Start is the Temporal install. Closing that gap unlocks the tutorial path without committing chant to maintaining a real durable runtime.
chant's
Opcomposite currently requires Temporal for execution —chant run <op>spawns a Temporal worker and submits a workflow. That's the right shape for production deploys, but it's a real barrier in the Quick Start: a new user has to install Temporal (or sign up for Temporal Cloud) before they can runchant run hello.A small local-only executor closes that gap without competing with Temporal. Single Node process, no durability across restarts, no gates, no schedules — just enough to run
*.op.tsfiles end-to-end so the tutorial works in 30 seconds.The graduation story: tutorial → local runner; production → Temporal lexicon (or, eventually, Inngest / Restate / etc.). Two clearly-scoped offerings, neither watered down.
Approach
A new mode for
chant runthat parses the Op directly from*.op.ts(chant already builds an Op IR duringchant build) and executes phases sequentially in the current process. No codegen output, no SQLite, no worker, no daemon. Activated bychant run --local <op>and auto-detected when no Temporal lexicon is configured inchant.config.ts.Lives in
packages/core/src/runtime/local/. Reuses pre-built activities from the Temporal lexicon (shell,build,kubectlApply,helmInstall,stateSnapshot,stateDiff, etc. — they're plain Node functions; only the workflow side was Temporal-coupled).Tasks
packages/core/src/runtime/local/executor.ts— walks the Op IR, runs phases sequentially (or in parallel whenphase.parallel === true)outcomeAttributeby storing the result in an in-memory map keyed by__r0/__r1and surfacing it to stdout (no search-attribute persistence)maximumAttempts/startToCloseTimeoutin-process (setTimeoutfor backoff,Promise.racefor timeout)onFailurehandling — try/catch around main phases, runonFailurephases on rejection, re-throw at the endchant run --local <name>flag wiring inpackages/core/src/cli/handlers/run.tschant.config.tshas no Temporal lexicon configured, default to local mode and print a one-liner explaining the choiceguide/ops.mdx("Try it locally without Temporal") and a callout in Quick Start; explicitly document what's NOT supported (gates, schedules, durable cross-process state)Done when
chant init→ writehello.op.ts→chant build→chant run helloand see it work in under a minuteonFailure+ retryOut of scope (intentionally)
gate()step) — require persistence across processes. Local mode errors with "use the Temporal lexicon for gate-based workflows."TemporalSchedule) — require an external scheduler. Same error.chant run history— local mode has no persistence layer to query.Why this and not a full internal runtime
A full internal runtime (SQLite-backed, durable, with gates and schedules) would be technically interesting but breaks chant's stated boundary (
philosophy.mdx: "chant doesn't deploy"). It also imports permanent maintenance of state-machine edge cases that Temporal has spent years solving. The local executor is deliberately scoped to be a teaching tool, not a production runtime — anyone going to prod uses the Temporal lexicon (or eventually Inngest / Restate / etc. as additional lexicons).Why now
The audit thread (#21–#67) settled chant's observational-state story. The remaining friction in the Quick Start is the Temporal install. Closing that gap unlocks the tutorial path without committing chant to maintaining a real durable runtime.