█████ █████ █ █ ████ █████ █████ █ █ ██ █ █ █ █ █ █ █ ███ ████ █ █ █ ████ █ █ █ █ █ █ █ ██ █ █ █ █ █ █████ █████ █ █ █ █ █████ █████
Describe a process as tasks in YAML — HTTP calls, child processes, or TypeScript you write — and genroc runs each instance to completion, surviving worker crashes, restarts and long waits without holding a thread or losing state.
Get startedwrite it — every expression is checked against the schemas, as you type
run it — for months, through failures, deploys and new versions
A step can be TypeScript. It is bundled and typechecked on apply, against types generated from the task’s own schemas.
- id: greet
action:
type: child
<<: "$process: ./script-node.genroc.yaml"
input:
code: "$import: ./greet.ts"
input: { who: "$: input.who" }
result_schema:
type: object
properties:
greeting:
type: string
// greet.ts
import type { Input, Output } from "./greet.genroc";
export default (input: Input): Output => {
return {
greeting: `hello, ${input.who}`
}
}; Running instances can move to a new version. Each one’s state is checked against the new definition, and the ones that would not fit are refused.
> genctl upgrade onboard --from 1 --to 2
3kjfx4vm onboard REFUSED at "wait": outputs: required property "email" is missing
02pcayvt onboard -> 2 (1 in tree)
moved 1 tree(s) from 1 to 2, 1 refused Waits last minutes or months — this one loops weekly, forever. The instance sits in the database, not in a thread, so restarts and deploys do not touch it.
nameUnique process identifier.: weekly-digestUnique process identifier.
tasksOrdered list of execution tasks. Control advances linearly unless a switch case redirects.:
- idTask identifier, unique within the definition.: wait_for_mondayTask identifier, unique within the definition.
actionDescribes the action to perform. Omit for switch-only (routing) tasks.:
typeDelay action: parks the instance until a duration elapses (for) or an instant arrives (until).: delayDelay action: parks the instance until a duration elapses (for) or an instant arrives (until).
untilAn instant: RFC 3339, "+2d 08:00", a calendar pattern, unix milliseconds, or a $: expression.: "mon 09:00"
tzIANA name ("Europe/Prague") or fixed offset ("+02:00"); defaults to UTC. Abbreviations are rejected.: Europe/PragueIANA name ("Europe/Prague") or fixed offset ("+02:00"); defaults to UTC. Abbreviations are rejected.
switchRequired. Routing: a shorthand ("next", "end", "$task-id") or an ordered list of cases.: nextRequired. Routing: a shorthand ("next", "end", "$task-id") or an ordered list of cases.
- idTask identifier, unique within the definition.: sendTask identifier, unique within the definition.
actionDescribes the action to perform. Omit for switch-only (routing) tasks.:
typeHTTP call. URL, method, headers and body are all expressions.: fetchHTTP call. URL, method, headers and body are all expressions.
methodHTTP method, lowercase (e.g. get, post) or a template such as ${ input.method }. Required — the verb is never guessed.: postHTTP method, lowercase (e.g. get, post) or a template such as ${ input.method }. Required — the verb is never guessed.
urlRequest URL. May contain ${ } interpolations, e.g. ${ config.server_url }/path.: "https://api.example/digest"
switchRequired. Routing: a shorthand ("next", "end", "$task-id") or an ordered list of cases.: $wait_for_mondayRequired. Routing: a shorthand ("next", "end", "$task-id") or an ordered list of cases. Retries back off with jitter. Anything else becomes a named error the caller can match on.
nameUnique process identifier.: chargeUnique process identifier.
tasksOrdered list of execution tasks. Control advances linearly unless a switch case redirects.:
- idTask identifier, unique within the definition.: chargeTask identifier, unique within the definition.
actionDescribes the action to perform. Omit for switch-only (routing) tasks.:
typeHTTP call. URL, method, headers and body are all expressions.: fetchHTTP call. URL, method, headers and body are all expressions.
methodHTTP method, lowercase (e.g. get, post) or a template such as ${ input.method }. Required — the verb is never guessed.: postHTTP method, lowercase (e.g. get, post) or a template such as ${ input.method }. Required — the verb is never guessed.
urlRequest URL. May contain ${ } interpolations, e.g. ${ config.server_url }/path.: "https://pay.example/charges"
on_errorOrdered error-routing rules evaluated when the call fails. First match wins.:
- codeError code patterns. '%' is the only wildcard; every other character is literal. Empty = catch-all.: [http.503]
retryRetry policy applied before the rule routes. Omit for no retries.:
retriesNumber of retries before following goto or failing. 0 = no retries.: 5Number of retries before following goto or failing. 0 = no retries.
delayWait before the first retry: "30s", a number of milliseconds, or a $: expression. Defaults to 1s.: 1sWait before the first retry: "30s", a number of milliseconds, or a $: expression. Defaults to 1s.
max_delayCeiling the growing wait is clamped to. Defaults to 5m, or to 'delay' when that is longer.: 5mCeiling the growing wait is clamped to. Defaults to 5m, or to 'delay' when that is longer.
- codeError code patterns. '%' is the only wildcard; every other character is literal. Empty = catch-all.: [http.402]
raiseTerminate as 'raised' with this code and message — a condition a parent can catch.:
codeError code, lower_snake_case with no dots. A literal — never an expression.: card_declinedError code, lower_snake_case with no dots. A literal — never an expression.
messageHuman-readable message. A template: ${ } renders when the clause fires.: "the card was declined"
switchRequired. Routing: a shorthand ("next", "end", "$task-id") or an ordered list of cases.: endRequired. Routing: a shorthand ("next", "end", "$task-id") or an ordered list of cases. Fan out over an array. Each child is its own durable instance, and the results come back typed, in input order.
nameUnique process identifier.: greet-allUnique process identifier.
input_schemaJSON Schema used to validate the input payload when starting a new instance.:
typeThe value's JSON type, or a list of types it may take.: arrayThe value's JSON type, or a list of types it may take.
itemsThe schema every element of an array conforms to.: { typeThe value's JSON type, or a list of types it may take.: stringThe value's JSON type, or a list of types it may take. }
tasksOrdered list of execution tasks. Control advances linearly unless a switch case redirects.:
- idTask identifier, unique within the definition.: greetTask identifier, unique within the definition.
actionDescribes the action to perform. Omit for switch-only (routing) tasks.:
typeList fan-out: one child per element of 'over'. The result is an array in 'over' order.: child_listList fan-out: one child per element of 'over'. The result is an array in 'over' order.
nameName of the child process to invoke for every element.: greetName of the child process to invoke for every element.
overmap(input, (name) => { who: name }) → array<object{who}>: "$: mapmap(input, (name) => { who: name }) → array<object{who}>(inputinput → array<string>, (namename → string) => { whomap(input, (name) => { who: name }) → array<object{who}>: namename → string })"
result_schemaJSON Schema validating and exposing EACH child's output; the result is an array.:
typeThe value's JSON type, or a list of types it may take.: objectThe value's JSON type, or a list of types it may take.
propertiesThe named members of an object, each a schema.: { message: { typeThe value's JSON type, or a list of types it may take.: stringThe value's JSON type, or a list of types it may take. } }
requiredWhich properties must be present. A property not listed here may be absent, and reading it yields null.: [message]
outputself.result → array<object{message}>: "$: selfself → object{result}.resultself.result → array<object{message}>"
switchRequired. Routing: a shorthand ("next", "end", "$task-id") or an ordered list of cases.: endRequired. Routing: a shorthand ("next", "end", "$task-id") or an ordered list of cases.
outputoutputs.greet → array<object{message}>: "$: outputsoutputs → object{greet}.greetoutputs.greet → array<object{message}>"