Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / Workflow

subscribe

subscribe Event(typed params) [as Alias] { Candidates = …; Reassign = …; Assignee = …; When = …; After = […]; }

Declares that a workflow state waits on an event, and configures the wait — who may hold it, who may hand it on, whether it is armed at all, and what must be satisfied first. A subscribe holds CONFIG only: the routes that fire when the event arrives live at the state level, and the SLA promises live in its own Assigned/Finished blocks.

stableworkflowauthoring

Summary#

subscribe declares that a workflow state is listening for an event, and configures that wait — who may fill it, when it is armed, what must hold first, and what it promises. It is config only: the guarded routes that fire when the event arrives (on Event when (…) { … goto … }) live at the state level alongside the wait, not inside the subscribe block.

Signature#

subscribe <Event>(<typed params>) [as <Alias>] [foreach (<T> <x> in <collection>)] {
  Candidates = <principal => bool> | <() => List<Principal>>;   // who may HOLD or satisfy it
  Reassign   = <actor => bool>;                                 // who may hand it ON
  Assignee   = <expr>;                                          // who it is handed to at arm time
  When       = <predicate>;                                     // whether it is armed on this run at all
  After      = [<Slot>, …];                                     // slots that must be satisfied first

  Assigned { … }   // the pickup promise — Within, Remind, a breach arm
  Finished { … }   // the completion promise
  Requires { … }   // named preconditions on filling it
}

subscribe <Event>();   // bodyless — a wait with no configuration

Description#

A workflow state advances when an event it subscribes to arrives and a matching route transitions it. subscribe names that event and restates its typed parameters (so the payload is visible at the handler), then configures the wait itself. Each setting has its own page — see See also — and the shape to hold is that they answer different questions:

settingquestion
Candidateswho may hold or satisfy this slot
Reassignwho besides the holder may move it
Assigneewho it belongs to from the moment it is armed (a slot with one is not a pool slot)
Whenwhether this run gets the slot at all
Afterwhich sibling slots must be satisfied before it opens

The promises — how long a slot may sit unclaimed, how long its holder has, the nudges along the way, the retries, and where a missed one routes — are declared in the Assigned/Finished blocks inside the slot, not as flat settings on it. That is where Within, Remind, Retries, Backoff and the Unassigned / Unfinished / Exhausted arms live.

A slot's success routes (on <Event> when (…), on <Alias>(…)) and the state's own timers (on Expire, on Deadline) live at the state level, not inside the subscribe — every on … in one place.

An entity-typed parameter is a live row, not a copy. A route may read it and write through it, exactly as it can through the workflow's own tracked item, and those writes are saved with the rest of the transition:

event CustomerWithdrawsItem(OrderItem item);

on CustomerWithdrawsItem(OrderItem item) {
  item.Status = ItemStatus.Withdrawn;    // persisted with the transition
  RefundItem(item);
}

The event's delivery context (who deposited, the claim) is available to a route that opts into a Deposit parameter — see <span class="planned" title="this page is planned and not written yet">workflow-route</span>; it is never ambient.

A state may hold more than one subscribe (multi-wait / N-of-M); that is its own surface — see <span class="planned" title="this page is planned and not written yet">workflow-multiwait</span>.

Examples#

A pool slot the support team may take, a supervisor may move, and which promises to be picked up within an hour:

subscribe Respond() as Reply {
  Candidates = u => u.Team == Team.Support && u.OnDuty;
  Reassign   = a => a.IsSupervisor;

  Assigned { Within = TimeSpan.FromHours(1); Unassigned { goto Escalated; } }
}

The same wait as an app writes it, in context:

Minimal — a wait with no config, just the event:

subscribe Submit();

See also#

  • Candidates (slot) — the slot's Candidates gate: who may HOLD/satisfy this slot (predicate or computed set), and how a screen ASKS it before offering a button: <Wf>.For(item).<Slot>.Candidates(u)
  • Assign — handing a slot to a named colleagueReassign, and the verbs that hand a slot to a named colleague
  • Assigned / Finished (milestones) — the Assigned/Finished promises declared inside the slot: Within, Remind, Retries, Backoff, and the breach arms
  • slot dependencies (After / When / Pending)After: the sibling slots that must be satisfied before this one opens
  • Requires — named preconditions, and the live checklistRequires: named preconditions on filling the slot, and the live checklist that reports them
  • <span class="planned" title="this page is planned and not written yet">workflow-event</span> — the event this subscribes to (a method signature)
  • <span class="planned" title="this page is planned and not written yet">workflow-route</span> — the state-level on <Event> … goto … routes that consume the deposit
  • <span class="planned" title="this page is planned and not written yet">workflow-state</span> — the enclosing state and its Expire deadline
  • Tracks and Initial (the field a workflow drives) — how the workflow binds to an entity's enum property

Related

Candidates (slot)

Declares WHO may hold or satisfy a `subscribe` slot. `Candidates` is one expression surface that dispatches on its…

Assign — handing a slot to a named colleague

Give a slot to somebody else. Claiming takes work for yourself and releasing puts it back in the pool; assigning is the…

Assigned / Finished (milestones)

A milestone puts an SLA on a slot's progress — Assigned (someone must PICK IT UP within Within) and Finished (it must…

Tracks and Initial (the field a workflow drives)

Names the enum field a workflow owns and the state a run starts in. No application code may write that field, and when…