Pattern library
A recipe for every kind of wait.
103 patterns built on one primitive. Each page states the situation, shows the code, and names the guarantee you can lean on.
103 patterns
The escalation boundary
Confidence-gated escalation
The workflow finishes on its own when the model is confident and parks a review row when it is not, so people see only the uncertain cases.
conditionalproxyActivitiesDashboardHTTPSDKThe escalation boundary
Answer, timeout or cancel
Every wait ends in one of three typed values: the answer, false on timeout, or null on cancel. Each branch is explicit in code.
conditionalDashboardHTTPSDKThe escalation boundary
A checklist computed at runtime
The workflow decides which steps a person must confirm. The form renders them from the row, so one schema serves every variation.
conditionalx-lt-widgetDashboardSDKThe escalation boundary
Errors become escalations
When retries run out, the failure becomes a row an operator can act on. The run waits for retry or skip instead of disappearing.
conditionaldidInterruptDashboardHTTPSDKThe escalation boundary
Ask for what is missing
When a run lacks a fact it needs, it asks the one person who has it with a form for just that field, then continues.
conditionalassigneeDashboardHTTPMCPThe escalation boundary
One crash-safe write
The row, its facets and the resume timer commit with the workflow's checkpoint in one write. A crash leaves all of it or none of it.
conditionalsignal_keySDKThe escalation boundary
Early signals are buffered
A payload sent before the workflow starts waiting is held and delivered when the wait registers. Order of arrival stops mattering.
signalconditionalSDKThe escalation boundary
Pin the form edition per row
Each row renders and validates against the form version its code was written for, while the role's form keeps evolving.
conditionalschemaVersionDashboardHTTPSDKThe escalation boundary
Know who resolved it
The resolver's identity rides the wake as $resolution and lands on the row as resolved_by, so follow-on work can go to the same person.
conditional$resolutionDashboardHTTPSDKThe escalation boundary
Born-assigned hand-off
The next row is created already assigned to a named person, in the same write that creates it. It lands in their list with no claim step.
conditionalassigneeDashboardSDKThe escalation boundary
Batch: N contributions, one wake
One row collects a named set of submissions and wakes the workflow once, when the last one lands, with the whole collection.
conditionalbatchDashboardHTTPSDKThe escalation boundary
Start a batch partly filled
Items already satisfied before the wait begins go in filled, so the row opens with real progress and delivers them with the rest.
conditionalbatchSDKThe escalation boundary
Deliver what arrived on timeout
With partialOnTimeout, a batch that misses its deadline wakes with the items filled so far instead of false, so the workflow can act on them.
conditionalbatchSDKThe escalation boundary
Wake on flag
A contributor flags one pending item and the workflow wakes at once with what has arrived and the flag, so it can reroute the order.
conditionalbatchDashboardHTTPSDKThe escalation boundary
Open container
One row is a container that fills over time. Items join one at a time and the workflow wakes once with the ordered collection.
conditionalAccumulatoraccumulateDashboardHTTPSDKThe escalation boundary
A timeout is a delivery window
On a container, the timer closes the window and delivers what it holds. The type has no false branch to handle.
conditionalAccumulatorAccumulatorResultSDKThe escalation boundary
Count trigger versus cap
max either ends the wait when the container fills or only limits how much it can hold. One flag, resolveAtMax, picks which.
conditionalAccumulatoraccumulate.maxSDKHTTPThe escalation boundary
Reciprocal add
A bag joins a bin and the bin records the bag in one statement. Both rows change or neither.
accumulatereciprocalScanDashboardHTTPThe escalation boundary
Find a container by held key
Which bin holds order ORD-9 is one GIN-indexed containment query on the bin rows. No side table tracks membership.
accumulate_keyssearchByFacetsHTTPSDKCLIThe escalation boundary
Human flags, AI remediates
A reviewer who cannot fix the input marks it for triage, and a tool-calling workflow repairs it and runs the original step again.
_lt.needsTriage_lt.hintDashboardHTTPMCPThe escalation boundary
Pluggable resolution strategy
One registered class decides what a resolution does: re-run the step or hand it to triage. Routing rules live in code you own.
LTEscalationStrategyescalationStrategyRegistrySDKResolving from anywhere
One row, many resolvers
A person, a service, an operator, an agent or a machine can resolve the same row. The workflow receives the same typed answer either way.
conditionalresolveDashboardHTTPSDKResolving from anywhere
Resolve by domain key
A caller that knows only orderId resolves the right row in one atomic statement, with no lookup of the escalation id first.
resolveByMetadataresolve_by_metadataHTTPSDKCLIResolving from anywhere
Resolve by signal key
A webhook that knows the deterministic signal id resumes the exact waiting workflow, with no id lookup and no facet to duplicate.
resolveBySignalKeysignal_keyHTTPSDKMCPResolving from anywhere
System ingress ignores claims
A person's claim blocks other people resolving by id, while webhooks resolving by signal key or domain key act for the process regardless.
resolveBySignalKeyresolveByMetadataHTTPSDKDashboardResolving from anywhere
Resolve a set, all or none
Each row in a set resolves with its own payload in one statement, waking each workflow with its own value, or nothing resolves.
resolveAllOrNonerequireClaimedHTTPSDKResolving from anywhere
Intent on create, outcome on resolve
The row is created with the facets that route it and resolved with the facets that describe what happened. One row answers both questions.
conditionalresolveDashboardHTTPSDKResolving from anywhere
The row is the production log
A station resolves its in-flight row with the run's result, so the work queue is also the record of what was produced and how long it took.
resolvesearchByFacetsHTTPSDKCLIResolving from anywhere
Cancel is home
Cancelling a wait sends the item back to a known home queue. An operator's cancel is a safe reset, never a lost item.
conditionalcancelDashboardHTTPMCPResolving from anywhere
A claim is a work lock
A claim names a holder and a window. While the window is live nobody else can resolve the row, and when it lapses the row is back in the pool.
claimassigned_toDashboardHTTPSDKResolving from anywhere
An expired claim is recovery
When a holder walks away, the window lapses and the row is claimable again with no job, no status change and no lost input.
assigned_untilavailableDashboardHTTPSDKResolving from anywhere
One contract, one 422
Every resolve surface rejects a bad payload with the same 422 body naming each field, so every client handles validation one way.
enforce_schemaschema_validationDashboardHTTPSDKResolving from anywhere
Validate before claiming
An agent's claim-and-resolve validates the payload first, so a rejected answer never leaves a row locked to the agent.
claim_and_resolvecheck_resolutionMCPHTTPResolving from anywhere
Parse the resolution at the boundary
One zod schema gives the workflow its type, its runtime check and its version pin, so resolver payloads enter code already parsed.
parseResolverPayloadResolverPayloadTypeErrorSDKResolving from anywhere
Roll out enforcement by watching 422s
Turn on schema enforcement for one role and let each 422 name the submitter and the exact fields it is missing.
enforce_schemacheck_resolutionHTTPMCPDashboardThe queue as a market
Role is the wall, facets are capability
The role decides who can ever see a row. Metadata facets decide which consumer inside that role can take it.
rolemetadataHTTPSDKCLIThe queue as a market
A query that fits in a URL
Facets, ranges, exclusions and ordering ride as JSON query params, so any filtered queue is a link you can paste, pin or curl.
GET /api/escalationsfacetsHTTPDashboardCLIThe queue as a market
Availability is a query
A row is held only while its claim window is live. Availability is computed at read time, so no job has to flip a flag back.
availableassigned_untilHTTPSDKCLIThe queue as a market
Claim complete groups
A consumer claims whole orders, every unit at once, and only orders whose units have all arrived. No order is ever split across consumers.
claimGroupsoriginIdHTTPSDKCLIThe queue as a market
All-or-none claim
Claim exactly N rows or none. A dispatcher that needs four free stations either locks four or locks nothing and tries again.
claimByFacetsallOrNoneHTTPSDKCLIThe queue as a market
Two-sided dispatcher
Demand and supply are both rows. A dispatcher counts free supply, claims that much demand, locks the supply all-or-none, and pairs them.
searchByFacetsclaimGroupsSDKHTTPThe queue as a market
Carry a claim across continueAsNew
A looping dispatcher keeps the orders it claimed but could not place yet, and carries them into its next run instead of releasing them.
continueAsNewclaimGroupsSDKThe queue as a market
The list and the badge agree
The at-risk count on the Pace Board and the list it links to run the same SQL predicate, so the list always holds exactly that many rows.
jeopardypriority_threshold_minutesDashboardHTTPSDKThe queue as a market
Scope is enforced in SQL
A member's read and write scope are ANDed into the query itself, so totals, pages and claims all respect it and nothing is filtered after the fact.
read_scopewrite_scopeHTTPSDKCLIThe queue as a market
Pace by queue depth
An upstream step releases new work only while the downstream queue is below a set depth, reading the depth with one counted query.
searchByFacetstotalSDKHTTPThe queue as a market
Lot traceability by containment
Stamp the lots each unit consumed onto its row as an array facet. Every row that used a lot is then one containment query.
metadata patchfacetsHTTPSDKCLIThe physical world
A scan is a rule
A code runs an ordered list of queue queries and the first match acts, so one scan both moves the item and reports where it is.
scanSchemesPOST /api/scan-codes/executeScanHTTPMCPThe physical world
The label and the row share a facet
A scheme names the metadata facet a label's target matches, so a printed code finds its row by the same value the workflow stamped.
target_facetscanSchemesScanSDKThe physical world
Facts above, choices below
One lifelong code serves many intents: the station states what is true about the row and offers the actions that fit.
presentfactsScanDashboardHTTPThe physical world
One scan, one action
When a step offers exactly one choice, the scan runs it directly: the item that just arrived is claimed and its form is on screen.
autoSelectSingleclaim-show-detailScanDashboardThe physical world
Item, badge, container
Three scans place an item in a container: the item says which, the badge says who, and the container scan writes both rows at once.
holdaccumulateScanSDKThe physical world
Hold a subject
The item scan writes nothing: it holds the item on the station so the next scan knows what it is acting on.
holdsubjectScanHTTPThe physical world
Match and refuse before any write
A wrong pairing is refused with copy that names the right container, and nothing is written.
matchrefuseScanThe physical world
Fill a checklist by scan
A batch row lists the codes an order expects; each scan checks one off, and the last fill completes the row and wakes the workflow.
batchfillScanSDKDashboardThe physical world
A badge attributes, never grants
A badge scan mints a short-lived acting grant; every act then runs as the badged person under their own live RBAC.
identity schemeactingTokenScanDashboardHTTPThe physical world
Station login, badge at submit
A shared device signs in read-only; anyone edits the form, and the badge is asked for once, at the submit that changes the record.
read_scopewrite_scopeDashboardScanThe physical world
Manager override
An exception action shows to everyone and runs only for a badge that holds the manager role; anyone else is refused and keeps their badge.
choices.rolesrefuseScanDashboardThe physical world
Kiosk mode and wall screens
A single-role floor login locks to its queue, and a role's portals lay its pinned views out as live wall screens.
properties.kioskportalsDashboardThe physical world
A machine is a resolver
A workflow parks a row and waits; a machine resolves it over MQTT exactly as a person would from the dashboard.
Machines.loadLinestart({ machines })MQTTSDKDashboardThe physical world
Command a machine with a row
Start, stop, pause or change over a machine by parking a row on its role; the machine's reply resolves the row as data.
Machines.commandRowMachines.commandTargetMQTTSDKHTTPThe physical world
Handoff row
Each hop between stations is one row naming the units that move; it resolves with a receipt or a typed error code.
handoffunitsMQTTSDKDashboardThe physical world
Learned addresses, approved by a person
A station learns its machine from first contact; any later disagreement becomes a registration row a person approves or rejects.
addressingmachine-registrationMQTTDashboardThe physical world
Broken messages become rows
Under a strict codec a message that breaks the contract is confirmed, never acted on, and shown to an operator as a row.
LineCodecstrictMQTTDashboardThe physical world
Offline, quiet and alarm rows
A stopping alarm, a dropped machine and a silent one each become a row for the line operator, resolved when the machine recovers.
line-alarmmachine-offlineMQTTDashboardThe physical world
One leader per line
Every replica runs the same config; one holds a Postgres advisory lock per line and runs its gateway, and the rest take over on loss.
advisory lockMachineGatewayMQTTSDKThe physical world
Idempotent commands
Every command carries an id and an expiry, so a retry is answered rather than run twice, and a late copy is refused.
cmdIdMACHINE_DISPATCH_ATTEMPTSMQTTAgents and MCP
Humans as tools
An agent routes work to a person through the same tool protocol it uses for everything else, and gets the typed answer back.
escalate_and_waitescalate_to_humanMCPDashboardAgents and MCP
Tools as durable activities
Register an MCP server and its tools become checkpointed workflow activities: retried on failure, replayed from cache after a crash.
McpClient.toolActivitiesproxyActivitiesSDKMCPAgents and MCP
A workflow is a tool
A compiled pipeline deploys as an MCP tool, so the next agent that meets the same case calls a deterministic fix instead of reasoning again.
list_workflowsget_workflowMCPHTTPAgents and MCP
Scope times role
A key's scope decides read or write; the account's roles decide which tools and which records. Both must pass on every call.
mcp:readmcp:fullMCPHTTPAgents and MCP
Read-safe workflows
Mark a side-effect-free workflow read-safe and read-scoped keys can run it, while every other workflow stays out of their reach.
readSaferead_safeMCPSDKAgents and MCP
Several environments, one conversation
List local, staging and production as separate MCP servers and name the environment in the prompt; tool names never collide.
.mcp.jsonmcp:readMCPAgents and MCP
Instance federation
One Long Tail calls another's tools over MCP with a service account the remote issues; neither side shares a database or a login.
POST /api/mcp/serversstreamable-httpMCPHTTPAgents and MCP
Connect an agent in one line
Add the /mcp URL to any MCP client, sign in once in the browser, and the agent acts as you with your roles as they are now.
/mcpauth.oauthServerMCPAgents and MCP
Tag-based tool discovery
Tag a server when you register it and every tag-scoped agent run picks up its tools, with no workflow code naming the server.
tagsfindServersByTagsHTTPMCPAgents and MCP
Exactly-once event subscriptions
Every replica sees every event, and a subscription still starts one workflow per event, through a deterministic id and idempotent start.
agentssubscriptionsSDKMCPAgents and MCP
Goals, rules and memory
An agent automation carries goals that drive it, rules that constrain it and a knowledge domain it accumulates into over time.
agentsgoalsSDKMCPDashboardAgents and MCP
Autonomous topic wiring
Topics carry payload schemas in a catalog, so an agent can discover what is published and wire a subscription entirely through tool calls.
list_topicsregister_topicMCPSDKAgents and MCP
Teach agents your vocabulary
A domain dictionary maps the floor's jargon to roles, facets and workflows, so an agent hears a noun and knows the query.
mcp.domainDictionaryget_domain_contextMCPHTTPSDKAgents and MCP
An event is a notification
Escalation events carry routing fields and facets only; a subscriber that needs the payload reads the row by id through the scoped API.
CallbackEventAdaptereventRegistrySDKHTTPIdentity
Initiator and principal
A run records who asked and who executes as separate facts, so a service account can do the work while the audit still names the person.
executeAsexecute_asSDKHTTPIdentity
Credential cascade
An activity asks for a provider credential by name and gets the principal's, then the initiator's, then the system's, with the source recorded.
getCredentialgetActivityIdentitySDKIdentity
Ephemeral credential tokens
A password typed into a form reaches the tool as an opaque token, exchanged for plaintext only at the moment of the call.
format: passwordeph:v1DashboardMCPIdentity
Delegation tokens
A tool call carries a five-minute, scope-limited token for the person behind the run, which an external server trades for that person's access.
_auth.tokenPOST /api/delegation/validateHTTPMCPIdentity
One-time user
Route one item to one named person with a self-scoped membership; they see and answer exactly that form and nothing else in the queue.
assigned_toread_scopeSDKHTTPDashboardIdentity
Member scope profiles
Two scope axes on a membership give five profiles, from full worker to auditor, all enforced inside the query.
read_scopewrite_scopeHTTPSDKCLIIdentity
Personas with provenance
A persona bundles roles at chosen scopes; assigning it writes ordinary memberships that remember which persona sustains them.
lt.personas.seedgranted_by_personaSDKHTTPCLIIdentity
One-method auth adapter
Authentication is one method that turns a request into a user id or null, so any identity provider plugs in without touching a route.
LTAuthAdapterAuthPayloadSDKHTTPAnalytics
Park every state
Each state an item passes through is one escalation row. The queue becomes a complete time series of the process with no extra instrumentation.
conditionalsubtypeSDKHTTPDashboardAnalytics
The entity is a shared facet
Roles that declare the same entity key form that entity's system. One dial per role, and every analytics query can scope to the whole journey.
entity_facetentity_state_sourceHTTPSDKCLIAnalytics
Dwell and membership
One call answers how long entities spent in each state over a window, or how many are in each state right now.
aggregateByFacetsaggregate_by_facetsHTTPSDKCLIAnalytics
Reconstruct any moment
Pass a past instant and membership rebuilds the live set as it stood then, from the same rows, with no snapshot table.
aggregateByFacetsasOfHTTPSDKCLIAnalytics
Gaps are a signal
One entity's timeline lists every interval across every queue and keeps the gaps between them, so hand-off delay is visible, not averaged away.
timelineByFacettimeline_by_facetHTTPSDKCLIForms and configuration
The form is data
A role's form is a versioned JSON Schema; each row pins the edition it renders, so editing the form never breaks work in flight.
form_schemaschemaVersionSDKHTTPCLIForms and configuration
Versioned lookups
Option lists live once in the knowledge store as immutable editions; rows carry a three-field ref and forms read the edition through it.
lookupsx-lt-optionsSDKDashboardCLIForms and configuration
Code-owned configuration
Set configSource to code and every declared role, workflow, topic, agent and scan scheme is diffed and applied on each boot from git.
configSourceresetSDKForms and configuration
Orphans are reported, never deleted
A record in the database with no declaration in code is named in the boot log and left in place; removal stays a deliberate act.
configSourceconfig applySDKDashboardHTTPForms and configuration
Link variables
One pinned link serves every station: a role declares a variable, each device binds its value, and the link resolves at render time.
properties.link_variables{lt:name}DashboardForms and configuration
Pins are the bookmark set
A role ships the exact queries its members need as pinned views with live counts, in their nav from the first login.
default_pinsbadgeDashboardHTTPForms and configuration
Conditional fields
A field appears only when a condition holds, live as the person types, and a hidden required field is skipped by validation on both sides.
x-lt-showIfx-lt-hide-if-emptyDashboardHTTPForms and configuration
Hold submit until embedded work drains
A parent form's submit stays disabled while its child rows are open, and can close itself the moment the last one resolves.
x-lt-submit-guardx-lt-widget: escalation-listDashboardHTTPForms and configuration
Roster: check off who arrived
A roster lists every member a container expects, marks each waiting, in or flagged, and holds the rest of the form until all are accounted for.
x-lt-widget: rosterx-lt-rosterDashboardScanHTTPForms and configuration
Start a workflow from a form
A control on a work form starts another workflow with values mapped from the record, under the same per-caller list and input gate.
x-lt-widget: invokex-lt-invokeDashboardHTTPMCP