Configuration Reference

MiniBot is configured via a config.toml file, most easily created with the interactive wizard (see Getting Started):

minibot configure

To hand-write or inspect the file directly instead, start from the provided example:

cp config.example.toml config.toml

Values follow standard TOML syntax. Byte-size fields accept human-readable strings (e.g. "64KB", "5MB") in addition to raw integers.

Environment variables

Use ${NAME} in any string value to read a variable from MiniBot’s process environment. References work in nested tables and lists, including provider headers and extension configuration:

[providers.openai]
api_key = "${OPENAI_API_KEY}"
base_url = "${API_BASE_URL}/v1"

[providers.openai.headers]
Authorization = "Bearer ${PROXY_TOKEN}"

[runtime]
agent_timeout_seconds = "${AGENT_TIMEOUT_SECONDS}"

[channels.telegram]
enabled = "${TELEGRAM_ENABLED}"
allowed_chat_ids = ["${OWNER_CHAT_ID}"]

Names follow [A-Za-z_][A-Za-z0-9_]*. Multiple references in one value are supported. Write $${NAME} to produce literal ${NAME}. Bare $NAME and unsupported expressions such as ${NAME:-default} remain unchanged. Table names and keys are never expanded.

TOML is parsed before substitution, so quotes, backslashes, and newlines in environment values are inserted verbatim without changing the TOML structure. Both TOML basic and literal strings are expanded. Inserted values are not expanded again. Non-string TOML values stay unchanged; quoted references for numeric, boolean, and byte-size fields use the existing schema’s conversions and validation. Environment values are not parsed as TOML lists or tables.

An unset variable raises an error naming the variable and configuration path, including list indexes, without showing its value. All sections are expanded, including disabled providers and tools. A variable set to an empty string produces "" and follows the setting’s existing validation.

Supply variables to each process that loads configuration: the daemon, console, task workers, and minibot configure. MiniBot does not load .env files or execute shell expressions. Changes to the environment take effect the next time settings are loaded. MINIBOT_CONFIG still selects the configuration file when no explicit path is supplied.

minibot configure retains the original references for unchanged values, including list entries, and uses resolved credentials for model discovery. References entered in credential prompts are saved literally. Loading settings never rewrites the file; literal secrets remain plain text on disk.

For Python callers, expansion occurs in Settings.from_dict() and Settings.from_file() before normalization and validation, without mutating the input dictionary. Direct Settings(...) and Settings.model_validate(...) calls do not expand references.

Vault references

${secret:NAME} resolves to an entry in the encrypted credential vault, so a credential never has to sit in plain text on disk. This matters because config.toml is readable by the bash tool, which has no filesystem jail — the vault file is not.

[providers.openai]
api_key = "${secret:OPENAI_API_KEY}"

[channels.telegram]
bot_token = "${secret:telegram}"

[[tools.mcp.servers]]
name = "linear"
headers = { Authorization = "Bearer ${secret:linear}" }

Names follow [A-Za-z_][A-Za-z0-9_.-]*, matching what the vault document accepts as a key. $${secret:NAME} produces a literal ${secret:NAME}. The resolved value is injected into the in-memory Settings instance only; nothing is written back to the file.

Resolution happens in a second pass, after ${ENV_VAR} expansion and after the vault is unlocked at startup — the vault’s location comes from configuration, so it cannot be known before the first pass. Consequences worth knowing:

  • [vault] settings themselves cannot use ${secret:}; doing so is an error.

  • [vault] enabled must be true wherever a reference appears, or startup fails naming the reference.

  • A configuration with no references never reads the vault for expansion at all.

  • Task workers reload configuration in their own process and receive the vault contents over the in-memory pipe from the daemon, so references resolve there too.

  • minibot configure preserves references rather than resolving them, exactly as it does for ${ENV_VAR}.

${secret:NAME} and the typed [[tools.mcp.servers]] auth_secret field both read the vault and both remain supported; auth_secret is the shorthand for the common Authorization: Bearer case. Setting both on the same server is an error.

This protects the credential at rest. Once resolved, the value lives in the daemon’s memory just as an ${ENV_VAR} one does; see Security & Sandboxing for the full threat model.

Runtime

class minibot.adapters.config.schema.RuntimeConfig(*, log_level='INFO', environment='development', agent_timeout_seconds=120, owner_id='primary')[source]

Top-level runtime settings. TOML section: [runtime]

  • log_level — root log level (default: "INFO").

  • environment — label used in log context (default: "development"). It also drives the built-in HTTP UI: "development" and "debug" make the server send Cache-Control: no-store for dashboard static assets, so a normal reload picks up edits; any other value (for example "production") leaves normal caching on.

  • agent_timeout_seconds — hard wall-clock timeout for any agent turn (min/default: 120).

  • owner_id — the person this MiniBot assists (default: "primary").

MiniBot is a personal assistant for exactly one owner. owner_id is a constant of the deployment: it is never derived from a message, a task payload or any caller-supplied field, and it becomes ToolContext.owner_id for every tool call on every entrypoint. It therefore owns long-term memory, the relation graph, scheduled jobs and the RAG corpus.

Conversations are scoped separately, per channel and chat. One owner, many chat sessions: a private Telegram chat, a group and the console keep independent history while sharing that one owner’s long-term data.

Parameters:
  • log_level (str)

  • environment (str)

  • agent_timeout_seconds (int)

  • owner_id (str)

Channels

class minibot.adapters.config.schema.TelegramChannelConfig(*, enabled=True, bot_token='', allowed_chat_ids=<factory>, allowed_user_ids=<factory>, mode='long_polling', webhook_url=None, require_authorized=True, media_enabled=True, max_photo_bytes=5242880, max_document_bytes=10485760, max_total_media_bytes=12582912, max_attachments_per_message=3, allowed_document_mime_types=<factory>, format_repair_enabled=True, format_repair_max_attempts=1)[source]

Telegram channel settings. TOML section: [channels.telegram]

  • bot_token — BotFather token (required).

  • allowed_chat_ids / allowed_user_ids — access control lists.

  • mode — "long_polling" (default) or "webhook".

  • webhook_url — required when mode = "webhook".

  • require_authorized — reject messages from unlisted IDs (default: true).

  • media_enabled — accept photo/document attachments (default: true).

  • max_photo_bytes / max_document_bytes / max_total_media_bytes — per-message size caps.

  • max_attachments_per_message — attachment count cap (default: 3).

  • allowed_document_mime_types — MIME whitelist; empty means all types are allowed.

  • format_repair_enabled — auto-repair malformed Markdown before sending (default: true).

Parameters:
  • enabled (bool)

  • bot_token (str)

  • allowed_chat_ids (list[int])

  • allowed_user_ids (list[int])

  • mode (str)

  • webhook_url (str | None)

  • require_authorized (bool)

  • media_enabled (bool)

  • max_photo_bytes (Annotated[int, BeforeValidator(func=~minibot.config.schema._coerce_byte_size, json_schema_input_type=PydanticUndefined), FieldInfo(annotation=NoneType, required=True, metadata=[Gt(gt=0)])])

  • max_document_bytes (Annotated[int, BeforeValidator(func=~minibot.config.schema._coerce_byte_size, json_schema_input_type=PydanticUndefined), FieldInfo(annotation=NoneType, required=True, metadata=[Gt(gt=0)])])

  • max_total_media_bytes (Annotated[int, BeforeValidator(func=~minibot.config.schema._coerce_byte_size, json_schema_input_type=PydanticUndefined), FieldInfo(annotation=NoneType, required=True, metadata=[Gt(gt=0)])])

  • max_attachments_per_message (Annotated[int, Gt(gt=0)])

  • allowed_document_mime_types (list[str])

  • format_repair_enabled (bool)

  • format_repair_max_attempts (Annotated[int, Gt(gt=0)])

