# Agent Runtime

GoClaw runs one or more agents in one process. Each agent is an entry in `agents.list` with its own workspace, model and memory, and channel messages reach an agent through [routing](../routing.md). With no `agents.list`, there is one agent, `main`. Every agent processes messages with an LLM provider and tool calling.

## Architecture

```mermaid
flowchart TD
    MSG["User Message"] --> RUNTIME["<b>Agent Runtime</b><br/>System Prompt + History + Memory"]
    RUNTIME --> LLM["<b>LLM Provider</b><br/>Gemini / Claude / OpenAI / DeepSeek"]
    LLM -->|Tool Calls| POOL["<b>WorkerPool</b><br/>Parallel execution · Bounded concurrency"]
    POOL -->|Tool Results| LLM
    LLM -->|Streamed Tokens| RES["Final Response"]
    RES --> CH["Channel Output"]
```

## Agent Loop

The event-driven agent loop (`ProcessStream`) is shared across all LLM providers:

1. Build the system prompt from workspace files + skills + memory
2. Append session history and the new user message
3. Call the LLM with the tools selected for this request: the core tools, plus the tools Tool RAG picks for the message (`tools.rag.top_k`, default 12) and the agent's most-used tools (`tools.rag.usage_prior`, default 6). The model can add a tool the selection left out with `search_tools`
4. If the LLM returns tool calls:
   - Execute tools **concurrently** via the bounded `WorkerPool`
   - Feed tool results back to the LLM via event channels
   - Repeat (up to `tools.max_tool_iterations`, default 20)
5. If the LLM returns text only, stream `EventTokenChunk` to the client

The Gemini provider uses a custom loop (native `genai` SDK) that natively streams content, but follows the same logical flow.

## LLM Providers

| Provider | Config Key | SDK |
|----------|------------|-----|
| OpenAI | `openai` | github.com/openai/openai-go/v3 (official) |
| Claude (Anthropic) | `claude` | github.com/anthropics/anthropic-sdk-go (official) |
| Gemini | `gemini` | google.golang.org/genai (native) |
| Gemini Legacy (deprecated) | `gemini-legacy` | served as `gemini` |
| DeepSeek | `deepseek` | github.com/openai/openai-go/v3, DeepSeek's API (DeepSeek publishes no Go SDK) |
| Ollama | `ollama` | github.com/ollama/ollama/api (official) |

The provider is chosen at startup from `ai.provider`. An agent's `agents.list[].model` overrides it for that agent, either as a provider name (`claude`) or as `provider/model` (`claude/claude-sonnet-4-5-20250929`). With neither set, the provider is `openai`.

## Model Failover

Every provider makes a model call again when it fails because the provider is overloaded (twice, after about 2 and 6 seconds) or on the network (once, after half a second); quota, billing and key errors are not retried ([Provider Fallback](../provider_fallback.md#before-it-moves-on-the-same-provider-is-asked-again)).

When the provider still fails before the reply has used a tool, the request moves to the next `provider/model` of `ai.fallback`, or of the agent's own `agents.list[].fallback`, which replaces it. A provider that keeps failing is put in cooldown and skipped while others remain. [Model Failover](model-failover.md) explains how.

## System Prompt

The system prompt is assembled in this order (`GetStaticSystemPromptFor` in `agent.go`):

1. **Core instruction** — the admin's core instruction for this agent, when one is set
2. `IDENTITY.md` and `SOUL.md` — Identity, persona, tone, boundaries. A subagent gets its profile here instead
3. `AGENTS.md` — Operating instructions, rules
4. **Instructions** — the admin's `instructions/<name>.instructions.md` that apply to this run and name no tools
5. `TOOLS.md` — Tool usage notes and conventions (narrowed to the step's tools in a SOP step)
6. **Tool priority**; when Tool RAG is on, **finding tools** (`search_tools`); **when you cannot get it**: say which of three it is, in a sentence or two (no tool can do it; a tool exists but needs an administrator, was not offered here or was blocked by a rule; or the tool failed or found nothing), and never present other data as the answer; and **GoClaw documentation**: `goclaw_docs` for how GoClaw is configured and how it works, not for data a webhook or a system sent or holds
7. **Workspace, runtime and workspace files** — Working directory path, OS, host, timezone, and a listing of the workspace
8. **Skills** — Loaded skill markdown (built-in + user + workspace), filtered by Skill RAG
9. **Memory protocol** and **memory routing policy** — Which memory scope to use, and who may teach what
10. **Subagent delegation** — when the agent has `subagents.allow_agents`

A missing file is skipped. `Memory.md`, personal and global memory, agent notes and lessons are not part of this prompt: what holds for the session goes into the session context that follows it, and what was found for the message (the notes, lessons and personal memory it matches, and the current time) follows the person's message, after the history, so the providers' prompt caches keep the conversation from turn to turn ([Memory](../memory.md#3-session-context-injection)).

### Bootstrap File Protection

The following files are **read-only** except to an admin and to cron and SOP runs that act for no one in particular:

- `Memory.md`
- `SOUL.md`
- `TOOLS.md`
- `AGENTS.md`
- `IDENTITY.md`
- `USER.md`
- subagent profiles (`agents/*.agent.md`) and instructions (`instructions/*.instructions.md`)

The `file_write` and `file_edit` tools refuse to write them for other callers.

## Workspace

The default agent's workspace is `~/.goclaw/workspace/`. Every other agent's is `~/.goclaw/agents/<id>/workspace/`. `agents.list[].workspace` sets another path for either.

The workspace is the agent's working directory for all file operations. Path traversal outside the workspace is blocked.

### Bootstrap Files

| File | Purpose |
|------|---------|
| `SOUL.md` | Agent persona and boundaries |
| `AGENTS.md` | Operating rules and guidelines |
| `TOOLS.md` | Tool documentation and conventions |
| `Memory.md` | Long-term memory (shared across sessions) |

A new workspace is seeded with these four files from defaults built into the binary. In the default agent's workspace, `TOOLS.md` and `AGENTS.md` are written again from those defaults at every start (`AGENTS.md` from the `tools.mode` profile), so edits to those two files there do not last; `SOUL.md` and `Memory.md` are seeded only when missing. Rules of your own belong in an instruction (`instructions/<name>.instructions.md`, on the Web UI's Instructions page) instead.

### Memory

`Memory.md` is the agent's curated long-term memory; it goes into the session context of every request. Everything the agent learns at run time is stored as records in the database, not as files:

- `memory_write` saves a record in one of four scopes: `personal` (one user's own context, never written or loaded in cron and SOP runs), `agent_notes` (org-wide knowledge: admins, cron and SOP runs, and whoever `memory.write_access` lists), `global` and `agent_config` (admins, and whoever `memory.write_access` lists; never SOP, cron or webhook runs)
- `memory_search` searches memory by meaning and keywords; `memory_get` reads a full entry
- Bootstrap files are **read-only** for non-admins (see above)

## Canvas

There is no canvas tool the model calls directly (`canvas_show` exists in `canvas.go` but is not registered). Files reach the canvas from tools that produce them:
- `browser` (its `screenshot` action) saves the PNG and shows it to Web UI clients as a `canvas` message
- `diagram_render` renders a Mermaid diagram to PNG
- `file_write` with `attach: true` attaches the file it wrote

These files are collected for the request and sent as attachments with the answer, on every channel. Screenshots and diagrams are stored in `~/.goclaw/canvas/`.
