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": ... }. Retries back off exponentially, starting at 2 seconds and capped at 30 seconds between attempts. A call where the app never answers isn’t retried. In the editor, set Max retries and Retry on in the node inspector. In the workflow editor, pick the Endpoint from the endpoints Major extracted from the app’s deployed API, or click Enter manually to type the method and path. If the endpoint’s path has a parameter such as {id}, fill it in under Path. Edit input in the node’s Request body field, or its Query params field for GET and DELETE.

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.

jev_noul, jev_choice, and jev_score

Ask Jev (TypeSafe’s judgment model) a question about some text, then branch on the answer with a router. Use them to filter, classify, or rate content. In the editor they’re called Jev yes/no, Jev choice, and Jev score. All three take a text field: the text to judge. It supports {{ }} interpolation, so it’s usually built from run state, for example "{{trigger.input.email_body}}".

jev_noul

Asks one or more yes/no questions. The output is each question’s yes-probability, from 0 to 1, under its id. For a node judge with a question is_urgent, branch with judge.is_urgent > 0.5.

jev_choice

Picks one label from a list of options. The output is { "choice": "<label>", "confidence": ..., "probabilities": { "<label>": ... } }. Branch with, for example, classify.choice == "billing".

jev_score

Rates the text on an ordered scale. The output is { "score": ..., "confidence": ..., "probabilities": ... }. score is the expected score from 0 to the last level’s position, so it can fall between levels. Branch with, for example, rate.score >= 1.5.

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.