---
title: "MiniAgent"
id: "1700"
type: "page"
slug: "mini-agent"
published_at: "2026-09-20T19:50:18+00:00"
modified_at: "2026-11-14T11:18:05+00:00"
url: "https://xedant.com/agents/agent/docs/mini-agent/"
markdown_url: "https://xedant.com/agents/agent/docs/mini-agent.md"
excerpt: "MiniAgent is the built-in coding agent: a fully self-contained backend compiled right into Agent (a…"
---

# MiniAgent

[https://xedant.com/agents/agent/docs/mini-agent/.md](https://xedant.com/agents/agent/docs/mini-agent/.md)

**MiniAgent** is the built-in coding agent: a fully self-contained backend compiled right into Agent (a C# library, a minimal Pi-style agent rewritten from scratch). It needs no external program and has nothing to install — Agent and MiniAgent are one whole and **fully self-sufficient out of the box**.

MiniAgent is part of Agent’s backend system and is selected with the `AGENT_BACKEND=mini` variable. For the general overview of backends, see the [Backends](/agents/agent/docs/backends)
 page.

## Why this matters for your business

Regular backends are third-party programs downloaded and installed through a package manager. MiniAgent is different: it lives **inside** Agent itself, which means:

- **Independence from third-party developers.** The agent’s work does not depend on someone else’s projects and their updates — the engine is always at the server’s side.
- **Supply security.** No packages installed from third-party sources — the very risk of receiving a compromised installer disappears.
- **Self-sufficiency out of the box.** MiniAgent is already inside the product: nothing to download, install, or update separately.
- **Everything on your server.** The agent runs wherever Agent runs: your data never leaves your infrastructure.

## Capabilities

It is a full agent with everything real work needs:

- **Tools**`read`, `write`, `edit`, `bash`, `parallel_bash`, `grep`, `find`, `ls`, `glob`, `load_skill`, `todo_write`, `agent`, and the background tasks `agent_start`, `agent_check`, `agent_stop` — reading, editing, and creating files, running commands, search, skill loading, and launching subagents;
- **Persistent sessions** — the conversation is saved in JSONL format and resumes after a restart;
- **Model and reasoning-level switching on the fly** — right in the middle of a dialog, losing nothing;
- **One thinking level for every chat** — a single profile setting for the whole process; it wins over the model-name suffix and over the level stored in a session;
- **Automatic context compaction** — long conversations do not “forget” their beginning;
- **Retries on transient provider failures** and protection from lost replies — the pause between attempts and their number are configurable, and every retry is visible in the chat as its own line (more below);
- **Token and cost accounting** — in the chat and in analytics;
- **Project context** — reads `CLAUDE.md`/`AGENTS.md` itself (`CLAUDE.md` takes priority) and finds the `.claude/skills` skills on its own;
- **Interactive forms and buttons** (`agent.form`/`agent.button`) — right in the system prompt, with no separate extensions;
- **Image reading** — the `read` tool attaches an image file to the request (details in the note below);
- **Frugal file reading** — how many lines `read` returns per call is configurable, and a long file is read in parts instead of filling the context at once;
- **Loading pages and searching the web** — the agent opens the addresses it needs and searches the internet on its own: the `fetch` and `search` calls go through a configurable list of services, and when one service does not answer, the turn passes to the next one (more below);
- **External tools and rules** — MiniAgent connects the MCP servers from `mcp.yml` itself and applies the hooks from `hooks.yml`: in mini chats they work exactly as they do for the command-line backends;
- **Subagents** — the `agent` tool launches a nested session with its own context, visible as a child chat: several calls in one answer run simultaneously, and right beside them sit background tasks whose outcome arrives in the current turn by itself (more below).

*Note: sending images into the chat is not wired up yet — images attached to a message are ignored with a warning in the log. At the same time the agent reads images from disk itself with the `read` tool: on models whose image input is allowed, the file is attached to the request (jpg, png, gif, webp, bmp up to 5 MB), while on text-only models a clear error comes back. A file over the limit is rejected with a hint to shrink it with a command.*

## Connecting it

MiniAgent is selected with the `AGENT_BACKEND=mini` variable. The easiest way is to create a model from a ready provider template that already carries the MiniAgent backend: **Anthropic, DeepSeek, z.ai, BigModel, OpenRouter, xAI, MiniMax, Moonshot, OpenAI, OpenCode Go/Zen**. The template fills in the backend and the connection parameters for you:

- `MINI_BASE_URL` — the provider address;
- `MINI_API` — the protocol format: `anthropic-messages` or `openai-completions`;
- `MINI_AUTH` — the authorization type: `api-key` or `bearer`;
- `MINI_API_KEY` — the access key.

The model is set in the “provider/model:thinking” format, for example `MODEL=anthropic/claude-sonnet-5:medium`. The `:thinking` suffix sets the reasoning level: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`; without a suffix the level is `medium`. A model the templates do not know is assembled automatically from the parameters above; when a `~/.mini/models.json` file exists (a Pi-compatible format), it takes priority. If no model is set at all, `deepseek/deepseek-v4-flash` is used. The default provider can be set with the `MINI_PROVIDER` variable — it applies when the model name has no “provider/” prefix.

## Data

MiniAgent’s data is stored in the `~/.mini` folder (overridable with the `MINI_AGENT_DIR` variable):

- `models.json` — the model configuration;
- `agent-sessions` — sessions in JSONL format;
- `skills` — additional skills;
- `CLAUDE.md` — the global context.

## MiniAgent profiles

**A profile is a named set of settings for the built-in agent**: which context files to load, which tools it may use, how long a single call may run, the token ceiling for requests, and how many subagents may run at once. Profiles let you keep several modes of working in one project: a “safe” one without `bash` for sensitive repositories, a “draft” one with a long timeout for heavy tasks, a “read-only” one for reviews — and switch between them just by changing the model.

Profiles live in the `miniagent.yml` file in the project’s brand folder (`.xedant/`). The root map is `profiles:` — the key is the profile name, the value is its settings:

```
# miniagent.yml
profiles:
  safe:                       # safe mode: no bash, a short timeout
    disabledTools:
      - bash
    toolCallTimeout: 60
    loadAgentsMd: false

  readonly:                   # read-only: only the search tools are allowed
    enabledTools:
      - read
      - grep
      - find
      - glob
      - ls
```

The model picks the profile with a `mini:name` suffix in the `AGENT_BACKEND` variable of the model’s configuration on the [Models](/agents/agent/docs/models)
 page — for example, `AGENT_BACKEND=mini:safe`. The profile name is lowercased and looked up case-insensitively; the legacy alias `mini-agent:safe` works too. A plain `AGENT_BACKEND=mini` without a suffix, an empty suffix, or a **nonexistent name** all give the built-in defaults — a missing profile logs a warning. Only the MiniAgent backend understands the colon suffix; other backends take the `AGENT_BACKEND` value as a whole.

## Profile settings

Every profile field is optional: a missing field, an empty `{}` profile, or a missing file all mean the built-in defaults.

| Field | Type | Default | What it does |
| --- | --- | --- | --- |
| loadClaudeMd | bool | true | loads CLAUDE.md into the context |
| loadAgentsMd | bool | true | loads AGENTS.md into the context |
| enabledTools | list of names | none (all 11 enabled) | the tool allowlist; an empty list is an error; mutually exclusive with disabledTools |
| disabledTools | list of names | none (all enabled) | the tool denylist; mutually exclusive with enabledTools |
| toolCallTimeout | int, seconds | 300 | the ceiling on a single tool call |
| maxOutputTokens | int | 384000 | the request’s output-token ceiling; by default the ceiling comes from the model’s own description (384000); overrides the model’s maxTokens |
| thinkingBudget | int | 65536 | the thinking budget for every reasoning level except off; applied on anthropic endpoints |
| thinkingLevel | string | the level from the model name, else medium | one reasoning level for every session of the profile; wins over the :thinking suffix and over the level a session has stored; one of off, minimal, low, medium, high, xhigh, max |
| parallelBashThreads | int | 5 | how many commands of one parallel_bash call run at once |
| readMaxLines | int | 500 | how many lines one read call returns before truncation; the second cap is 50 KB per response |
| maxParallelAgents | int | 4 | how many subagents of one chat run at once; the rest wait in the queue |
| systemPrompt | string | built-in | replaces the built-in base system prompt; empty also means built-in |
| sessionHeader | string | none (X-Agent-Session, X-Opencode-Session on opencode) | the name of the HTTP header carrying the session id on every provider request; a headers entry in models.json with the same name takes priority |

**The thinking level.** The `thinkingLevel` field sets one level for every session of the profile — handy when the whole server must work at one level: thinking switched off for speed and savings, or turned all the way up for complex tasks, for example. The setting wins over both the `:thinking` suffix in the model name and the level stored in the session. The level affects not only the quality of the answer but also the bill: the higher it is, the longer the model thinks and the more tokens it spends. One more thing to know about DeepSeek-family servers: they used to always run at their own default level — thinking on, maximum effort — and the level chosen in the chat never reached them. Now the level arrives: thinking can be turned off or lowered.

**How many lines the agent reads.** The `readMaxLines` field limits how many lines one `read` call returns — 500 by default. The second cap is 50 KB per response: a file made of a few huge lines is truncated by size. When a file is longer, the agent receives a hint of where to continue and reads it on with further calls: it sees the whole big file, but the context is not filled with it in one go. Fewer lines per call — a cheaper conversation, but more calls to the file.

A profile manages exactly the 11 built-in tools: `read`, `bash`, `parallel_bash`, `edit`, `write`, `grep`, `find`, `glob`, `ls`, `load_skill`, `todo_write`. The `agent`, `agent_start`, `agent_check`, and `agent_stop` tools stand apart: they are added to every root chat always, and the profile lists never filter them — none of them can be enabled or disabled through a profile. **Both `enabledTools` and `disabledTools` in one profile is an error** (in the yml and in environment variables alike): allowing and forbidding the same tool makes no sense. An empty `enabledTools` is rejected — it would leave the profile with no tools at all — while an empty `disabledTools` only produces a warning. `fetch` and `search` never appear in either list either: they are not built-ins and stand on their own — each exists once its own catalogue holds at least one enabled service of its kind: `fetch.yml` for `fetch`, `search.yml` for `search` (more below).

Each setting’s priority: **the model’s variable > the server process environment variable > the profile > the built-in default**. The profile lays on top of the defaults, a `MINI_PROFILE_*` variable on top of the profile, and a variable set on the model itself on top of a server-wide one — so a value can be overridden for a single model without creating a separate profile. An empty value does not zero a setting: it counts as unset and the next source down answers.

**The session header.** Every provider request carries the session id in an HTTP header — the receiving provider can tell MiniAgent chats apart: group traffic, rate-limit requests, or keep per-session storage without parsing the conversation. By default the header is named `X-Agent-Session`; on opencode providers (a provider id starting with `opencode` or an address on `opencode.ai`) — `X-Opencode-Session`. The name is changed by the profile’s `sessionHeader` field or the `MINI_PROFILE_SESSION_HEADER` variable; an explicit `headers` entry in models.json with the same name beats the automatic stamp. The `sessionHeader` key has no editor in the settings dialog — you write it into `miniagent.yml` by hand or set the variable; the dialog passes a hand-set value through unchanged. A request sent before the session id exists carries no header.

## Environment variables

Any profile setting can be overridden with a `MINI_PROFILE_*` variable — at the process level, for every mini chat on the server, or on a single model, in that model’s variables. In both cases it applies on top of the selected profile (or the defaults, when no profile is set):

| Variable | Overrides |
| --- | --- |
| MINI_PROFILE_LOAD_CLAUDE_MD | loadClaudeMd |
| MINI_PROFILE_LOAD_AGENTS_MD | loadAgentsMd |
| MINI_PROFILE_ENABLED_TOOLS | enabledTools (comma-separated names) |
| MINI_PROFILE_DISABLED_TOOLS | disabledTools (comma-separated names) |
| MINI_PROFILE_TOOL_CALL_TIMEOUT | toolCallTimeout |
| MINI_PROFILE_MAX_OUTPUT_TOKENS | maxOutputTokens |
| MINI_PROFILE_THINKING_BUDGET | thinkingBudget |
| MINI_PROFILE_THINKING_LEVEL | thinkingLevel |
| MINI_PROFILE_READ_MAX_LINES | readMaxLines |
| MINI_PROFILE_PARALLEL_BASH_THREADS | parallelBashThreads |
| MINI_PROFILE_MAX_PARALLEL_AGENTS | maxParallelAgents |
| MINI_PROFILE_SYSTEM_PROMPT | systemPrompt |
| MINI_PROFILE_SESSION_HEADER | sessionHeader |

**An empty variable value counts as unset** — the setting comes from the next source down, the profile or the built-in default, so you can “clear” an override with an empty string. Both list variables at once (`MINI_PROFILE_ENABLED_TOOLS` and `MINI_PROFILE_DISABLED_TOOLS`) is a hard error, as is an unparseable value (not `true`/`false`, not a positive number): the session is not created, and the error names the variable.

Example — a 120-second tool-call timeout and `bash` disabled for all chats: set the variables `MINI_PROFILE_TOOL_CALL_TIMEOUT=120` and `MINI_PROFILE_DISABLED_TOOLS=bash`.

MiniAgent, like the other backends, respects the network variables `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY`: when the server reaches the internet through a proxy, provider requests go through it too, while addresses from `NO_PROXY` go direct. Details on the [Models](/agents/agent/docs/models)
 page.

## The parallel_bash tool

`parallel_bash` is MiniAgent’s tool for running **several independent commands in one call**. The model decides which commands do not depend on each other (this independence contract is fixed in the tool’s description) and combines them into a single call:

```
parallel bash:
  - git status --short
  - ls pages/ | wc -l
  - df -h /project
```

The commands run concurrently: `parallelBashThreads` (5 by default) limits how many run at once, the rest wait in the queue. The call finishes after every command answers, and the result returns **ordered `[i] command` sections — one per command, in input order**, so the agent can match each output to its command. The trivial difference from `bash`: `bash` runs one command, `parallel_bash` runs a batch; both work on the shared `ShellCommand` core, and `bash` behavior is unchanged.

## Loading pages and searching the internet

MiniAgent works not only with the files on the server: it can open pages on the internet and search for what it needs on its own. These are two separate tools — `fetch` for loading a page by address and `search` for searching. For a business this saves the main thing — time: no need to copy documentation, articles, and search results into the chat by hand. Just ask, and the agent brings the page content or a list of findings with links, and then works with it like ordinary text.

### Page loading

`fetch` downloads a page by address and hands it to the model as readable text: the page markup is converted into plain text with light formatting, while content that already arrives as text, a data table, or markup for programs comes through as it is (the `markdown: false` argument returns the raw body unconverted). If the markup itself matters, the model can ask for the source content without conversion. A page too big for the conversation does not fit in: the agent receives it as a file and reads the pieces it needs with ordinary reading. In the compact view the call shows as the short line **Fetch {url}** with the address; in the normal view — as a call card with the same address and an expandable result.

### Web search

`search` runs the query and brings a numbered list of findings: a title, an address, a short snippet, and the date when the engine provides one. If the engine answered the question itself, that answer arrives as an `Answer:` line above the list. The model decides how many results to ask for (the `count` argument, ten by default) and in what language to search (`language`, the two-letter code). In the compact view the call shows as the line **Search {query}** with the query text; the results expand right there, in the call card.

### Several services and the fallback

Page loading and searching are handled not by the agent itself and not by one program but by a **list of services** — one you configure yourself. It is done this way because sites are very different: an ordinary page is enough to request directly, another one only answers through a proxy, a third is assembled by scripts and opens only in a real browser. Every service has a **priority**: the service with the lower number is tried first, and if it did not answer or answered with an error, the turn passes to the next one. So one broken key or an unreachable proxy does not stop the work — the next service in the list carries it. There is one exception: once a service has returned content, the HTML→Markdown conversion is a hard stop — a conversion failure is not replayed by the remaining services, because re-downloading the same address would reproduce the same failure.

### The fetch.yml and search.yml files

Page loading and searching are configured in two different files of the project’s brand folder ([.xedant/](/agents/agent/docs/xedant-folder)
): loading in `fetch.yml`, searching in a separate `search.yml`. The two are built the same way, and each has its own `services:` section listing its services. An entry has five fields: `name` (the name the service is known by in messages), `type` (the service type), `enabled` (the switch), `priority` (the priority), and `settings` (the type’s settings — addresses, keys, time limits):

Here is what a fetching service looks like in `fetch.yml`:

```
# fetch.yml — page fetching only
services:
  - name: Direct HTTP
    type: Direct          # Direct | Proxied | BrowserEmulation | Nodriver |
#   RemoteBrowser | ScriptFetch (case-insensitive)
    enabled: true         # false never joins the chain (default: true)
    priority: 100         # lower is tried first (default: 100)
    settings:             # free-form map, validated against the type's schema
      UserAgent: "Mozilla/5.0 ..."
      TimeoutSec: "30"
```

And this is a searching service in `search.yml` — the section and the fields are the same, only the types and their settings differ:

```
# search.yml — internet search only
services:
  - name: Serper
    type: Serper
    enabled: true
    priority: 100
    settings:
      ApiKey: $SERPER_API_KEY   # the key comes from the environment
```

**Secrets stay out of the files.** Every settings value expands `$VAR`, `${VAR}`, and `${VAR:-default}` at call time — against the chat’s variables first, then the server process environment. An unset variable without a default keeps the literal text and logs one warning. So the file carries `ApiKey: $SERPER_API_KEY`, never the key itself.

**Validation.** Each entry has five keys: `name` (unique within its own file — attempts and warnings name the service by it), `type` (from the tables below, case-insensitive), `enabled` (default `true` — `false` never joins the chain), `priority` (default 100), and `settings`. A settings key the type does not know is a warning — the value is kept as written. A missing required key, a non-positive number, an off-catalog enum value, or a URL that is not an absolute http(s) address rejects the service; duplicate names within its own file and a non-positive `priority` are file errors. Both files are checked on save and at build — each file on its own, by the same rules as the other settings files, and the settings dialog refuses a save that breaks them.

**It works out of the box — fetching.** A `fetch.yml` with one enabled fetching service is created automatically on first start, so `fetch` works immediately without any setup; a file that fails to parse reads as the same default service, with one warning in the log. **Searching ships with nothing — deliberately.** `search.yml` is not pre-created: it appears when you save the first searching service. Ten of the eleven search types need an API key before they can do anything, so there is no built-in search service: until you add one, the `search` tool does not exist. A tool that errors on every call would be worse than a hidden one.

### Fetch service types

| Type | What it runs | Settings (kind; default) |
| --- | --- | --- |
| Direct | Plain HTTP GET from this machine | UserAgent (text; the built-in Firefox agent), ExtraHeaders (text; Key: Value per line), TimeoutSec (number; 30) |
| Proxied | The same GET through the service’s HTTP proxy | ProxyUrl (url; required), ProxyUsername (text), ProxyPassword (secret), UserAgent (text; the built-in Firefox agent), TimeoutSec (number; 30) |
| BrowserEmulation | A local Playwright browser renders the page (first use downloads it) | BrowserType (chromium, firefox, webkit; chromium), WaitMs (number; 3000), UserAgent (text) |
| Nodriver | Undetected chromium drives the page through a self-provisioned Python venv | WaitMs (number; 3000), TimeoutSec (number; 60) |
| RemoteBrowser | An external browser service renders the page | ServiceUrl (url; required), Protocol (PlaywrightMcp, Zendriver; PlaywrightMcp), WaitMs (number; 3000), TimeoutSec (number; 60) |
| ScriptFetch | A shell command fetches the URL and prints the JSON envelope | Command (text; required), TimeoutSec (number; 60) |

### Search service types

| Type | What it queries | Settings (kind; default) |
| --- | --- | --- |
| Serper | Google results through the serper.dev API | ApiKey (secret; required), TimeoutSec (number; 30) |
| Keenable | Web results through the Keenable search API | ApiKey (secret; required), TimeoutSec (number; 30) |
| SearXNG | A self-hosted or public SearXNG instance, in its JSON format | BaseUrl (url; required), TimeoutSec (number; 30) |
| DuckDuckGo | Keyless HTML scraping of DuckDuckGo results — fragile, expect rate limiting | ProxyUrl (url), TimeoutSec (number; 30) |
| Brave | Web results through the Brave Search API | ApiKey (secret; required), TimeoutSec (number; 30) |
| Tavily | Web results plus an engine answer through the Tavily API | ApiKey (secret; required), TimeoutSec (number; 30) |
| JsonSeo | A search engine of your choice through the JsonSeo API | ApiKey (secret; required), Engine (yandex, google, bing; yandex), Region (text), TimeoutSec (number; 30) |
| Tinyfish | Web results through the Tinyfish API | ApiKey (secret; required), TimeoutSec (number; 30) |
| Exa | Web results with highlights through the Exa API | ApiKey (secret; required), TimeoutSec (number; 30) |
| Anysite | A live scrape of the engine of your choice — slow, credit-priced | ApiKey (secret; required), Engine (bing, brave, baidu, startpage, yandex; bing), TimeoutSec (number; 120) |
| ScriptSearch | A shell command runs the query and prints the results envelope | ScriptKey (text; required), Args (text; a JSON object), TimeoutSec (number; 60) |

### The Fetch services and Search services tabs

Editing the list by hand in the file is not required: in the **MiniAgent** dialog, next to the profiles, there are the **Fetch services** and **Search services** tabs. The first tab writes `fetch.yml`, the second — `search.yml`: two independent files and two independent saves, each against its own last-read checksum. Everything else about them is identical:

- **The list of services** — in priority order, with add, edit, duplicate, and delete; beside it the enable switch, the priority field (“A lower number is tried first”), and the hint that a new service’s priority is set one above the current maximum — that is, it is tried last;
- **The form follows the service type** — pick a type and the fields appear on their own: the name is filled in from the type, required fields are marked, keys and passwords are masked and shown by a button, and every field shows its default value;
- **“Test”** — runs one service: fetching is checked against a simple page, searching with a small query. You see success, latency, the explanation, and a sample of the answer. The test runs the **saved** file, so save your edits first — the dialog warns about that;
- **Copying and pasting** — a service definition can be copied to the clipboard and pasted back or into another project, as JSON — one service or the whole set at once: identical settings travel between instances without manual entry;
- **Error and conflict protection** — saving each tab validates only its own list by the same rules as the file (an unknown type, a missing required setting, a duplicate name, a non-positive priority) and is rejected naming the service and the field; if the file was changed outside the dialog (the project settings text tab, a text editor), the tab offers to reload exactly that file instead of silently overwriting the outside edit. Each file has its own update event, so editing one never resets the other. A save runs the file’s validation build.

### When there are no services and when edits take effect

Disable every fetching service — and the `fetch` tool simply does not exist for new chats: the model request carries neither a tool description nor a mention in the instructions. Searching works the same way: while there is no `search.yml` file or all of its entries are disabled, there is no search tool in the chat. A missing `fetch.yml` does not switch fetching off, though: the server creates it at startup with the built-in Direct service. The settings are read once, at chat creation, so catalogue edits apply to new chats, and a conversation already underway finishes with the previous list.

## Subagents

**The `agent` tool lets the model launch a separate subagent** — a nested session with its own context and its own journal. It is the same trick as “subtasks” on command-line agents: a big task is split into parts, and each part works in a clean context without cluttering the main conversation.

- The call carries a task description and detailed instructions — the argument shape of a command-line agent’s subtask tool;
- the nested run shows up as a **separate child chat** linked to the parent: its messages, spend, and cost appear in real time, while a subagent summary grows in the parent chat;
- the subagent’s final reply (truncated to the shared output caps) returns to the parent as the tool result;
- a subagent runs without the chat’s skill, without MCP servers, without hooks, and without the `agent` tool itself — it cannot launch a subagent of its own;
- stopping the parent chat reaches the nested run too, and the child chat keeps everything that run managed to produce.

### Several subagents at once

When one answer contains several `agent` calls, they start **simultaneously**: the cards of all the calls appear at once, and the results come back in call order. How many subagents of one chat run at a time is set by the profile’s `maxParallelAgents` setting (4 by default): extra calls queue up and start as soon as a slot frees. The limit is shared by the whole chat — ordinary and background tasks wait in the same queue.

### Background tasks

Three separate tools exist for long work. `agent_start` queues a task and hands back its **number** at once. `agent_check` reports the task’s state, and once it has finished — its final answer or the error text. `agent_stop` stops a running task or cancels one that is still waiting for its turn.

- **The outcome arrives by itself.** Nothing has to be polled: a finished task brings its result into the current turn on its own, and it is visible on the `agent_start` call line — as an expandable result, exactly like an ordinary call’s. While the chat still has unfinished background tasks, the turn does not close;
- **A short label instead of the number.** In the chat, background calls are shown as a plain-language line — “Start …”, “Check …”, “Stop …” — with the task name the model came up with, not with its number;
- **The result is not lost.** A task’s outcome is kept on the server: you can come back to it by the same number — in another turn, and after an application restart. Tasks cut short by a server shutdown are closed out with a stop note the next time it starts;
- **Stopping the chat takes everything down.** If you stop the parent chat, all of its background tasks end: the running ones are stopped, the waiting ones are cancelled. The child chat keeps everything the subagent managed to produce, plus the stop note; a cancelled waiting task has no child chat at all.

## MCP servers

MiniAgent **connects the MCP servers** enabled in `mcp.yml` itself — no Claude Code command line is needed for it. The same three transport types are supported: local processes (`stdio`), remote servers over `http`, and the legacy `sse`.

Servers connect not at startup but at the first message of a chat. Disabled entries are skipped. If a server did not start or did not answer, the chat keeps working and a warning naming the server goes to the log: one broken server neither drags the others down nor breaks the conversation. In commands, arguments, environment variables, addresses, and headers the entries `$NAME`, `${NAME}`, and `${NAME:-default-value}` are expanded — against the chat variables first, then the environment; an unset variable stays as is with a warning. When the chat stops, the connections are closed and the local server processes are killed, so stopping does not wait for them to exit.

How to set up servers and what lives in `mcp.yml` — on the [MCP Servers](/agents/agent/docs/mcp-servers)
 page.

## Hooks

The rules from `hooks.yml` apply in mini chats too: blocking a tool, checking before its call, actions on conversation events. The same catalog is passed both to the command-line backends and to MiniAgent, so rules do not have to be set up twice.

The list of events, deny rules, and the per-rule time limit — on the [Hooks](/agents/agent/docs/hooks)
 page.

## The profiles dialog in settings

The dialog opens from the **“MiniAgent”** card in the **Configuration** group of the settings hub (the gear in the header) — more about the hub on the [Settings](/agents/agent/docs/settings)
 page. The dialog edits the same `miniagent.yml` a text YAML editor would, but as a form:

- **Profile list** — create, rename, and delete. The name follows the mask `^[a-z0-9][a-z0-9_-]*$`: a lowercase letter or digit, then lowercase letters, digits, hyphens, and underscores — and it doubles as the `mini:name` suffix;
- **Profile editor** — the `loadClaudeMd`/`loadAgentsMd` toggles, tool toggles with an “N of M tools enabled” readout (they edit `disabledTools`), numeric fields with default-value hints, and a system-prompt editor with a preview of the built-in one. Among the numeric fields there is **“Max parallel agents”** — how many subagents of one chat to run at once (4 by default, with the hint “Subagents of one chat running at once; extras queue. Default: 4”); zero or a negative number cannot be saved. The **Reset to default** button clears the prompt text — the built-in one is taken fresh from every application update, never copied;
- **Built-in defaults summary** — shown next to the list;
- **Conflict protection** — every save passes a checksum check (md5): when the file has changed in the meantime (an edit in another client, a text editor, or the Project Settings tab), the server answers `409` and offers to reload the dialog — your edits are never silently overwritten;
- **The same validation as YAML** — saving from the form and editing as text pass the same rules (profile names, mutually exclusive lists, number ranges) and give the same errors; the validator runs as a pseudo-build.

**Settings freeze at session creation**: a live chat works with the profile it was created with, and edits apply to new sessions — switching the profile or the model recreates the session. One more subtlety: when the profile disables the `load_skill` tool, the “Start by loading the … skill” line disappears from the system prompt — demanding a skill load from a tool that does not exist makes no sense. And when the tool does run, the skill arrives whole, whatever its size: the general output cap does not apply to `load_skill` — capping the very call that pulls the skill into the context would defeat it.

## Retry Settings

The provider does not always answer at once: the service is overloaded, there are too many requests, the connection dropped. Instead of ending the turn with an error right away, MiniAgent repeats the request — and often the answer arrives on the retry. How long to wait between attempts and how many attempts to make is up to you: the settings hub has a **Retry** card in the **Configuration** group (the gear in the header). More about the hub on the [Settings](/agents/agent/docs/settings)
 page.

The card opens the **Retry Settings** dialog with two fields:

- **Retry interval** — how many seconds to wait before retrying a failed request, **60 seconds** by default;
- **Max attempts** — how many times the request is sent in total (the first request plus its retries) before the error fails the chat, **10** by default. Only a whole number greater than zero is accepted, otherwise an error appears under the field;

The pause is always the same — it does not grow with every attempt. An empty field means “go back to the default”. The dialog footer shows where the settings file lives — **Config location:** and the path `.xedant/retry.yml`. The **Cancel** and **Save Changes** buttons close or save the dialog, and a successful save confirms with “Retry settings saved”. The file looks like this:

```
retryIntervalSeconds: 60
maxAttempts: 10
```

Only transient failures are retried: an overloaded service, rate limiting, `400`, `429`, and `5xx` responses, dropped connections. A `400` that states a reason is retried too — that route proved unstable. Cases a retry cannot change — exhausted account limits and credits — the chat reports immediately, without waiting out the remaining attempts (at the default values that saves up to nine minutes of waiting).

Every retry is visible: a failed attempt shows in the chat as its own line with a yellow (warning) highlight, naming the model, the attempt number out of the total, the failure cause, and the wait before the next request. The line is not an error — the answer usually arrives on the retry, so the chat gets no “error” label; the message about the error and the **error** label on the chat appear only when the attempts run out (only your new message or a continue clears it). Interrupting the answer during the pause cancels the retry.

Every attempt is paid: the provider processes and charges each request, and the spend of failed attempts is added to the turn’s spend — the chat and the analytics numbers show the real bill. How the provider’s cache softens a retry is described on the [Context Utilization](/agents/agent/docs/context-utilization)
 page.

The same file can be edited as text in the project settings tab and in any editor — a change is picked up while the application runs. If the file is corrupt, the dialog shows the defaults and explains that saving replaces the broken file. If the file was changed elsewhere, the dialog warns: “retry.yml changed outside this dialog. Your edits were not saved.” — with a **Reload** button. Settings apply to new sessions: an active chat finishes with the policy it was created with, and a broken file does not break chats — the defaults keep working. The file is checked at build time as well: unknown keys and a number below one are caught, just like in the other settings files.

## A practical example

**The “safe” profile — bash off, a 60-second call timeout.** Create it in the dialog: **Settings → Configuration → MiniAgent → “New profile”**, name it `safe`, turn the `bash` toggle off, set `toolCallTimeout: 60`, and save. The equivalent file:

```
profiles:
  safe:
    disabledTools:
      - bash
    toolCallTimeout: 60
```

Now assign it to a model: in the model wizard on the [Models](/agents/agent/docs/models)
 page, set the `AGENT_BACKEND=mini:safe` variable (in yml — a line in the `variables:` list). Chats on that model will run without shell commands and cap every tool call at 60 seconds — everything else stays built-in.

## Related pages

- [MCP Servers](/agents/agent/docs/mcp-servers) — external tools and data sources that MiniAgent connects on its own;
- [Hooks](/agents/agent/docs/hooks) — deny and execute rules shared by the command-line backends and mini chats;
- [Settings](/agents/agent/docs/settings) — the MiniAgent card and the settings hub;
- [.xedant Folder](/agents/agent/docs/xedant-folder) — the project configuration files, including the `fetch.yml` and `search.yml` service catalogues;
- [Models](/agents/agent/docs/models) — the `AGENT_BACKEND` variable, choosing a profile by model, and the image-input flag;
- [Skills](/agents/agent/docs/skills) — skills in the chat and the `load_skill` tool.

**← Back:** [Backends](/agents/agent/docs/backends)

**Next:** [Tips & Troubleshooting](/agents/agent/docs/tips)
 →