LLM

class minibot.adapters.config.schema.LLMMConfig(*, provider='openai', api_key='', base_url=None, model='gpt-4o-mini', http2=False, temperature=None, max_new_tokens=None, max_tool_iterations=15, request_timeout_seconds=45, sock_connect_timeout_seconds=10, sock_read_timeout_seconds=45, retry_attempts=3, retry_delay_seconds=2.0, system_prompt='You are Minibot, a helpful assistant.', system_prompt_file='./prompts/main_agent_system.md', prompts_dir='./prompts', reasoning_effort=None, reasoning_summary=None, main_responses_state_mode='full_messages', agent_responses_state_mode='previous_response_id', responses_state_mode='full_messages', prompt_cache_enabled=True, prompt_cache_retention=None, strip_logs=False, extra_headers=<factory>, auth_path=None, openrouter=OpenRouterLLMConfig(attribution_enabled=True, models=[], provider=None, reasoning_enabled=None, plugins=[]), xai=XAILLMConfig(web_search_enabled=False, x_search_enabled=False, web_search=XAIWebSearchConfig(allowed_domains=[], excluded_domains=[], enable_image_understanding=False), x_search=XAIXSearchConfig(allowed_x_handles=[], excluded_x_handles=[], from_date=None, to_date=None, enable_image_understanding=False, enable_video_understanding=False)))[source]

Main LLM settings. TOML section: [llm]

  • provider — provider name: "openai", "anthropic", "openrouter", "xai", etc.

  • api_key — provider API key.

  • base_url — optional base URL (for proxies or OpenAI-compatible local servers).

  • model — model identifier (default: "gpt-4o-mini").

  • temperature — sampling temperature (null uses provider default).

  • max_new_tokens — max tokens to generate per turn.

  • max_tool_iterations — maximum tool-call rounds before forcing a final answer (default: 15).

  • request_timeout_seconds — HTTP timeout per LLM request (min: 45).

  • retry_attempts — extra attempts for a failed HTTP request, and for a main-agent step whose response ends with status failed or has no text and no tool calls (default: 3). Context-length and invalid-prompt failures are not retried.

  • retry_delay_seconds — initial delay between attempts; step retries back off exponentially up to min(4 * retry_delay_seconds, 10) seconds (default: 2.0).

  • system_prompt — inline system prompt (overridden by system_prompt_file).

  • system_prompt_file — path to the main system prompt markdown file.

  • prompts_dir — directory for runtime prompt fragments.

  • reasoning_effort — reasoning budget hint for supported models (e.g. "high").

  • reasoning_summary — request a plaintext reasoning summary from Responses models ("auto"/"concise"/"detailed").

  • main_responses_state_mode — how conversation state is passed for the main agent ("full_messages" or "previous_response_id").

  • prompt_cache_enabled — enable provider-side prompt caching (default: true).

  • strip_logs — shorten selected fields in the provider raw-response debug log (default: false).

  • extra_headers — extra HTTP headers sent on every provider request (usually inherited from [providers.<name>.headers]).

  • auth_path — path to an OAuth credentials file, used by the chatgpt_codex provider (usually inherited from [providers.chatgpt_codex.auth_path]; defaults to ~/.minibot/auth_codex.json).

  • openrouter — OpenRouter-specific routing overrides ([llm.openrouter]).

  • xai — xAI web/X search integration ([llm.xai]).

Parameters:
  • provider (str)

  • api_key (str)

  • base_url (str | None)

  • model (str)

  • http2 (bool)

  • temperature (float | None)

  • max_new_tokens (Annotated[int, Gt(gt=0)] | None)

  • max_tool_iterations (Annotated[int, Gt(gt=0)])

  • request_timeout_seconds (int)

  • sock_connect_timeout_seconds (Annotated[int, Gt(gt=0)])

  • sock_read_timeout_seconds (Annotated[int, Gt(gt=0)])

  • retry_attempts (Annotated[int, Gt(gt=0)])

  • retry_delay_seconds (float)

  • system_prompt (str)

  • system_prompt_file (str | None)

  • prompts_dir (str)

  • reasoning_effort (str | None)

  • reasoning_summary (str | None)

  • main_responses_state_mode (Literal['full_messages', 'previous_response_id'])

  • agent_responses_state_mode (Literal['full_messages', 'previous_response_id'])

  • responses_state_mode (Literal['full_messages', 'previous_response_id'])

  • prompt_cache_enabled (bool)

  • prompt_cache_retention (Literal['in-memory', '24h'] | None)

  • strip_logs (bool)

  • extra_headers (dict[str, str])

  • auth_path (str | None)

  • openrouter (OpenRouterLLMConfig)

  • xai (XAILLMConfig)

Providers

See Providers for setup examples and compatible endpoint guidance.

class minibot.adapters.config.schema.ProviderConfig(*, api_key='', base_url=None, headers=<factory>, auth_path=None, api_format=None, models=<factory>)[source]

Named LLM provider credentials. TOML section: [providers.<name>]

Used to supply API keys and base URLs for secondary providers referenced by agent definitions (model_provider).

  • api_key — provider API key.

  • base_url — optional base URL override (e.g. for proxies or local endpoints).

  • headers — extra HTTP headers sent on every request to this provider. OpenCode Go requires x-opencode-session and rejects requests without it (MissingSessionID).

  • auth_path — used only by [providers.chatgpt_codex]: path to the ChatGPT Codex OAuth credentials file written by minibot codex login. Defaults to ~/.minibot/auth_codex.json when unset.

  • api_format — which API dialect this endpoint speaks, and therefore which client is built: "openai", "openai_responses", "openrouter", "claude", "google" or "chatgpt_codex". Required unless the section name is itself one of those values, which lets several endpoints of the same format coexist: [providers.opencode_go] with api_format = "openai_responses" alongside [providers.zai] with api_format = "openai".

  • models — advisory list of model ids this endpoint serves. Not validated against the endpoint; it is what agents and runtime delegation overrides are offered to choose from.

OpenAI-compatible third-party endpoints (set under [providers.openai] with [llm].provider = "openai", or [providers.openai_responses] with provider = "openai_responses"):

  • OpenCode Zen (pay-as-you-go): base_url = "https://opencode.ai/zen/v1", e.g. model = "kimi-k2.7-code".

  • OpenCode Go (subscription): base_url = "https://opencode.ai/zen/go/v1", e.g. model = "mimo-v2.5". Some models (gpt-5.6-luna, grok-4.6) are only exposed via the Responses variant of that base URL.

  • z.ai GLM Coding Plan: base_url = "https://api.z.ai/api/coding/paas/v4" (Chat Completions, recommended — documented function calling/streaming support) with model = "glm-5.3" or the cheaper "glm-5.3-flash". A Responses-style endpoint also exists at https://api.z.ai/api/v1 but z.ai’s docs don’t confirm parity with OpenAI Responses semantics (previous_response_id, reasoning), so prefer Chat Completions unless you’ve verified it works for your use case.

