Build

Steps

A step is one meaningful unit of work inside a loop. Steps make a process easier to understand by showing where judgment, action, waiting, and approval happen.

Step boundaries are useful for more than execution. They give operators a clear timeline, preserve useful intermediate results, and let you retry or change one responsibility without rewriting the whole process.

Most loops should begin with one agent step. Split work when a boundary makes responsibility or evidence clearer, not merely because the prompt has several sentences.

Choose a step by responsibility

StepkindRequired configUse it when
AgentagentinstructionsThe work needs judgment, synthesis, or flexible tool use.
Actionactionaction_nameThe work needs one exact operation, such as posting a message or updating a record.
CheckcheckchecksThe loop needs evidence that a condition is true.
Sleepsleepduration or untilTime owns the next move.
Wait for eventwait_for_eventevent_typeAnother system owns the next move.
Interactioninteractionprotocol and targetsA human or agent must answer, review, or approve.
Child looplooploop_idAnother reusable process should begin.

When in doubt, keep judgment in an agent step and side effects in an action step. A review agent can recommend a label; a following action can apply it. The run then shows exactly which decision led to which change.

Author the step object

Every entry in steps has kind and config. It may also have a stable id, a display name, a step-level if, retry, and timeout. For example, this deterministic action runs only for high-severity classifications:

steps:
  - id: apply-label
    name: Apply label
    kind: action
    if: steps.classify.output.severity == "high"
    config:
      action_name: github.issue.add_labels
      execution_location: managed
      parameters:
        repo_full_name: "${{ event.repository.full_name }}"
        issue_number: "${{ event.issue.number }}"
        labels:
          - "${{ steps.classify.output.label }}"
    retry:
      max_attempts: 3
      delay: 2s
    timeout:
      duration: 30s

Action inputs always belong under config.parameters. Use config.execution_location only when routing matters: managed, worker, or environment. Pass the complete loop file to mobius loops create -f or mobius loops update -f; invalid kinds now report the full accepted set, and common action-input aliases such as input and params point to parameters.

Expressions and templates

String leaves in step configuration use ${{ ... }} interpolation. The expression environment has four roots:

RootContents
eventThe triggering event or manually supplied event data.
metaTrigger and routing metadata.
configThe loop's resolved run configuration.
steps.<id>.outputThe output of a prior step. steps[0].output also works.

The step-level if field is a bare expression over the same roots. It must evaluate to true or false; false records the step as skipped. Write if: event.severity == "high", not a quoted template. A surrounding ${{ ... }} is accepted for convenience but is unnecessary. Later-step outputs are unavailable because they do not exist yet, and an unknown path fails instead of rendering an empty value.

Templates support comparisons, boolean and arithmetic operators, indexing, optional access, and value-first pipelines such as ${{ event.labels | map(it.name) | join(", ") }}. Available helpers are:

  • Core: len, string, int, float, bool, contains, has, keys, entries, lower, upper, and sprintf.
  • Strings, collections, and math: trim, split, join, replace, startsWith, endsWith, first, last, sum, slice, sort, reverse, min, max, abs, floor, ceil, and round.
  • Collection forms: map, filter, flatMap, sortBy, any, all, find, count, if, and try.
  • Formatting and structure: coalesce, get, dig, trimPrefix, trimSuffix, title, capitalize, truncate, indent, quote, slug, lines, uniq, bullets, json, prettyJSON, fromJSON, now, and today.

Static objects and arrays in parameters keep their types while Mobius recursively renders their string leaves. An interpolation that returns an object or array becomes compact JSON text; Mobius does not parse rendered JSON text back into a structured parameter. Use a static object with templated leaves when the action expects an object. Use fromJSON(raw).field when a provider value is a JSON string and you need one field from it.

Connect steps through results

Each completed step can save a result for later steps. A step named classify, for example, might return a label, severity, and summary. A later notification step can use those values without receiving the first agent's whole transcript.

Prefer small, structured results between steps. They are easier to inspect, safer to reuse, and more stable than passing long prose or hidden conversation history through the process.

Mobius also gives an agent step the run's inputs, triggering event, metadata, and earlier results as context. Use templates when a value must appear in a specific field or sentence; use context for the broader information the agent needs to understand the task.

Use agent and action steps together

Agent and action steps solve different problems:

  • An agent decides what should happen when the answer depends on context.
  • An action performs a named operation with explicit inputs.

Keeping them separate gives you a clean place to add a check or interaction before an irreversible change. It also makes retries safer because the run can show whether the decision or the side effect failed.

An agent may call actions as tools within its own step when exploration is part of the task. Use a separate action step when the operation is a required part of the process and should be visible on the timeline.

Pause without losing the process

Some work cannot continue immediately. A sleep step waits for time. A wait-for- event step waits for another system. An interaction waits for a person or agent to provide information, approval, or review.

While a step is waiting, the run is suspended, not broken. Its state is saved and it resumes when the expected answer arrives. Use a timeout when no answer should leave the work open forever.

Add checks where evidence matters

A check turns “this looks good” into a visible decision point. Put it after the step that creates the evidence and before the action that depends on it.

Checks can stop the run, let it continue with a recorded failure, or open an approval gate. Prefer evidence from action results, test output, or artifacts over an agent's own claim that its work succeeded.

Conditions keep optional work visible

A condition lets a step run only when it is relevant. For example, a loop can skip escalation for low-severity findings while still showing the skipped step on the timeline.

Use a condition for process logic that operators should be able to see. Keep domain judgment inside an agent step when the choice cannot be expressed as a clear rule.

Retries and timeouts

Retries are for temporary failures. Timeouts keep a step from waiting or running without a useful end. Both are safety controls, not substitutes for a well-defined responsibility.

Be cautious when retrying side effects. Mobius can retry a step, but it cannot undo a message already sent or a record already changed. Make external actions idempotent when the same request might be attempted again.

Build steps in the app

Open Build > Loops, choose a loop, and add steps in the order a person would explain the process. Name each step after its responsibility, such as Classify issue, Request approval, and Apply label.

Run the loop manually and read the timeline. If one step hides several important decisions or side effects, split it. If several steps always change together and add no useful checkpoint, combine them.

The interactive API reference contains exact step fields, expression syntax, retry options, and per-kind configuration.

Next

  • Put steps in a reusable process with loops.
  • Inspect their execution with runs.
  • Pause for a decision with interactions.
  • Design limits and checks with guardrails.