Skip to main content
A workflow’s nodes are its steps and its edges connect them. Every node has an id, a type, a config, and an optional label that’s shown in the graph. This page lists each node type’s config fields. The authoritative definition is the JSON Schema at https://api.prod.major.build/public/workflow.schema.json.
Use underscores, not hyphens, in node ids. A hyphenated id can’t be referenced from a $expr expression.

agent_call

Runs an agent with a prompt.

app_call

Calls an endpoint on one of your deployed apps. The node’s output is the response body. A body that isn’t a JSON object is wrapped as { "body": ... }.

router

Branches the run on state. Branches are checked top to bottom and the first one whose when is true wins. A condition that evaluates to null doesn’t match. Every target in the winning to list runs in parallel. The router must have exactly one outgoing edge per target named in its branches and default.

for_each

Runs a loop body once per item in a list. A for_each has two outgoing edges: one with "loop": "body" into the loop body, and one with "loop": "exit" that runs after the last iteration. Every path from the body must lead back to the for_each. Loop bodies are the only cycles a workflow may have. Inside the body, <for_each_id>.item and <for_each_id>.index are the current item and its position. After the exit edge, <for_each_id>.results holds each iteration’s final output, in item order.

join

Waits for parallel branches to meet. Every edge into a join must come from the same fan-out (a router branch with several targets, for example), with no other join in between. Keep each parallel leg a simple line into the join.

wait

Pauses the run.

human_approval

Asks a person to choose in Slack. Requires the Major Slack integration. The output is { "choice": "<value>", "responded_by": "<user id>" }, or { "choice": "<on_timeout value>", "timed_out": true } on timeout. A human_approval has one outgoing edge, which should lead to a router that branches on <node_id>.choice. Only Major members with access to the workflow can answer.

end

Finishes the run. An end node has no outgoing edges.

Edges

Each edge is { "id": "...", "from": "node_id", "to": "node_id" }, with an optional label shown in the graph. Only for_each out-edges carry "loop": "body" or "loop": "exit".

Graph rules

Saving checks the definition against these rules, and errors name the path that failed:
  • At most 50 nodes, and the file is at most 256 KB.
  • Node ids and edge ids are unique. trigger is reserved and can’t be a node id.
  • entry and every edge’s from and to name an existing node.
  • Only router and for_each fan out. Every other node has exactly one outgoing edge, and end nodes have none.
  • A node can have several inbound edges only if at most one of them can be active at a time. Parallel paths must meet at a join first.
  • Every node is reachable from entry, and every path reaches an end node or loops back to a for_each.

Next steps

State and input

Reference node outputs and workflow input.

Triggers

Start the workflow automatically.