Parameters:
  • api_key (str)

  • base_url (str | None)

  • headers (dict[str, str])

  • auth_path (str | None)

  • api_format (Literal['openai', 'openai_responses', 'openrouter', 'claude', 'google', 'chatgpt_codex'] | None)

  • models (list[str])

Memory

[memory].notify_compaction_updates accepts "off" (no notices), "brief" (running and done notices), or "full" (notices plus the summary). Existing configurations must replace false with "off" and true with "full"; the old boolean values now fail validation at startup.

class minibot.adapters.config.schema.MemoryConfig(*, backend='sqlite', sqlite_url='sqlite+aiosqlite:///./data/minibot.db', max_history_messages=None, max_history_tokens=None, context_ratio_before_compact=0.95, notify_compaction_updates='off')[source]

Conversation history memory settings. TOML section: [memory]

  • backend — storage backend (currently only "sqlite").

  • sqlite_url — SQLite database URL (default: "sqlite+aiosqlite:///./data/minibot.db").

  • max_history_messages — hard cap on stored messages per conversation (null = unlimited).

  • max_history_tokens — token budget for history sent to the LLM (null = unlimited).

  • context_ratio_before_compact — fraction of context window used before triggering automatic compaction (default: 0.95).

  • notify_compaction_updates — what the chat receives when history is compacted: "off" nothing (default), "brief" only the short “running” and “done” notices, "full" those notices plus the compaction summary.

Parameters:
  • backend (str)

  • sqlite_url (str)

  • max_history_messages (int | None)

  • max_history_tokens (int | None)

  • context_ratio_before_compact (float)

  • notify_compaction_updates (Literal['off', 'brief', 'full'])

Orchestration

[orchestration.specialists].enabled (default true) is the switch for using owner-defined specialist agents. With it off, the roster, fetch_agent_info and named delegation all disappear, while the generic task worker stays available as long as [tasks] is enabled. Specialists run on the task backend, so the default follows [tasks].enabled: with tasks off and this key omitted, the roster is disabled. Setting it to true explicitly while [tasks].enabled = false fails config loading instead of exposing a roster nothing can use.

[orchestration.agent_management] is opt-in and off by default: reload exposes reload_agents for hand-edited files, and write exposes controlled create/update/delete tools for model-authored definitions stored in its own directory, which must not overlap [orchestration].directory.

Model-authored agents are bounded by an owner-configured ceiling, empty by default so a managed agent is granted nothing until the owner lists it. The ceiling itself may use fnmatch patterns (file*), but a managed definition may not: every entry in its tools_allow has to be an exact tool name, because only an exact name can be checked against a pattern without enumerating the tool list. A managed definition may not use tools_deny at all — it grants every tool except the listed ones, so no ceiling can bound it — and it claims MCP servers through mcp_servers rather than through tool names. providers restricts which model provider a managed agent may target, including a spawn_task or delegate model override; the provider the daemon already runs on is always allowed, since reusing it is not an escalation. Owner-authored agents are not subject to the ceiling, so their permissions stay exactly as the owner wrote them.

class minibot.adapters.config.schema.OrchestrationConfig(*, directory='./agents', tool_ownership_mode='shared', shared_mcp_servers=<factory>, main_tool_use_guardrail='disabled', main_agent=MainAgentConfig(name='minibot', tools_allow=[], tools_deny=[]), specialists=<factory>, agent_management=<factory>)[source]

Multi-agent orchestration settings. TOML section: [orchestration]

  • directory — path to agent definition files (default: "./agents").

  • tool_ownership_mode — how tools are shared between agents: "shared" (default), "exclusive", or "exclusive_mcp".

  • shared_mcp_servers — MCP server names whose tools stay visible to the main agent even when a specialist claims them under an exclusive ownership mode (default: empty).

  • main_tool_use_guardrail — optional guardrail before tool execution: "disabled" (default) or "llm_classifier".

  • main_agent — tool allow/deny policy for the main agent ([orchestration.main_agent]).

  • specialists — whether owner-defined specialists are used at all ([orchestration.specialists]).

  • agent_management — optional runtime reload and model-authored definitions ([orchestration.agent_management]).

Parameters:
class minibot.adapters.config.schema.SpecialistsConfig(*, enabled=True)[source]

Specialist agent settings. TOML section: [orchestration.specialists]

  • enabled — use owner-defined specialist agents (default: true). Off drops the roster, fetch_agent_info and named delegation, while the generic task worker stays available whenever [tasks] is enabled. Specialists run on the task backend, so the default follows [tasks].enabled: with tasks off and this key omitted, the roster is disabled. Setting it to true explicitly while [tasks].enabled = false fails config loading rather than exposing a roster nothing can act on.

Parameters:

enabled (bool)

class minibot.adapters.config.schema.AgentManagementConfig(*, reload=False, write=False, directory='./data/agents', tools_allow=<factory>, mcp_servers=<factory>, providers=<factory>)[source]

Runtime agent management. TOML section: [orchestration.agent_management]

  • reload — expose reload_agents so an owner can hand-edit definition files and re-read them (default: false).

  • write — expose controlled create/update/delete tools for model-authored definitions (default: false). A successful write refreshes the registry itself, so this does not require reload.

  • directory — where model-authored definitions live (default: "./data/agents"). Must not overlap [orchestration].directory, so owner- and model-authored files stay distinguishable.

  • tools_allow — fnmatch patterns naming the native tools a managed agent may grant itself (default: empty, which grants none). A managed definition’s own tools_allow must list exact names, and it may not use tools_deny.

  • mcp_servers — MCP server names a managed agent may claim (default: empty). MCP access is claimed here, never through a tool name.

  • providers — providers a managed agent may target, including a spawn_task override (default: empty, meaning the main [llm] provider only, which is always allowed).

Parameters:

Decision

[decision] is opt-in and off by default. When enabled, every main-agent turn also asks a decision model (a <base_url>/decisions endpoint, OpenRouter’s /api/alpha/decisions by default, not /chat/completions) four fixed questions about the user’s message: route (answer directly, use tools, or delegate a task), needs_memory, needs_web and complexity. The request runs in parallel with the real generation and is logged as a turn decision line next to the tools the agent actually used and whether the turn was handed off to a task, so the model’s choices can be compared with reality before anything acts on them. It never changes a reply, adds no latency, and a timeout or any failure is logged and ignored.

It runs as the bundled minibot.extensions.integrations.decision extension, listening to the turn events (see Events), so it is active in the daemon and console but not in the task worker. It is also asked for turns that end before the model is called, such as unsupported media. It is a lossy observer: an event dropped by the event bus means no turn decision line for that turn, and at most 32 turns wait for an answer at once.

The question is asked once the opening message is ready for the model, so a voice note counts by what it says: its automatic transcription is appended to the message text. Only the audio of that message counts; messages sent while the turn runs, audio transcribed later by the transcribe_audio tool, and audio longer than the automatic-transcription limit are left out, and nothing is transcribed just for the decision.

