Design: entity workflows — a run that is the state of a thing
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 9
- Forks
- 0
- Avg merge
- 3h 3m
- Merged PRs (30d)
- 509
Description
Everything shipped so far is a run: it starts, does its steps, and finishes. Temporal's other great pattern is the entity workflow — a long-lived execution that is the current state of one thing (a tenant, a subscription, an incident, a device), mutated by signals and updates, compacted through Continue-As-New, addressed by a stable ID that names the entity. Flowstate should be able to express it, because it is the difference between "orchestrate a task" and "manage a thing over its lifetime" — and the second is where docs/ARCHITECTURE.md's workload list (business processes spanning months, operational runbooks) actually lives.
What the codebase already holds open for this, deliberately:
- docs/DSL.md files
state:and entities in Phase 5, and the byte-bound decision is already made ("state:gets a byte bound now, not an open question") — an entity's state rides inRunState, which already has size enforcement (CheckRunStateSize) and the wire-contract discipline of invariant 10. - Continue-As-New with signal draining already works — the exact machinery an entity needs to live past history limits without dropping a mutation in flight.
- The signal path (
wait_for_signal:, buffered early signals,PendingSignalcarried across CAN) is the mutation-delivery half, already built. - Interpreter versioning (pinned per run, auto-upgrade at CAN) matters more for entities than for runs: an entity lives across many deploys by definition, and the CAN seam is exactly where it picks up new interpreter behavior safely.
What does not exist and the design must answer:
- A DSL shape. A run is
steps:executed once. An entity is state plus handlers — "when signal X arrives, do these steps; when queried, answer this." That is a different top-level document shape, not a step kind. Sketch to argue with:edition: v2026.x entity: subscription state: plan: ${payload.plan} renewals: ${0} on: renew: steps: - id: charge http: ... cancel: steps: [...] - Update, not just Signal. A mutation whose caller needs the answer (approve-and-tell-me) is Temporal's Update primitive, ranked in the earlier capability survey as needing a
RunStatemutation model under invariant 10 plus a local-driver request/response hook. Entities are the feature that finally justifies that cost — signals alone make every mutation fire-and-forget. - Addressing and lifecycle. An entity's workflow ID is the entity key (
subscription/cust-123), which means signal-with-start semantics (mutating a thing that does not exist yet creates it), tenancy on the key (the namespace prefix discipline the fairness key already uses), and aflow entityCLI/RPC surface distinct fromflow run. - The local driver question, faced honestly. A local rehearsal of an entity is a process that must accept mutations over time — closer to
flow run local --signalthan it looks, but the loop never ends. Probably: local entities rehearse one mutation at a time (flow entity local --state state.json --signal renew=...answering with the next state), which keeps invariant 3 meaningful without pretending a laptop process is durable.
Sequencing: behind Phase 2's typed contract (state and handler payloads want types) and alongside Update. Not Phase 5-distant, though — the schema groundwork (RunState fields, reserved document keys) is cheap to hold open now and expensive to retrofit. Related: #106 (modules — an entity definition is a natural thing for a module to export), #96 (webhooks — an inbound webhook mutating an entity is the composition that makes both features sing).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read docs/DSL.md and docs/ARCHITECTURE.md first, then review the existing RunState, CheckRunStateSize, signal buffering, Continue-As-New, and interpreter-versioning behavior described in the issue. The design is complete when it resolves the entity DSL, Update semantics, addressing and lifecycle, and local-driver behavior, with sequencing against #106 and #96 documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- backend-api-design, distributed-systems
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 28/100