Agentic workflows that keep going until the check passes

Write the pipeline once in TOML: agents research in parallel, fix and verify in a loop, then branch on the verdict. One command runs it from your terminal, CI or a script and prints what it cost.

curl -fsSL https://octomind.run/install.sh | bash
octomind workflow research --dry-run
workflow research · from muvon/tap-dev
workflow: research
  description: Investigates a question from background, evidence, and counter-argument angles in parallel, synthesizes a cited report, then loops a groundedness judge until every claim verifies against its sources.

  1. angles  [parallel]
     sub-steps=3  total_runs=3
    1. background  role=assistant:researcher  session=Fresh  timeout=0s  retries=0
       prompt: Research the background and current landscape of this question. Search broad, then narrow. Prefer primary and official …
    2. evidence  role=assistant:researcher  session=Fresh  timeout=0s  retries=0
       prompt: Research the strongest evidence, data, and expert positions that bear on this question. Search broad, then narrow. Pref…
    3. counter  role=assistant:researcher  session=Fresh  timeout=0s  retries=0
       prompt: Research counter-arguments, risks, caveats, and credible dissenting views on this question — actively seek disconfirmin…
  2. report  [loop]  max_iterations=2
     exit_when: output=Some("judge") contains=None matches=Some("(?m)^VERDICT: GROUNDED")
    1. synthesizer  role=assistant:researcher  session=Continue  timeout=0s  retries=0
       prompt: Synthesize the three research passes below into one balanced, well-structured report that answers the question.  Rules:…
    2. judge  role=ai:evals  session=Fresh  timeout=0s  retries=0
       prompt: You are a groundedness judge in a fresh session. You did not write this report. Check it against the gathered evidence …
octomind 0.58.8 · captured

How it works

  1. Write the agentic workflow as one TOML file

    Each step is an agent with its own role, model and tools. This one tests every root-cause hypothesis in parallel, drafts three patches, loops fix and verify, then branches on the verdict.

    fix-bug.toml
    name        = "fix-bug"
    description = "Probe each root-cause hypothesis in parallel, draft three patches, loop fix and verify until tests pass."
    max_cost    = 3.00
    
    [[steps]]
    name   = "hypotheses"
    role   = "developer:general"
    prompt = "List 2-4 root-cause hypotheses for this bug. Wrap each one in <h>...</h>.\n\n{{input}}"
    
    [[steps]]
    name         = "probes"
    parallel     = true
    source       = "hypotheses"
    match        = "(?s)<h>(.*?)</h>"
    max_parallel = 3
    min_success  = 1
    
      [[steps.run]]
      name    = "probe"
      role    = "developer:general"
      timeout = 600
      prompt  = "Check this hypothesis against the code. Answer CONFIRMED or RULED OUT with file:line evidence.\n\n{{probes}}"
    
    [[steps]]
    name        = "drafts"
    parallel    = true
    min_success = 2
    
      [[steps.run]]
      name   = "patch"
      role   = "developer:general"
      count  = 3
      prompt = "Write the smallest patch for the confirmed cause as a unified diff. Do not edit files.\n\n{{probe}}"
    
      [[steps.run]]
      name   = "test"
      role   = "developer:general"
      prompt = "Write one regression test that fails on the current code for the confirmed cause.\n\n{{probe}}"
    
    [[steps]]
    name           = "repair"
    loop           = true
    max_iterations = 3
    exit_when      = { output = "verify", matches = "(?m)^VERIFY: PASS" }
    
      [[steps.run]]
      name    = "fix"
      role    = "developer:general"
      session = "continue"
      prompt  = "Pick the best patch, apply it, and add the test.\n\nPatches:\n{{patch}}\n\nTest:\n{{test}}"
    
      [[steps.run]]
      name   = "verify"
      role   = "developer:general"
      prompt = "Run the new test and the related suite. End with one line: VERIFY: PASS or VERIFY: FAIL.\n\n{{input}}"
    
    [[steps]]
    name        = "outcome"
    conditional = true
    condition   = { output = "verify", matches = "(?m)^VERIFY: PASS" }
    on_match    = ["summary"]
    on_no_match = ["escalate"]
    
      [[steps.run]]
      name   = "summary"
      role   = "developer:brief"
      prompt = "Summarize the fix in the current unstaged changes.\n\n{{input}}"
    
      [[steps.run]]
      name   = "escalate"
      role   = "developer:brief"
      prompt = "The loop did not converge. Report what changed and what still fails.\n\n{{verify}}"
  2. Check it for $0 with --dry-run

    The validator checks step names, every {{variable}}, each regex and every graph route, then prints the plan. No model is called and nothing is spent.

    octomind workflow fix-bug.toml --dry-run   # validate and print the plan
    octomind workflow                          # list the workflows your taps ship
  3. Run the AI agent workflow and keep the result

    Input arrives on stdin and every step reads it as {{input}}. With --format jsonl, stdout gets one JSON event per step and a closing cost event; live progress stays on stderr.

    echo "Login fails when the email contains a plus sign" \
      | octomind workflow fix-bug.toml --format jsonl > result.jsonl