Every turn sends the user’s message text, the automatic transcriptions of its audio, and the names of the main agent’s tools to OpenRouter and the model provider behind it, so enable it only where that is acceptable and check the provider’s data policy for the chosen model.

Keep the key in the vault:

[decision]
enabled = true
model = "~typesafe/jev-latest"
base_url = "https://openrouter.ai/api/alpha"
api_key = "${secret:openrouter_api_key}"

The default ~typesafe/jev-latest bills a small per-request fee. inception/mercury-decide:free is a drop-in alternative at no cost; free model variants may follow a different data policy.

class minibot.adapters.config.schema.DecisionConfig(*, enabled=False, model='~typesafe/jev-latest', base_url='https://openrouter.ai/api/alpha', api_key='', timeout_seconds=3.0)[source]

Optional decision model consulted once per main-agent turn. TOML section: [decision]

  • enabled — consult the decision model on every turn (default: false). Today this only records what the model would have chosen next to what the agent actually did; it never changes a reply.

  • model — an OpenRouter decisions model (default: "~typesafe/jev-latest", billed per request; "inception/mercury-decide:free" also works). Each turn sends the user’s message text and the main agent’s tool names to OpenRouter.

  • base_url — root of a decisions API; requests go to <base_url>/decisions (default: "https://openrouter.ai/api/alpha").

  • api_key — OpenRouter API key, required when enabled. Accepts ${secret:NAME}.

  • timeout_seconds — per-request timeout; a timeout or any failure is logged and the turn goes on untouched (default: 3.0).

Parameters:
  • enabled (bool)

  • model (str)

  • base_url (Annotated[str, AfterValidator(func=~minibot.config.schema._check_http_url)])

  • api_key (str)

  • timeout_seconds (float)

Scheduler

class minibot.adapters.config.schema.ScheduledPromptsConfig(*, enabled=True, sqlite_url='sqlite+aiosqlite:///./data/scheduled_prompts.db', poll_interval_seconds=60, lease_timeout_seconds=120, batch_size=10, max_attempts=3, min_recurrence_interval_seconds=60, pool_size=5, echo=False)[source]

Scheduler persistence and polling settings. TOML section: [scheduler.prompts]

  • enabled — enable the scheduler (default: true).

  • sqlite_url — SQLite database URL for job storage.

  • poll_interval_seconds — how often due jobs are checked (default: 60).

  • lease_timeout_seconds — lease duration before a stalled job is retried (default: 120).

  • batch_size — max jobs processed per poll cycle (default: 10).

  • max_attempts — retries before a job is marked failed (default: 3).

  • min_recurrence_interval_seconds — floor for recurring job intervals (default: 60).

Parameters:

Logging

class minibot.adapters.config.schema.LoggingConfig(*, structured=True, logfmt_enabled=True, log_level='INFO', kv_separator='=', record_separator=' ')[source]

Structured logging settings. TOML section: [logging]

  • structured — enable structured (JSON-like) log output (default: true).

  • logfmt_enabled — use logfmt key=value format instead of JSON (default: true).

  • log_level — log level for the logging subsystem (default: "INFO").

  • kv_separator — separator between key and value in logfmt (default: "=").

  • record_separator — separator between fields in logfmt (default: " ").

Parameters:
  • structured (bool)

  • logfmt_enabled (bool)

  • log_level (str)

  • kv_separator (str)

  • record_separator (str)

Tasks

[tasks].backend selects the queue: "sqlite" (no broker, polled, survives a crash via lease expiry) or "rabbitmq" (needs a broker and the rabbitmq extra, pushed). [tasks.sqlite] configures the first, [rabbitmq] the second.

The default is "sqlite". A config written before that default changed and left backend unset now uses the SQLite queue; set backend = "rabbitmq" explicitly to keep using the broker.

By default a worker starts with no context: it sees only its system prompt, the task prompt and context_json, and the spawn_task and delegate descriptions tell the main agent so. [tasks].history = true gives worker conversations a persistent history instead. It needs backend = "sqlite".

A conversation is a named agent in a chat, or that agent plus a session name the main agent passes to spawn_task or delegate (for example one per client). A general worker only gets a conversation when it is given a session; otherwise it starts empty as before. Every finished task appends its prompt and answer to the conversation, each capped at 8000 characters (failed or timed-out tasks append nothing), and the next task receives it before its own prompt. Tasks of one conversation run one at a time: the queue does not lease a task while another task of the same conversation is leased or running, so a later task waits and then sees the earlier result. Different sessions run in parallel. When the stored history grows past roughly 16 KB and the model’s context limit is known, the worker summarizes it before running and the summary replaces it; when the limit is unknown nothing is summarized and the worker only receives the newest messages that fit in about 32 KB. Tasks without a chat (no chat_id) never get a history. fresh = true on spawn_task or delegate clears the conversation before a task, and the tool description switches to explain all this:

[tasks]
history = true

The history lives in the [memory] database under the session task:<channel>:<chat_id>:<agent_name>[:<session>] (task_worker for the general worker), so it is visible in the web console’s session list.

class minibot.adapters.config.schema.TasksConfig(*, enabled=True, backend='sqlite', worker_timeout_seconds=1800, worker_max_steps='unlimited', worker_max_tool_calls='unlimited', max_concurrent_workers=4, delegation_mode='auto', history=False, worker_extensions=<factory>, sqlite=SqliteTaskQueueConfig(sqlite_url='sqlite+aiosqlite:///./data/tasks.db', poll_interval_seconds=5, lease_timeout_seconds=2100, batch_size=4, max_attempts=3, done_retention_seconds=2592000, pool_size=5, echo=False))[source]

Async task system settings. TOML section: [tasks]

Gates both the task consumer service and the spawn_task/delegate/cancel_task/list_tasks/ get_task tools. spawn_task and delegate are also the only ways to hand work to a specialist agent, so disabling this section turns multi-agent orchestration off entirely.

  • enabled — enable the async task system (default: true; the sqlite backend needs no broker and no extra).

  • backend — queue backend: "sqlite" (default; no broker required) or "rabbitmq" (see [rabbitmq]).

  • worker_timeout_seconds — hard per-task processing timeout (default: 1800).

  • worker_max_steps — optional execution-step ceiling; "unlimited" disables it (default).

  • worker_max_tool_calls — optional tool-call ceiling; "unlimited" disables it (default).

  • max_concurrent_workers — maximum parallel task handlers (default: 4).

  • delegation_mode — which delegation tools the main agent gets. "auto" (default) attaches both: delegate when the model needs the result to keep working (it comes back as a new turn) and spawn_task when the worker’s answer is the final deliverable (it goes straight to the chat). "delegate" attaches only delegate, so every result returns to the main agent as a new turn; past the continuation limit it delivers straight to the chat instead of failing. Replaces the removed continue_turn_mode = "always"; continue_turn_mode and continue_turn_default are rejected.

  • history — keep a persistent history per worker conversation (default: false; needs backend = "sqlite"). A conversation is a named agent in a chat, task:<channel>:<chat_id>:<agent_name>, or that plus a session name passed to spawn_task; general workers only get one when given a session. Each task sees the conversation’s earlier prompts and answers (each capped at 8000 characters), stored in the [memory] database, and tasks of one conversation run one at a time, later ones waiting in the queue. A large history is summarized before the next task when the model’s context limit is known, and spawn_task gains fresh to clear it first. With false every worker starts with no history.

  • worker_extensions — bundled tool extensions a worker loads on top of the scheduler and utility ones (default: []). "kv_memory" adds the [tools.kv_memory] tools, "rag" the [tools.rag] tools and "codemode" the run_tools_script tool ([tools.codemode]), which calls the tools that specialist itself has. Only a specialist that names them in tools_allow gets them (a tools_deny-only specialist gets every tool it does not deny, these included); a spawn_task without an agent never does. Each listed extension needs its [tools.*] section enabled, and must appear once. Storage is prepared on the first call in each worker; RAG also loads its embedding model in every worker that calls it.

  • sqlite — queue storage settings used when backend = "sqlite"; see [tasks.sqlite].

