# Execution Engine

Every session-backed entry point (TUI, which since v1.2.0 sends its runs to the daemon over the Unix socket instead of executing them itself, `/v1/send`, pending resume, Telegram, Discord) goes through the same startup: `exec.Prepare` matches a skill from the input, then `exec.Run` resolves a skill named by the caller, emits the skill and model selection events, picks the model and its fallbacks through `exec/model.Route`, and hands off to `exec.Execute()`. Subagents and the scheduler call `exec.Run` directly with `isSub=true` and skip `exec.Prepare`; the stateless `/v1/chat/completions` skips both and calls `exec.Execute()` itself. `exec.Start` was renamed `exec.Run` in v1.2.1, and `ResolveAgent` became `exec/model.Route` in the same release. Since v1.1.0 reasoning is a per-session setting: when it is `auto` (or unset) the selector inside `exec/model.Route` also decides the reasoning level from the kind of work, and the global `auto_reasoning` switch was removed. Auto routing never selects a `pass`-tier model, even when the message names it, and such models are left out of the fallback list; only a session pinned to one, or a caller passing it as the explicit `model`, runs it.

`exec.Execute()` runs the main loop for up to **256 iterations** (`limits.max_tool_iterations`; 128 before v1.1.2). Each iteration:

1. Assemble messages: `SystemPrompts` + `ContextHistories` (guardrail refusals dropped) + the turn context, if any + `UserMessage` + `ToolHistories` (`ContextHistories` and `UserMessage` were `OldHistories` and `UserInput` before v1.2.1) — appended in that order, never rewritten mid-run, so the prompt-cache prefix stays stable. Since v1.3.7 the instructions connected MCP servers send are rendered inside the main system prompt, ahead of the guardrail block, instead of riding as a second system message, and the system prompt templates are English-only. Since v1.2.0 the turn context is one `user` message built each turn by `assignTurnContext`: the work directory (not for stateless `/v1/chat/completions` runs), the names of the tools to call through `run_tool` (since v1.3.7 MCP tools grouped by server as `mcp__<server>__{a, b}`), the skill list (omitted when `run_skill` is excluded), the background tasks this same task still has running (since v1.3.7, so a resumed turn knows which results are still on their way), the rolling summary as a `Prior summary` JSON block (since v1.3.7; it used to be a separate message between the history and the turn context), and the `CLAUDE.md` / `AGENTS.md` guide when the guide toggle is on; these used to sit in the system prompt, where every change reset the cache. The permission mode is no longer stated there or in the system prompt (Removed in v1.3.7). Since v1.3.7 the summary's `key_decisions`, `past_discussions` and `current_discussion` entries are first filtered by the decision model down to those relevant to the request — every entry is kept without a decision model or when the call fails, and the summary is left out when none is relevant — and the rules for using it live in the system prompt. Since v1.3.1, when a decision model is set, two more checks run in parallel with that one before the loop starts: one adds a tool-gap line telling the model to call `reasoning_guide(topics=["tool_generate"])` first when the request needs a capability no available tool provides (skipped when `reasoning_guide` or `edit_tool` is excluded), and the other drops skills it judges unrelated to the request from the skill list (a failed check keeps every skill)
2. Call `Agent.Send()` on the chosen provider
3. Parse `tool_calls` from the response
4. Dispatch the tool calls through `toolCall.go` (see [Tool Dispatch](/docs/execution-engine-tools))
5. Append results to `ToolHistories`; images returned by tools follow the round's results there as one `user` message (since v1.1.1 — they used to be injected into `UserInput`, which rewrote the cached prefix)
6. Stop when no `tool_calls` remain or the iteration limit is hit

Since v1.3.0 a TUI run can leave work in the background, since v1.3.2 through `background_command` and `background_subagents`; both are excluded from the run unless the request comes from the TUI (`cli-` origin with no deliver target). `run_command_background` was renamed `background_command` (Removed in v1.3.2); `run_websocket` and the `subagents` `background: true` mode were dropped (Removed in v1.3.2): use `background_command` and `background_subagents` instead. Since v1.3.8 the task ends normally even while they run: reports reach it while it is running or pending, and once it has ended a finished group runs its `objective` and `next` as a new task; the task staying pending for its background work was Removed in v1.3.8 — see [Pending Tasks and Cancellation](/docs/execution-engine-pending).

Each `Send` writes one row to the SQLite `usage` table (model, input / output / cache-write / cache-hit tokens, elapsed time); since v1.0.26 the row also records the IDs of the tool calls that response requested. Since v1.1.0 the completion event no longer carries the remaining provider quota; `GET /v1/providers/quota` serves it on request.

There is **no inter-round delay** — rate-limit protection comes from provider round-trip latency, per-model cooldown, and per-tool timeouts.

## Cross-turn workdir reset

The workdir is supplied per request, not carried over from history: the TUI passes its own working directory, `/v1/send` resolves the `work_dir` field, and subagents inherit or resolve theirs. Since v1.2.0 it is written into the turn context on every run, not into the system prompt, so the cached system prefix survives a directory change; a directory mentioned in an earlier turn does **not** carry over through history.

- **Turn context** — a `Work directory: ...` line stating that this directory is authoritative for this turn, that earlier ones in history are ignored, and that `run_command` already starts there. Stateless `/v1/chat/completions` runs keep the line in their own system prompt instead
- **TUI** — the user sets the directory with `Shift+P` (an absolute path, `~/...`, or a path relative to the current one; it must exist), and every later request carries it. Removed in v1.3.0: the agent's `cd` through `run_command` and the `workdir` frame that pushed the new directory to the TUI; `run_command` now rejects `cd` and points to absolute paths or `['sh','-c','cd <dir> && <command>']` for a single command

The per-message metadata header (timestamp + working directory wrapped around each user message) and its TUI stripper `stripUserMetaHeader` were removed; the turn-context work directory line is the only workdir anchor.
