/docs / workflows/activities

Activities

An activity is one step of a workflow. Most activities are carried out by the employee: you state the intent and it does the work with its skills and connections. Six types run without the model, so routing and timing stay exact.

Fields

{
  "id": "draft-reply",
  "label": "Draft the reply",
  "intent": "Draft a reply to the customer message in _watch_payload using the reply-drafting skill.",
  "skills": ["reply-drafting"],
  "requires_tools": ["mail_message_send"],
  "on_error": { "retry": 1, "fallback": "notify_owner" }
}
FieldDefaultMeaning
idrequiredUnique within the workflow. Used in connections and data paths.
typecustomAn employee step, or one of condition, loop, wait, http, command, decide.
intentnoneWhat the employee should accomplish. An employee step needs intent or steps.
steps[]Ordered instructions, when one sentence is not enough.
labelnoneName shown to the owner.
skills[]Skills to use. Marketplace skills listed here are installed with the employee.
tools[]When set, the only tools the step may use.
requires_tools[]Tools that must succeed for the step to count as done.
cmds[]Plugin commands named for the step.
mcps[]MCP servers named for the step.
modelnoneA model id for this step.
paramsnoneParameters for the typed activities, and maxIterations for employee steps.
min_iterationsnoneMinimum model turns before the step may finish.
token_budgetnone{max}. An estimate.
on_error{retry: 1, fallback: notify_owner}Retries, then the fallback. Any failure after retries ends the run.

Employee steps

An employee step runs as a turn of the employee: its persona, memory and connections apply, and it can use up to 50 model turns, or params.maxIterations. The results of earlier steps are passed in as [Activity 'id' result] blocks. The step that ends a workflow with an emit list is told to call emit_event with those events. The exit tool is always available to end the run.

The data context

Typed activities read values by dotted path from one object: inputs holds the run's inputs, nodes.<id> holds each finished activity's output (parsed as JSON when it is JSON), and item holds the current item inside a loop. A bare path looks in inputs, then nodes.

condition

{ "id": "large", "type": "condition", "params": { "expression": "inputs.amount >= 500" } }

params.expression is required. Its outgoing connections are labeled True and False. params.mode chooses how it is read:

ModeExpression
expressionThe default. path op value with ==, !=, >=, <=, > or <, compared as numbers when both sides are numbers; or a bare path, true when its value is truthy.
existsA path; true when it resolves to a truthy value.
containspath contains text, or bare text matched against the previous output.
regexA pattern matched against the previous output.

loop

{ "id": "each-invoice", "type": "loop", "params": { "source": "nodes.fetch.invoices", "concurrency": 4 } }

params.source is the path of a list. The connection labeled Each item leads to the body, which runs once per item with item set; the one labeled Done runs after all items. Iterations start together unless you set concurrency. maxIterations and batchSize are also accepted.

"connections": [
  { "from": "__trigger__", "to": "fetch" },
  { "from": "fetch", "to": "each-invoice" },
  { "from": "each-invoice", "to": "check", "label": "Each item" },
  { "from": "each-invoice", "to": "report", "label": "Done" }
]

wait, http and command

{ "id": "pause", "type": "wait", "params": { "duration": "5m" } }
{ "id": "status", "type": "http", "params": { "url": "https://status.example.com/api", "method": "GET" } }
{ "id": "export", "type": "command", "params": { "command": "date -u" } }
TypeRequiredBehavior
waitparams.durationPauses for a span in s, m or h. There is no wait-until; to resume on an event, trigger a second workflow on it.
httpparams.urlMakes the request. method, headers and body are optional.
commandparams.commandRuns a shell command. Its stdout is the activity’s output.

decide

A decide activity asks typed questions about the work so far and records structured answers that a condition can route on.

{
  "id": "triage",
  "type": "decide",
  "params": {
    "questions": {
      "urgency": { "type": "score", "instructions": "How urgent is this request?", "criteria": ["low", "normal", "high"] },
      "refund": { "type": "noul", "instructions": "The customer is asking for money back." }
    },
    "default": { "urgency": "normal", "refund": false }
  }
}
Question typecriteriaAnswer
choiceObject of option to description, 2 to 255 options.choice, confidence and probabilities.
scoreList of 2 to 10 ordered levels.score from 0 (first level) upward, and confidence.
noulNone.noul, the probability the statement holds.

Route on an answer with a condition, such as nodes.triage.urgency.score >= 1.5. params.default gives the safe answer for each question when no decision can be made; a defaulted answer has confidence 0. A question without a default gets no answer, so conditions on it take their False edge.

Errors

on_error.retry sets how many times a failed activity is retried; the default is 1. After the last retry the run ends, and with the default fallback of notify_owner the owner is told. Nebo checks each typed activity's required parameters when the run starts, and rejects a branch that points to an unknown activity.