Parameters:
class minibot.adapters.config.schema.SqliteTaskQueueConfig(*, sqlite_url='sqlite+aiosqlite:///./data/tasks.db', poll_interval_seconds=5, lease_timeout_seconds=2100, batch_size=4, max_attempts=3, done_retention_seconds=2592000, pool_size=5, echo=False)[source]

Queue storage settings for tasks.backend = "sqlite". TOML section: [tasks.sqlite]

  • sqlite_url — SQLite database URL for the task queue.

  • poll_interval_seconds — how often the consumer checks for queued tasks (default: 5).

  • lease_timeout_seconds — lease duration before a stalled task is claimable again (default: 2100).

  • batch_size — max tasks leased per poll cycle (default: 4).

  • max_attempts — redeliveries before a task is marked failed (default: 3). This is queue-level redelivery, distinct from the in-process provider rate-limit retry in app/tasks/manager.py.

  • done_retention_seconds — how long terminal task rows and their compact event history are kept before purging (default: 2592000).

Parameters:
class minibot.adapters.config.schema.RabbitMQConsumerConfig(*, broker_url='amqp://guest:guest@localhost:5672/', queue_name='minibot', exchange_name='minibot.tasks', prefetch_count=1)[source]

Broker connection settings for tasks.backend = "rabbitmq". TOML section: [rabbitmq]

Requires the rabbitmq extra: poetry install --extras rabbitmq. Enabling the task system itself lives in [tasks].

  • broker_url — AMQP connection URL (default: "amqp://guest:guest@localhost:5672/").

  • queue_name — queue to consume from (default: "minibot").

  • exchange_name — fanout exchange name (default: "minibot.tasks").

  • prefetch_count — max unacknowledged messages per worker (default: 1).

Parameters:

Vault

An optional encrypted store for credentials, unlocked once at startup. Needs the vault extra (poetry install --extras vault). Secrets are written with minibot vault edit (see CLI Reference) and bound to a destination in configuration — [[tools.mcp.servers]] auth_secret names a vault entry that the MCP client sends as its own Authorization header. The LLM can list secret names and nothing more; there is no tool that reads a value and no secret:// substitution it can write into a tool argument. See Security & Sandboxing for the threat model.

class minibot.adapters.config.schema.VaultConfig(*, enabled=False, path='secrets.vault.yml', password_file='')[source]

Encrypted credential vault. TOML section: [vault]

  • enabled — unlock the vault at startup (default: false).

  • path — the encrypted vault file (default: "secrets.vault.yml"). Write it with minibot vault edit; keep it out of git.

  • password_file — read the unlock password from this file instead of prompting. Supported, but not on equal footing with the interactive prompt: any tool that can read the filesystem can read this file. Same for the MINIBOT_VAULT_PASSWORD environment variable.

Secrets are destination-bound: an admin binds a secret to a consumer in config (for example [[tools.mcp.servers]] auth_secret), and the value is resolved there. The LLM can list secret names and nothing else.

Parameters:

HTTP server

An optional HTTP server running on the daemon’s own event loop. Needs the http extra (poetry install --extras http). It serves /health — open, so a container healthcheck needs no credential — and an authenticated dashboard at / showing the running model, channels, extensions, tools, routes, uptime, and pending turns. Its stylesheet and scripts are served beneath /static, gzip-compressed when the browser accepts it; pages are not compressed, since they carry tokens next to reflected input such as the search query. Conversation history is available at /history and can contain sensitive data. The browser chat at /chat uses the web:1 history session and can contain the same sensitive data. The /history, /memory and /scheduled pages each have a search box and load more entries as you scroll; history search matches message text across every conversation. Extensions can also contribute routes through mb.add_route, or mb.add_page for one with a menu entry (see Writing extensions). All routes except /health require a bearer token or HTTP Basic credentials; one is mandatory unless host is the literal 127.0.0.1 or ::1. When the key-value memory, scheduled prompts, graph and MCP extensions are enabled, their pages are available at /memory, /scheduled, /graph and /mcp. When tasks are enabled, /tasks lists the running tasks (?status=all adds finished ones), shows a task’s prompt, result, error and events, and can cancel a running task. While a reply runs, the chat’s send button becomes a stop button until you type or attach something; stopping works like /stop on Telegram. TLS is out of scope: run it behind a reverse proxy when it is reachable from outside the host. The chat WebSocket authenticates with a per-boot token sent through Sec-WebSocket-Protocol, not a URL query parameter. A TLS-terminating proxy must forward the original X-Forwarded-Proto and X-Forwarded-Host headers so browser origin validation compares against the public origin.

The browser chat can accept image and audio uploads stored temporarily under uploads/temp/web. This requires [tools.file_storage] enabled; audio additionally requires automatic transcription. chat_upload_max_attachments, chat_upload_max_image_bytes, chat_upload_max_audio_bytes and chat_upload_max_total_bytes bound a browser session’s uploads, and chat_upload_retention_hours controls how long completed uploads are kept before cleanup (0 disables it).

class minibot.adapters.config.schema.HTTPServerConfig(*, enabled=False, host='127.0.0.1', port=8080, auth_token='', basic_auth_user='', basic_auth_password='', chat_upload_max_attachments=3, chat_upload_max_image_bytes=5000000, chat_upload_max_audio_bytes=10000000, chat_upload_max_total_bytes=12000000, chat_upload_retention_hours=24)[source]

Built-in HTTP server. TOML section: [http]

  • enabled — serve HTTP alongside the daemon (default: false). Needs the http extra.

  • host / port — where to bind (default: 127.0.0.1:8080); port 0 picks a free one. Only literal 127.0.0.1 and ::1 can run without credentials.

  • auth_token — bearer token required on every route except /health. Accepts ${secret:NAME}.

  • basic_auth_user / basic_auth_password — HTTP Basic credentials, used instead of the bearer token when set (browsers prompt for these natively). Accepts ${secret:NAME}.

  • chat_upload_* — browser-chat media limits and temporary upload retention. Uploads require [tools.file_storage] enabled; audio also requires automatic transcription.

Routes come from core features and from extensions calling mb.add_route or mb.add_page. There is no TLS here: put a reverse proxy in front when this is reachable from outside the host.

Static dashboard assets under /static are served with Cache-Control: no-store when [runtime].environment is "development" or "debug", and with normal caching otherwise. They are gzip-compressed when the browser accepts it; pages are not.