What you get

  • Parallel agents, best-of-N and fan-out from a regex

    parallel = true starts sub-steps together, max_parallel caps how many run at once and min_success lets the block pass with a flaky branch. count = 3 samples one sub-step three times (a static block needs at least two sub-steps). match turns every regex hit in an earlier output into its own branch, so the planner step decides N at run time.

    src/workflow/run.rs:435
  • Loops that stop on a check, branches and bounded graphs

    A loop repeats until exit_when matches a step output, up to max_iterations (default 10). On each later pass a session = "continue" step receives the verifier's last output as its next prompt. conditional picks a branch, and graph mode routes with [[edges]], cycles included, capped by the required max_transitions.

    src/workflow/validate.rs:301
  • A budget and one cost line per run

    max_cost stops the workflow before the next step once summed spend crosses it. --format jsonl closes with one cost event: dollars plus input, output and cache tokens across every step.

    src/workflow/run.rs:167
  • Agentic workflows ship through taps

    Put workflows/<name>.toml in a tap and anyone with that tap runs it by name: octomind workflow research. Tap workflows may only use public tap roles, so they run the same on every machine. A local path runs any file with your own roles.

    src/agent/taps.rs:286
  • Event-driven: start it from a webhook, a timer or a script

    Keep a session alive with octomind run --daemon and feed it with octomind send, a [[hooks]] webhook listener, or the schedule tool (every="1h"). In that session the tap tool's workflow action runs a tap workflow in the background and drops the result into the inbox.

    src/mcp/orchestration/tap.rs:176

A validated plan, then a real run for one cent

First the plan for the fix-bug workflow above, straight from the validator with no model call. Then a three-step workflow run for real on openai:gpt-4.1-nano: one agent proposes three names, match fans them out to three parallel scorers, and a last step picks the winner. The cost event at the end is the whole bill: $0.0106 for five agent runs.

octomind workflow fix-bug.toml --dry-run
workflow: fix-bug
  description: Probe each root-cause hypothesis in parallel, draft three patches, loop fix and verify until tests pass.
  max_cost: $3.0000

  1. hypotheses  [sequential]
     role: developer:general
     session: Fresh  timeout: 0s  retries: 0
     prompt: List 2-4 root-cause hypotheses for this bug. Wrap each one in <h>...</h>.  {{input}}
  2. probes  [parallel · dynamic]
     source="hypotheses"  match="(?s)<h>(.*?)</h>"  runs=per-match  min_success=1  max_parallel=3
    1. probe  role=developer:general  session=Fresh  timeout=600s  retries=0
       prompt: Check this hypothesis against the code. Answer CONFIRMED or RULED OUT with file:line evidence.  {{probes}}
  3. drafts  [parallel]
     sub-steps=2  total_runs=4  min_success=2
    1. patch  role=developer:general  session=Fresh  timeout=0s  retries=0  count=3
       prompt: Write the smallest patch for the confirmed cause as a unified diff. Do not edit files.  {{probe}}
    2. test  role=developer:general  session=Fresh  timeout=0s  retries=0
       prompt: Write one regression test that fails on the current code for the confirmed cause.  {{probe}}
  4. repair  [loop]  max_iterations=3
     exit_when: output=Some("verify") contains=None matches=Some("(?m)^VERIFY: PASS")
    1. fix  role=developer:general  session=Continue  timeout=0s  retries=0
       prompt: Pick the best patch, apply it, and add the test.  Patches: {{patch}}  Test: {{test}}
    2. verify  role=developer:general  session=Fresh  timeout=0s  retries=0
       prompt: Run the new test and the related suite. End with one line: VERIFY: PASS or VERIFY: FAIL.  {{input}}
  5. outcome  [conditional]
     condition: output=Some("verify") contains=None matches=Some("(?m)^VERIFY: PASS")
     on_match:    ["summary"]
     on_no_match: ["escalate"]
    1. summary  role=developer:brief  session=Fresh  timeout=0s  retries=0
       prompt: Summarize the fix in the current unstaged changes.  {{input}}
    2. escalate  role=developer:brief  session=Fresh  timeout=0s  retries=0
       prompt: The loop did not converge. Report what changed and what still fails.  {{verify}}
octomind 0.58.8 · captured
octomind workflow name-it.toml --format jsonl < input.txt > result.jsonl
workflow · name-it

╭ ideas
╰ ✓ ideas  12.0s  · $0.0012  · 5004 tok  · ⚒0


╭ scores  (3 items in parallel)
│ ✓ score #1  12.8s  · $0.0021  · 5000 tok  · ⚒0
│ ✓ score #2  16.2s  · $0.0027  · 10548 tok  · ⚒0
│ ✓ score #3  14.6s  · $0.0023  · 10545 tok  · ⚒0
╰ ✓ scores  3/3 succeeded

── score ──

── score #1 ──
"PipelineX" scores 7 for a terminal tool name. It suggests a pipeline or workflow focus but may lack distinctiveness.

── score #2 ──
8 - "RunFlow" is concise, action-oriented, and suggests a process or sequence, fitting well for a terminal tool focused on executing workflows.
RunFlow - 8 - concise, action-oriented, and suitable for a terminal workflow tool.

── score #3 ──
8 - "AgentPipe" is concise, tech-sounding, and suggests a pipeline or agent functionality suitable for a terminal tool.
AgentPipe - 8 - concise, tech-sounding, suggests pipeline/agent functionality for a terminal tool.


╭ pick
╰ ✓ pick  16.0s  · $0.0024  · 10731 tok  · ⚒0

The highest-scored name is "RunFlow".
RunFlow

total · 1m12s  · $0.0106  · 41828 tok  · ⚒0
octomind 0.58.8 · captured
jq -R -c 'fromjson? | select(.type == "cost") | {type, session_cost, session_tokens, input_tokens, output_tokens, cache_read_tokens}' result.jsonl
{"type":"cost","session_cost":0.010575181999999999,"session_tokens":41828,"input_tokens":15416,"output_tokens":172,"cache_read_tokens":26240}
octomind 0.58.8 · captured

What it doesn't do

  • No shell step type

    Every step is an octomind run <role> agent subprocess. Run scripts through the step agent's own tools or an MCP server, or before and after octomind workflow in your shell. Docs →

  • No nested workflows or nested blocks

    A step cannot call another workflow file, and parallel, loop and conditional blocks hold only plain steps. Compose with graph [[edges]], or chain two workflow runs in a shell pipeline. Docs →

  • Input is stdin only

    There are no --var flags, and a TTY or empty stdin is an error. Put everything the run needs into the piped text; every step reads it as {{input}}.

  • max_cost is a soft budget

    It is checked after each step or parallel block finishes, so a step already running completes and can overshoot. Retries, timeouts and failed parallel replicas can leave spend outside the total. Set a per-step timeout and max_iterations alongside it. Docs →

  • Schedules run only while the process runs

    The schedule tool fires inside a live octomind session; there is no built-in cron. For a nightly run, call octomind workflow from system cron or a systemd timer. Docs →

Questions

What are agentic workflows?

An agentic workflow is a multi-step pipeline where each step is an AI agent with tools, and later steps read the output of earlier ones. The flow can run agents in parallel, repeat a step until a check passes, or branch on what an agent returned. In octomind the whole pipeline is one TOML file.

What are some agentic workflow examples?

The taps ship ready ones: research runs three researchers in parallel and loops a groundedness judge, debug reproduces a bug and loops fix and verify until a test proves it fixed, and deep-review reviews a change from five lenses in parallel. Run octomind workflow to list what your taps include.

How do I stop a workflow from looping forever or overspending?

Loops stop at max_iterations (default 10) and graphs at the required max_transitions. max_cost stops the run before the next step once spend crosses it, but a step already running finishes, so also set a per-step timeout.

Can each step use a different model?

Yes. Set model = "provider:model" on any step and it is passed as --model to that step's agent. Two sub-steps in one parallel block on different models give you a side-by-side comparison.

Can a workflow step run a shell command?

Not as a step type: every step is an agent. The agent runs commands through its own tools, such as a shell tool or an MCP server, when its role has them.

How is this different from GitHub Agentic Workflows?

GitHub Agentic Workflows turn markdown files into GitHub Actions that run on GitHub. An octomind workflow is a TOML file run by one binary on your laptop, a server or inside any CI job, with the model you choose per step.

Start with one command

Apache-2.0 and any model. Install it, then run step one above.

curl -fsSL https://octomind.run/install.sh | bash
Workflows guide →