> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dotbot.ch/llms.txt
> Use this file to discover all available pages before exploring further.

# The dotbot execution engine

> Understand how dotbot runs each task as a single provider session, coordinates concurrent task runners, and exposes an HTTP runtime you can drive from the CLI.

dotbot runs each task as one focused provider session. The session explores the codebase, resolves ambiguity, writes code, runs tests, and commits — all within a single attempt. Folding discovery and implementation into one session keeps the agent's context intact from the first file it reads to the commit it makes, and it lets dotbot pause for human input or park a finished task for review without splitting the work across separate runs.

## A task runs as one session

When dotbot picks up a task, it claims the task directly for execution and moves it straight to `in-progress`. There is no separate analysis state. Discovery is the opening part of the same session, not a distinct phase the task transitions through.

```
todo → in-progress → done
```

Inside that single session the agent:

1. Explores the codebase and identifies the files the task will affect
2. Writes code in the task's isolated git worktree
3. Runs the project's test suite and verify hooks
4. Commits changes with a tag in the format `[task:XXXXXXXX]`

<Note>
  Tasks of type `script`, `mcp`, `task_gen`, and `barrier` never start a provider session. The runtime dispatches them deterministically, runs them in the task's worktree, and skips verification hooks. They move straight from `todo` to `in-progress` to `done`.
</Note>

Every commit message dotbot produces includes the short task ID tag, so you can trace any change back to the task that produced it:

```
feat: add user authentication [task:a1b2c3d4]
```

## The HTTP runtime

Task execution sits on top of a per-project HTTP runtime. The runtime owns the task queue, the state transition table, and the activity log. The CLI talks to it over HTTP rather than mutating files directly, which is what keeps concurrent task runners consistent.

You can drive the runtime directly:

| Command                 | What it does                                                       |
| ----------------------- | ------------------------------------------------------------------ |
| `dotbot go`             | Starts the runtime and the web dashboard together                  |
| `dotbot serve`          | Starts only the HTTP runtime in the foreground, with no dashboard  |
| `dotbot runtime-status` | Reports the runtime PID, URL, and the list of active workflow runs |

`dotbot serve` is useful for diagnostics and tests that want the HTTP surface without a UI. It runs until you press Ctrl+C, then removes `.bot/.control/runtime.json` so the next start gets a fresh token. `dotbot runtime-status` exits `0` when the runtime is alive and reachable, `1` when it is not running, and `2` when the PID is alive but the HTTP endpoint is unreachable.

## Multi-slot concurrent execution

dotbot can run multiple tasks from the same workflow in parallel. Each task runs in its own task-runner process and its own git worktree (see [Per-task git worktree isolation](/concepts/git-worktree-isolation)), so there are no file conflicts between concurrent tasks.

You control the concurrency limit with the `execution.max_concurrent` setting in `settings.default.json` or from the Settings tab in the dashboard. It defaults to 1.

<Tip>
  Use a cheaper model tier for simple tasks and reserve the most capable tier for complex ones. Per-task model selection reduces token spend without sacrificing quality where it matters.
</Tip>

## Per-task model selection

Models are configured as tiers — `fast`, `balanced`, and `best` — and each provider maps the tiers to its own concrete models. The default tier is `best`. A task can set a `model` field to override the default for that task:

```json theme={null}
{
  "execution": { "model": "best" }
}
```

Model resolution order: task-level `model` override, then `execution.model` from settings, then the active provider's default model. An unknown tier falls back to the provider default.

## Process types

dotbot runs a unified **task-runner** process per execution slot. Each task-runner claims a task, runs it to completion, and then picks up the next available task. The legacy split between separate analysis and execution processes is gone.

You can see active processes in real time on the **Processes** tab in the dashboard. For each running process it shows the type, the active model, the current task, and elapsed time.

## Flow diagram

```
┌──────────────┐     ┌────────────────────────────────────┐     ┌────────────┐
│   todo       │────▶│            in-progress              │────▶│   done     │
│  (waiting)   │     │  single provider session:          │     │ (committed │
│              │     │  discovery → code → tests → commit  │     │  + merged) │
└──────────────┘     └────────────────────┬───────────────┘     └────────────┘
                                           │
                          ┌────────────────┴─────────────────┐
                          ▼                                   ▼
                   ┌──────────────┐                   ┌──────────────┐
                   │ needs-input  │                   │ needs-review │
                   │ (ask human)  │                   │ (await sign- │
                   │              │                   │  off)        │
                   └──────────────┘                   └──────────────┘
```

When the agent cannot resolve a question from the codebase, it moves the task to `needs-input` and routes the question to a stakeholder via Teams, Email, or Jira. Once an answer arrives, the task returns to `todo` and is picked up again with the answer in context. When a task requires human sign-off before it merges, it moves to `needs-review` instead of `done`. See [Task lifecycle states and transitions](/concepts/task-lifecycle) for the full state machine.