Parameters:
  • enabled (bool)

  • host (str)

  • port (int)

  • auth_token (str)

  • basic_auth_user (str)

  • basic_auth_password (str)

  • chat_upload_max_attachments (Annotated[int, Gt(gt=0)])

  • chat_upload_max_image_bytes (Annotated[int, BeforeValidator(func=~minibot.config.schema._coerce_byte_size, json_schema_input_type=PydanticUndefined), FieldInfo(annotation=NoneType, required=True, metadata=[Gt(gt=0)])])

  • chat_upload_max_audio_bytes (Annotated[int, BeforeValidator(func=~minibot.config.schema._coerce_byte_size, json_schema_input_type=PydanticUndefined), FieldInfo(annotation=NoneType, required=True, metadata=[Gt(gt=0)])])

  • chat_upload_max_total_bytes (Annotated[int, BeforeValidator(func=~minibot.config.schema._coerce_byte_size, json_schema_input_type=PydanticUndefined), FieldInfo(annotation=NoneType, required=True, metadata=[Gt(gt=0)])])

  • chat_upload_retention_hours (Annotated[int, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=0)])])

Extensions

Python extensions loaded at startup. See Writing extensions for the full extension API.

The optional relation graph is a built-in extension. After installing the graph extra, enable minibot.extensions.tools.graph in [extensions].modules. Its optional configuration accepts sqlite_url (default sqlite+aiosqlite:///./data/graph.db) and echo for SQL logging. See Relation graph.

class minibot.adapters.config.schema.ExtensionsConfig(*, modules=<factory>, config=<factory>)[source]

Python extensions loaded at startup. TOML section: [extensions]

  • modules — importable module names, each exposing a register(mb) function. Resolved via normal Python import, so both pip-installed packages and local modules on PYTHONPATH work.

  • config — per-extension settings, keyed by extension name. The extension receives its own slice as mb.config; keys inside are arbitrary.

A module that cannot be imported, has no register, or whose register raises fails startup: a silently missing tool is worse than a crash on boot.

Parameters:

Tool Configuration

Section

Config model

Key options

[tools.approval]

ToolApprovalConfig

require_approval (fnmatch tool-name patterns, default empty), timeout_seconds; Approve/deny buttons in the Telegram or web chat (/chat) that started the call, before a matching call runs, denied on timeout or on channels without buttons, such as the console. In the web chat a pending approval is shown again after a reload or reconnect. A denial skips the remaining tool calls of the same model response, so the model sees it before anything else asks again. The buttons answer only for an authorized user, and only for the user whose request triggered the call when it is known (a scheduled job has no requester, so any authorized user may answer)

[tools.kv_memory]

KeyValueMemoryConfig

enabled, sqlite_url, default_limit, max_limit

[tools.http_client]

HTTPClientToolConfig

enabled, timeout_seconds, max_bytes, max_parse_bytes, response_processing_mode (auto/compact/text/none), max_chars, spillover settings, follow_redirects (default false: a redirect response is returned as-is) and max_redirects (default 5). A chunked response is read only up to the largest of max_bytes, max_parse_bytes and the spill ceiling; the whole request, body included, is bounded to three times timeout_seconds. A response with a Content-Length is still read in full by the HTTP client before the cap applies

[tools.time]

TimeToolConfig

enabled, default_format

[tools.wait]

WaitToolConfig

enabled (default false), max_milliseconds

[tools.calculator]

CalculatorToolConfig

enabled, default_scale, max_expression_length, max_exponent_abs

[tools.python_exec]

PythonExecToolConfig

enabled, python_path, venv_path, sandbox_mode, timeout/output/code limits, artifact settings, environment policy

[tools.python_exec.rlimit]

PythonExecRLimitConfig

enabled, CPU, memory, file-size, process, and open-file limits

[tools.python_exec.cgroup]

PythonExecCgroupConfig

enabled, driver, cpu_quota_percent, memory_max_mb

[tools.python_exec.jail]

PythonExecJailConfig

enabled, command_prefix

[tools.bash]

BashToolConfig

enabled, timeout/output limits, parent environment and allowlist policy. max_output_bytes is enforced while the command runs: output beyond it is read and discarded, never buffered, and a spilled file holds at most that many bytes

[vault]

VaultConfig

enabled, path, password_file; see Vault above

[http]

HTTPServerConfig

enabled, host, port, auth_token, basic_auth_user, basic_auth_password, chat_upload_*; see HTTP server above

[tools.tool_output_spill]

ToolOutputSpillConfig

enabled, spill_after_chars, preview_chars, subdir, exclude_tools; applies to every tool result (not just http_request), except calls made from a codemode script

[tools.apply_patch]

ApplyPatchToolConfig

enabled, restrict_to_workspace, workspace_root, allow_outside_workspace, max_patch_bytes

[tools.file_storage]

FileStorageToolConfig

enabled, root_dir, max_write_bytes, allow_outside_root, upload paths

[tools.grep]

GrepToolConfig

enabled, max_matches, max_file_size_bytes

[tools.browser]

BrowserToolConfig

output_dir for browser/MCP-generated artifacts

[tools.audio_transcription]

AudioTranscriptionToolConfig

enabled, model, device, compute_type, beam_size, VAD and auto-transcription settings, server_url (remote whisper.cpp server)

[tools.mcp]

MCPToolConfig

enabled, name_prefix, timeout_seconds, reload, servers

[[tools.mcp.servers]]

MCPServerConfig

name, transport, stdio command fields, HTTP fields, tool allow/deny filters

[tools.skills]

SkillsToolConfig

enabled, paths, preload_catalog, native, native_disabled, write_path, install

[tools.rag]

RagToolConfig

enabled, backend, sqlite_url/qdrant_url, collection_name, embedding, rerank, chunk/search settings; see RAG & Persistent Knowledge

[tools.codemode]

CodemodeToolConfig

enabled, timeout_seconds (default 60; time spent waiting for a [tools.approval] answer is not counted), max_tool_calls (default 50; the extra call raises a catchable codemode:tool_call_limit error), max_memory_mb, max_output_chars, exclude; needs the codemode extra; see Agent Tools

[tasks]

TasksConfig

enabled, backend, worker_timeout_seconds, worker_max_steps, worker_max_tool_calls, max_concurrent_workers, delegation_mode, history, worker_extensions, sqlite

[tasks.sqlite]

SqliteTaskQueueConfig

sqlite_url, poll_interval_seconds, lease_timeout_seconds, batch_size, max_attempts, done_retention_seconds; terminal rows and compact event history are retained for 30 days by default

Note

Every owner-scoped tool — key/value memory, the relation graph, scheduled jobs and the RAG corpus — is owned by [runtime].owner_id (default "primary"). MiniBot assists exactly one person, so that value is a constant of the deployment and is never derived from a message or a task payload.

Conversation history is scoped separately, per channel and chat. One owner, many chat sessions — a private Telegram chat, a group and the console do not share history, but they do share that owner’s memory, graph and schedules.

Multi-user or multi-tenant isolation is deliberately not supported; it would arrive as an opt-in extension with its own identity model, not by reusing a channel’s sender id.

Tool Config Models

class minibot.adapters.config.schema.KeyValueMemoryConfig(*, enabled=False, sqlite_url='sqlite+aiosqlite:///./data/kv_memory.db', pool_size=5, echo=False, default_limit=20, max_limit=100)[source]

Key/value memory tool settings. TOML section: [tools.kv_memory]

  • enabled — expose the memory_* tools (default: false).

  • sqlite_url — SQLite database URL for stored entries.

  • pool_size / echo — SQLAlchemy engine settings.

  • default_limit / max_limit — page size and hard cap for memory searches.

Entries are owned by [runtime].owner_id, which is shared with every other owner-scoped tool rather than configured here.

Parameters:
class minibot.adapters.config.schema.HTTPClientToolConfig(*, enabled=False, timeout_seconds=10, follow_redirects=False, max_redirects=5, max_bytes=16384, max_parse_bytes=2000000, response_processing_mode='auto', max_chars=None, normalize_whitespace=True, spill_to_managed_file=False, spill_after_chars=16000, spill_preview_chars=2000, max_spill_bytes=5000000, spill_subdir='http_responses/tmp')[source]
Parameters:
  • enabled (bool)

  • timeout_seconds (Annotated[int, Gt(gt=0)])

  • follow_redirects (bool)

  • max_redirects (Annotated[int, Gt(gt=0)])

  • max_bytes (Annotated[int, BeforeValidator(func=~minibot.config.schema._coerce_byte_size, json_schema_input_type=PydanticUndefined), FieldInfo(annotation=NoneType, required=True, metadata=[Gt(gt=0)])])

  • max_parse_bytes (Annotated[int, BeforeValidator(func=~minibot.config.schema._coerce_byte_size, json_schema_input_type=PydanticUndefined), FieldInfo(annotation=NoneType, required=True, metadata=[Gt(gt=0)])])

  • response_processing_mode (Literal['none', 'auto', 'text', 'compact'])

  • max_chars (Annotated[int, Gt(gt=0)] | None)

  • normalize_whitespace (bool)

  • spill_to_managed_file (bool)

  • spill_after_chars (Annotated[int, Gt(gt=0)])

  • spill_preview_chars (Annotated[int, Gt(gt=0)])

  • max_spill_bytes (Annotated[int, BeforeValidator(func=~minibot.config.schema._coerce_byte_size, json_schema_input_type=PydanticUndefined), FieldInfo(annotation=NoneType, required=True, metadata=[Gt(gt=0)])])

  • spill_subdir (str)

class minibot.adapters.config.schema.TimeToolConfig(*, enabled=True, default_format='%Y-%m-%dT%H:%M:%SZ')[source]
Parameters:
  • enabled (bool)

  • default_format (str)

class minibot.adapters.config.schema.WaitToolConfig(*, enabled=False, max_milliseconds=30000)[source]
Parameters:
class minibot.adapters.config.schema.CalculatorToolConfig(*, enabled=True, default_scale=28, max_expression_length=200, max_exponent_abs=1000)[source]
Parameters:
class minibot.adapters.config.schema.PythonExecToolConfig(*, enabled=True, backend='host', python_path=None, venv_path=None, sandbox_mode='basic', default_timeout_seconds=8, max_timeout_seconds=20, max_output_bytes=64000, max_code_bytes=32000, artifacts_enabled=True, artifacts_default_subdir='generated', artifacts_allowed_extensions=<factory>, artifacts_max_files=5, artifacts_max_file_bytes=5000000, artifacts_max_total_bytes=20000000, artifacts_allow_in_jail=False, artifacts_jail_shared_dir=None, pass_parent_env=False, env_allowlist=<factory>, rlimit=PythonExecRLimitConfig(enabled=False, cpu_seconds=2, memory_mb=256, fsize_mb=16, nproc=64, nofile=256), cgroup=PythonExecCgroupConfig(enabled=False, driver='systemd', cpu_quota_percent=100, memory_max_mb=256), jail=PythonExecJailConfig(enabled=False, command_prefix=[]))[source]
Parameters:
  • enabled (bool)

  • backend (Literal['host'])

  • python_path (str | None)

  • venv_path (str | None)

  • sandbox_mode (Literal['none', 'basic', 'rlimit', 'cgroup', 'jail'])

  • default_timeout_seconds (Annotated[int, Gt(gt=0)])

  • max_timeout_seconds (Annotated[int, Gt(gt=0)])

  • max_output_bytes (Annotated[int, BeforeValidator(func=~minibot.config.schema._coerce_byte_size, json_schema_input_type=PydanticUndefined), FieldInfo(annotation=NoneType, required=True, metadata=[Gt(gt=0)])])

  • max_code_bytes (Annotated[int, BeforeValidator(func=~minibot.config.schema._coerce_byte_size, json_schema_input_type=PydanticUndefined), FieldInfo(annotation=NoneType, required=True, metadata=[Gt(gt=0)])])

  • artifacts_enabled (bool)

  • artifacts_default_subdir (str)

  • artifacts_allowed_extensions (list[str])

  • artifacts_max_files (Annotated[int, Gt(gt=0)])

  • artifacts_max_file_bytes (Annotated[int, BeforeValidator(func=~minibot.config.schema._coerce_byte_size, json_schema_input_type=PydanticUndefined), FieldInfo(annotation=NoneType, required=True, metadata=[Gt(gt=0)])])

  • artifacts_max_total_bytes (Annotated[int, BeforeValidator(func=~minibot.config.schema._coerce_byte_size, json_schema_input_type=PydanticUndefined), FieldInfo(annotation=NoneType, required=True, metadata=[Gt(gt=0)])])

  • artifacts_allow_in_jail (bool)

  • artifacts_jail_shared_dir (str | None)

  • pass_parent_env (bool)

  • env_allowlist (list[str])

  • rlimit (PythonExecRLimitConfig)

  • cgroup (PythonExecCgroupConfig)

  • jail (PythonExecJailConfig)

class minibot.adapters.config.schema.PythonExecRLimitConfig(*, enabled=False, cpu_seconds=2, memory_mb=256, fsize_mb=16, nproc=64, nofile=256)[source]
Parameters:
class minibot.adapters.config.schema.PythonExecCgroupConfig(*, enabled=False, driver='systemd', cpu_quota_percent=100, memory_max_mb=256)[source]
Parameters:
class minibot.adapters.config.schema.PythonExecJailConfig(*, enabled=False, command_prefix=<factory>)[source]
Parameters:
class minibot.adapters.config.schema.BashToolConfig(*, enabled=False, default_timeout_seconds=15, max_timeout_seconds=120, max_output_bytes=128000, pass_parent_env=False, env_allowlist=<factory>, spill_to_managed_file=False, spill_after_chars=2000, spill_preview_chars=500, spill_subdir='bash_output/tmp')[source]
Parameters:
  • enabled (bool)

  • default_timeout_seconds (Annotated[int, Gt(gt=0)])

  • max_timeout_seconds (Annotated[int, Gt(gt=0)])

  • max_output_bytes (Annotated[int, BeforeValidator(func=~minibot.config.schema._coerce_byte_size, json_schema_input_type=PydanticUndefined), FieldInfo(annotation=NoneType, required=True, metadata=[Gt(gt=0)])])

  • pass_parent_env (bool)

  • env_allowlist (list[str])

  • spill_to_managed_file (bool)

  • spill_after_chars (Annotated[int, Gt(gt=0)])

  • spill_preview_chars (Annotated[int, Gt(gt=0)])

  • spill_subdir (str)

class minibot.adapters.config.schema.ToolOutputSpillConfig(*, enabled=True, spill_after_chars=8000, preview_chars=800, subdir='tool_output/tmp', exclude_tools=<factory>)[source]

Generic offload of oversized tool results to a managed temp file.

Applies to every tool except those listed in exclude_tools, and only when file storage is enabled and the agent also has a read-back tool available (grep, code_read, read_file or bash). activate_skill spills only past 64,000 characters (or spill_after_chars, if larger), so skill instructions normally arrive inline.

Parameters:
class minibot.adapters.config.schema.ApplyPatchToolConfig(*, enabled=False, restrict_to_workspace=True, workspace_root='.', allow_outside_workspace=False, preserve_trailing_newline=True, max_patch_bytes=262144)[source]
Parameters:
  • enabled (bool)

  • restrict_to_workspace (bool)

  • workspace_root (str)

  • allow_outside_workspace (bool)

  • preserve_trailing_newline (bool)

  • max_patch_bytes (Annotated[int, BeforeValidator(func=~minibot.config.schema._coerce_byte_size, json_schema_input_type=PydanticUndefined), FieldInfo(annotation=NoneType, required=True, metadata=[Gt(gt=0)])])

class minibot.adapters.config.schema.FileStorageToolConfig(*, enabled=False, root_dir='./data/files', max_write_bytes=64000, allow_outside_root=False, save_incoming_uploads=False, uploads_subdir='uploads', incoming_temp_subdir='uploads/temp')[source]
Parameters:
  • enabled (bool)

  • root_dir (str)

  • max_write_bytes (Annotated[int, BeforeValidator(func=~minibot.config.schema._coerce_byte_size, json_schema_input_type=PydanticUndefined), FieldInfo(annotation=NoneType, required=True, metadata=[Gt(gt=0)])])

  • allow_outside_root (bool)

  • save_incoming_uploads (bool)

  • uploads_subdir (str)

  • incoming_temp_subdir (str)

class minibot.adapters.config.schema.GrepToolConfig(*, enabled=False, max_matches=200, max_file_size_bytes=1000000)[source]
Parameters:
  • enabled (bool)

  • max_matches (Annotated[int, Gt(gt=0)])

  • max_file_size_bytes (Annotated[int, BeforeValidator(func=~minibot.config.schema._coerce_byte_size, json_schema_input_type=PydanticUndefined), FieldInfo(annotation=NoneType, required=True, metadata=[Gt(gt=0)])])

class minibot.adapters.config.schema.BrowserToolConfig(*, output_dir='./data/files/browser')[source]
Parameters:

output_dir (str)

class minibot.adapters.config.schema.AudioTranscriptionToolConfig(*, enabled=False, model='small', device='auto', compute_type='int8', beam_size=5, vad_filter=True, auto_transcribe_short_incoming=True, auto_transcribe_max_duration_seconds=45, server_url=None)[source]
Parameters:
  • enabled (bool)

  • model (str)

  • device (Literal['auto', 'cpu', 'cuda'])

  • compute_type (str)

  • beam_size (Annotated[int, Gt(gt=0)])

  • vad_filter (bool)

  • auto_transcribe_short_incoming (bool)

  • auto_transcribe_max_duration_seconds (Annotated[int, Gt(gt=0)])

  • server_url (Annotated[str, AfterValidator(func=~minibot.config.schema._check_http_url)] | None)

class minibot.adapters.config.schema.MCPToolConfig(*, enabled=False, name_prefix='mcp', timeout_seconds=10, reload=False, servers=<factory>)[source]
Parameters:
class minibot.adapters.config.schema.MCPServerConfig(*, name, mode='bridge', transport='stdio', command=None, args=<factory>, env=<factory>, cwd=None, url=None, headers=<factory>, auth_secret=None, enabled_tools=<factory>, disabled_tools=<factory>, catalog_cache_ttl_seconds=60)[source]
Parameters:
class minibot.adapters.config.schema.SkillsToolConfig(*, enabled=True, paths=<factory>, preload_catalog=True, native=True, native_disabled=<factory>, write_path='~/.minibot/skills', install=False)[source]

Skill discovery for the main agent.

preload_catalog embeds skill names and descriptions in the system prompt. Without it the prompt only tells the model to call list_skills, so it cannot tell whether a relevant skill exists — while the specialist roster is in the prompt, which makes delegating look like the obvious route even for work a skill covers.

Skills are discovered from three sources, in precedence order: project (./.minibot/skills and ./.agents/skills, or paths when set), user (the same directory names under $HOME), and native — the skills bundled inside the MiniBot package. Setting paths replaces the project and user lists; native is independent of it, so configuring paths never silently drops the bundled skills.

native_disabled opts out of individual bundled skills by name, and is the only way to switch one off: bundled skills carry no enabled frontmatter, because nobody edits files inside an installed package. A project- or user-level skill of the same name always wins over a bundled one, which is the supported way to override one rather than disable it.

write_path is where the agent creates or installs skills, and is added as the highest-priority discovery path so a skill written at runtime is found without a restart. It defaults to ~/.minibot/skills, so it outranks the project-level ./.minibot/skills.

install attaches the install_skill tool, which downloads skills from GitHub or an archive URL into write_path. It is off by default because an installed skill is third-party instructions the agent will later follow; while it is off, the bundled install-skill skill is hidden as well.

Parameters:
class minibot.adapters.config.schema.RagToolConfig(*, enabled=False, backend='sqlite', sqlite_url='sqlite+aiosqlite:///./data/rag.db', echo=False, qdrant_url='http://localhost:6333', collection_name='minibot_chunks', embedding=RagEmbeddingConfig(model='sentence-transformers/all-MiniLM-L12-v2', dim=384, truncate_dim=None, max_sequence_tokens=128), rerank=RagRerankConfig(enabled=False, model='cross-encoder/ms-marco-MiniLM-L2-v2', candidate_limit=50, max_results=7), chunk_size_tokens=96, chunk_overlap_tokens=20, search_limit=5, truncate_result_tokens=False, max_result_tokens=1500)[source]

Retrieval-augmented generation settings. TOML section: [tools.rag]

  • backend — vector store: "sqlite" (default; no service required) or "qdrant".

  • sqlite_url — SQLite database URL used when backend = "sqlite".

  • qdrant_url — Qdrant HTTP endpoint used when backend = "qdrant".

The SQLite backend scores with an exact scan over the rows left after the scope filters, so it trades throughput at very large corpora for exact recall under filtering; Qdrant keeps an approximate index and is the option to reach for when the corpus outgrows that.

Parameters:
  • enabled (bool)

  • backend (Literal['sqlite', 'qdrant'])

  • sqlite_url (str)

  • echo (bool)

  • qdrant_url (str)

  • collection_name (str)

  • embedding (RagEmbeddingConfig)

  • rerank (RagRerankConfig)

  • chunk_size_tokens (Annotated[int, Gt(gt=0)])

  • chunk_overlap_tokens (int)

  • search_limit (int)

  • truncate_result_tokens (bool)

  • max_result_tokens (Annotated[int, Gt(gt=0)])