Skip to content

dotbot run <workflow> without --watch never starts the runtime and fails asynchronously #682

Description

@EnmaJim

What happened

dotbot help documents the verb plainly, with --watch presented as an optional monitoring
convenience:

run               Run/rerun a workflow

Running it without --watch reports success and exits 0:

> dotbot run smoke-test
› Minting WorkflowRun for 'smoke-test'...
    Run: wr_BMrYEikb → 2026-08-05-smoke-test-BMrY
› Creating 1 task(s) under the run...
    + Headless Smoke Check [t_fn0JIddl]
  ✓ Created 1 task(s) for smoke-test
› Launching workflow process...

  ✓ Workflow 'smoke-test' started.
    Use 'dotbot run smoke-test --watch' to run and monitor without opening the UI.

exit=0

The detached runner then immediately parks the task in needs-input:

"status": "needs-input",
"pending_question": {
  "question": "Per-task failure for 'Headless Smoke Check'",
  "context": "Per-task exception: Dotbot runtime endpoint not available. Start the runtime with
              'dotbot go' or set DOTBOT_RUNTIME_URL + DOTBOT_RUNTIME_TOKEN."
}

Nothing runs. .bot/.control/smoke-test.json (the workflow's only output) is never written.

Compare the two transcripts of the same command on the same project. With --watch:

› Launching workflow process...
› Starting headless runtime...
  ✓ Runtime ready at http://127.0.0.1:53523/
  ✓ Workflow 'smoke-test' started.
  ...
  ✓ Workflow process completed.        exit=0, 22.7s, task done

Without --watch, the › Starting headless runtime... step never appears. The runtime is
auto-started only on the watch path, while the detached runner requires it unconditionally.

That a --no-auto-runtime flag exists at all implies auto-start is meant to be the default behaviour,
not a side effect of --watch.

This is easy to hit without meaning to: any invocation that fails to bind --watch falls into the same
hole. dotbot run smoke-test --poll-interval-ms (flag with a missing value) silently drops --watch
handling and launched a real run that failed this way — that is how this was first observed.

What you expected

Either:

  1. dotbot run <workflow> starts the runtime the same way --watch does (with --no-auto-runtime as
    the documented opt-out); or
  2. if a runtime is genuinely required and cannot be auto-started on this path, the command refuses
    synchronously with a non-zero exit and the message that the task file ends up carrying —
    Dotbot runtime endpoint not available. Start the runtime with 'dotbot go' — instead of printing
    ✓ Workflow 'smoke-test' started. and exiting 0.

Reporting success for a run that cannot make progress is the core problem; a script or CI step has no
way to detect it.

Steps to reproduce

Deterministic, no AI provider needed — smoke-test is a single script task.

$env:DOTBOT_HOME = '<dotbot checkout>'
$repo = 'C:\tmp\nowatch-repro'
git init -b master $repo; cd $repo
git config user.email a@b.c; git config user.name t
'x' > README.md; git add -A; git commit -qm init
& $env:DOTBOT_HOME\bin\dotbot.ps1 init -y
git add -A; git commit -qm 'chore: dotbot init'
& $env:DOTBOT_HOME\bin\dotbot.ps1 workflow add smoke-test -y

# 1. no --watch: prints success, exits 0
& $env:DOTBOT_HOME\bin\dotbot.ps1 run smoke-test
"exit=$LASTEXITCODE"

# 2. wait, then inspect the task
Start-Sleep -Seconds 20
Get-ChildItem .bot\workspace\tasks\workflow-runs -Recurse -Filter 't_*.json' |
  ForEach-Object { (Get-Content $_ -Raw | ConvertFrom-Json) |
    Select-Object id, status, @{n='ctx';e={$_.extensions.runner.pending_question.context}} }
#   -> status = needs-input, ctx = "Dotbot runtime endpoint not available..."
Test-Path .bot\.control\smoke-test.json      # -> False, the workflow produced nothing

# 3. contrast: the same command WITH --watch succeeds
& $env:DOTBOT_HOME\bin\dotbot.ps1 run smoke-test --watch
"exit=$LASTEXITCODE"                          # -> 0
Test-Path .bot\.control\smoke-test.json      # -> True

Environment

OS: Windows 11 Pro 10.0.26200 | dotbot v4.0.2 (main @ 7c95b466)
pwsh 7.6.4 | git 2.54.0.windows.1 | claude CLI 2.1.222 (not exercised — script task only)
DOTBOT_HOME set explicitly; %APPDATA%\dotbot\user-settings.json absent
No dotbot go / serve running when the command was issued

Severity

high

Logs / screenshots

The failed run still creates and pushes an integration branch, so a run that accomplished nothing
leaves debris on the remote (see #683). From .bot/.control/activity.jsonl:

error  Mandatory task failed, stopping workflow: Headless Smoke Check
text   Integration branch workflow/smoke-test-YszU pushed to <origin>. Open a PR into master.
text   Process proc-194577 finished (stopped, tasks_completed: 0)

The generated handoff document, showing the task never reached a worktree:

## Identity
- Task: t_TWjZjyvu - Headless Smoke Check
- Run: wr_YszUcnx2
- Reason: workflow-escalation
- Worktree: C:\Users\EnmaLap\Desktop\tanda        <- the main checkout, not a task worktree
- Branch: master

## Context
Per-task exception: Dotbot runtime endpoint not available. Start the runtime with 'dotbot go'
or set DOTBOT_RUNTIME_URL + DOTBOT_RUNTIME_TOKEN.

Workaround: always pass --watch, or start dotbot go before dotbot run.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    Status
    Inbox

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions