English | [日本語](configuration.ja.md)

# Configuration Reference

MAESTRO is configured with a single `config.yaml` (created by copying `config.yaml.example`).

- **YAML keys are snake_case** (`max_concurrency`), camelCase in the code. `transformKeys` in `src/config.ts` converts them.
- Some can be **overridden by environment variables** ([see the end](#environment-variable-overrides)).
- `config_version: 2` is the current schema.

> The primary source for values is `config.yaml.example` (with comments) and `src/config.ts`. This reference summarizes the meaning of each option.

---

## `llm` — LLM connection for job execution

| Key | Default | Meaning |
|------|------|------|
| `timeout_minutes` | 10 | Overall limit per request (minutes). |
| `retry.max_attempts` | 3 | Number of retries on 429/5xx/transient connection failures. |
| `retry.backoff_ms` | [2000,5000,15000] | Wait per retry (ms). |
| `retry.retryable_status` | [429,500,502,503,504] | HTTP statuses eligible for retry. |

### `llm.workers[]` — connection targets used for job execution (required)

| Key | Meaning |
|------|------|
| `id` | Worker identifier. |
| `connection_type` | `direct` (connect directly to an OpenAI-compatible backend such as Ollama/vLLM) / `aao_gateway` (via a separate Gateway, Gateway Key required). |
| `endpoint` | Base URL of the OpenAI-compatible API (e.g. `http://localhost:11434/v1`). |
| `model` | Model name to use (specify explicitly per worker; `default_model` is removed). |
| `api_key` | Virtual key etc. for `aao_gateway` (optional). |
| `roles` | Purpose filter: `auto`/`fast`/`quality`/`title`/`reflection`, etc. `[title]` only = dedicated to title generation. |
| `max_concurrency` | This worker's concurrency. |
| `vlm` | `true` enables image input (ReadImage prefers VLM workers). |
| `enabled` | Enabled/disabled. |

### `llm.metrics` — Prometheus exporter (worker side)

| Key | Default | Meaning |
|------|------|------|
| `enabled` | true | Mounted on `/metrics` (bridge HTTP, default `PORT=9876`). |
| `prefix` | `aao_worker` | Metric name prefix. |
| `bearer_token` | — | When set, Bearer auth is required (the `env:NAME` form is allowed). |
| `allowed_hosts` | localhost only | Permitted source IPs. In production, always set a bearer or allowlist. |

---

## `gateway` — LLM Gateway server (optional)

Exposes MAESTRO itself as an OpenAI-compatible LLM Gateway (with virtual keys, budgets, and metrics, for sharing across multiple GPUs/teams). **Note that its env vars and connection type use the historical `AAO_*` / `aao_gateway` prefix (AAO = the old name of this Gateway feature).** For details, see [aao-gateway-overview.md](aao-gateway-overview.md).

| Key | Default | Meaning |
|------|------|------|
| `enabled` | false | true starts the gateway in the same process (supports hot reload). |
| `listen_port` | 4000 | Only for separate-deploy. |
| `request_timeout_sec` | 600 | Per whole request (including streaming). |
| `upstream_timeout_sec` | 30 | TTFB limit per upstream. |
| `shutdown_graceful_sec` | 30 | SSE drain limit after SIGTERM. |
| `backends[]` | — | `id`/`endpoint`/`model`/`max_slots`/`api_key`. Routing by exact model match. |
| `virtual_keys[]` | — | For bootstrap/backup (`key`/`team`/`allowed_models`/`tokens_budget`/`rate_limit_rpm`). Issuing new ones via the admin API is recommended. |
| `metrics` | enabled | `prefix: aao_gateway`, team/key_prefix/backend labels. Run with auth required. |

Issue and rotate Virtual Keys via the admin REST API (`POST /api/admin/gateway/keys`) or the UI (Settings → LLM → Gateway Server).

---

## `storage` — paths and capacity

| Key | Default | Meaning |
|------|------|------|
| `worktree_dir` | ./data/workspaces | Base for job working directories. |
| `custom_pieces_dir` | — | A Piece dir read in addition to the in-repo `pieces/` (optional). |
| `user_folder_root` | ./data/users | Stores AGENTS.md/scripts/notes etc. under `{root}/{userId}/`. |
| `task_upload_max_size_mb` | 50 | Upper limit for task/comment body (including base64; range 1–1000). |
| `trash_retention_days` | 30 | Auto-sweep of `trash/`. 0 deletes everything each time. |

---

## Execution — concurrency, limits, retry

| Key | Default | Meaning |
|------|------|------|
| `concurrency` | 4 | Max concurrent jobs across all workers (env `CONCURRENCY`). |
| `max_movements` | 200 | Max movements within one job (loop prevention). |
| `retry.max_attempts` | 3 | Max retries when a job fails. |
| `retry.backoff_seconds` | [60,300,900] | Wait seconds between each attempt. |
| `ask.max_per_job` | 2 | ASK (user question) limit per job. |
| `subtasks.max_depth` | 2 | Max nesting depth of SpawnSubTask. |
| `subtasks.max_per_parent` | 10 | Max subtasks one job can spawn. |

---

## `context` — LLM context management

| Key | Default | Meaning |
|------|------|------|
| `limit_tokens` | auto-fetched→128000 | Context limit. When omitted, auto-fetched from the provider API. |
| `thresholds[]` | 0.7=warn / 0.85=prompt / 0.95=force_transition | Action per usage-ratio threshold. |

---

## `safety` — runaway prevention and Bash sandbox

| Key | Default | Meaning |
|------|------|------|
| `max_iterations` | 200 | Max iterations within one movement. |
| `max_revisits` | 3 | Max revisits to the same movement. Exceeding it triggers ABORT. |
| `prompt_guard_ratio` | 0.8 | Up to what % of the context limit the prompt is allowed to use (0.5–0.95). |
| `history_summarization.enabled` | true | Replace old turns with a structured summary to hang on longer. |
| `history_summarization.tail_turns` | 2 | How many trailing turns to protect. |
| `history_summarization.preserve_recent_budget` | 8000 | Max tokens for tail protection. |
| `bash_unrestricted` | false | true removes Bash's command allowlist (**the sandbox mechanism is controlled separately by `bash_sandbox`**). |
| `bash_sandbox` | auto | Bash isolation mechanism: `auto` (use bwrap if present, otherwise hardened-whitelist) / `always` (force bwrap; fail to start if absent, recommended for production) / `off` (do not use bwrap; env scrubbing is kept). Details: [operations/bash-sandbox-provisioning.md](operations/bash-sandbox-provisioning.md). |

---

## `search_filter` — preventing sensitive-info leakage in WebSearch

| Key | Default | Meaning |
|------|------|------|
| `blocked_patterns[]` | — | Patterns removed from the search query by exact match. |
| `auto_block.private_ip` | true | Automatically block 10/172.16-31/192.168/127.*. |
| `auto_block.internal_domain` | true | `.local`/`.internal`/`.lan`/`.intranet`/`.corp`/`.home`. |
| `auto_block.email` / `phone` | true | Email/phone number. |

---

## `browser` — BrowseWeb runtime

| Key | Default | Meaning |
|------|------|------|
| `page_timeout` | 60000 | Page navigation timeout (ms). |
| `action_timeout` | 30000 | Action timeout (ms). |
| `captcha_solve` | skip | `skip` / `novnc` (manual CAPTCHA solving). |
| `max_captcha_pages` | 5 | CAPTCHA page limit. |
| `channel` | chromium | `chromium`/`chrome`/`msedge`. |
| `executable_path` | — | Browser executable (mutually exclusive with channel). |

---

## `tools` — tool settings

In the UI these are split into Web & Search / Browser / Media & Documents / External Services / Legacy Knowledge, but in YAML they are a single `tools` block. Main items:

**Web & Search**: `searxng_url` (WebSearch fallback target), `webfetch_timeout` (sec), `websearch_timeout`, `webfetch_allowed_hosts[]` (SSRF exceptions: when allowing private IP/.local).

**Media & Documents**: `vision_model`/`vision_base_url`/`vision_timeout`/`vision_max_tokens` (VLM for ReadImage), `ocr_model`, `office_{excel,docx,pdf}_max_size_mb` (default 10), `office_pptx_max_size_mb` (50), `office_pptx_max_uncompressed_mb` (200, zip-bomb detection), `speech_server_url`/`speech_timeout`/`speech_language`.

**External Services**: `x_*` (Twitter/X CLI integration: `x_cli_command`/`x_auth_token`/`x_ct0`/`x_proxy`/`x_download_*` etc.), `google_maps_api_key`/`maps_timeout` (Nominatim/OSRM when unset), `amazon_affiliate_tag`/`keepa_api_key`.

**User scripts**: `user_scripts_enabled` (RunUserScript; the plain runtime is sandboxed with Node `--permission`), `user_scripts_allow_userids[]`.

**Legacy Knowledge**: `knowledge_service_url` (knowledge tools disabled when unset), `knowledge_namespaces` (per-namespace api_key). For new namespaces, using MCP is recommended.

---

## `notes` — Shared Knowledge Notes injection

Injects notes from `data/users/{userId}/notes/` into the system prompt. `inject.per_note_max_kb` (4 recommended for Japanese), `inject.total_max_kb`, `inject.over_budget_strategy` (`truncate_last`/`skip_remaining`/`degrade_to_search`).

---

## `auth` — authentication (optional)

Runs without authentication when unset.

| Key | Meaning |
|------|------|
| `session_secret` | Session signing key (a random string). |
| `session_max_age` | Session lifetime (ms, default 86400000=24h). |
| `secure_cookie` | true in HTTPS environments. |
| `admin_emails[]` | Emails granted the admin role. |
| `primary_provider` | `google` / `gitea` (specify explicitly when both are enabled). |
| `providers.google` | `client_id`/`client_secret`/`callback_url`. |
| `providers.gitea` | `client_id`/`client_secret`/`base_url`/`callback_url`. Fetches Gitea orgs at login and uses them for visibility. |

---

## `branding` (optional)

`app_name`/`primary_color`/`login_page_title`/`logo_url`/`favicon_url`/`footer_text`. Editable via GUI at Settings → System → Branding (admin). `config.yaml` and `data/branding/` are gitignored.

---

## `secrets`

`master_key_path` (default `./data/secrets/master.key`, 32 bytes, auto-generated on first launch with mode 0600). Used to encrypt SSH keys, MCP tokens, etc.

---

## `reflection` — learning (OFF by default)

When ON, the LLM automatically updates user memory after each job completes (snapshots are revertible). `enabled`, `max_memory_changes_per_job` (3), `piece_edit_cooldown_hours` (24), `snapshot_retention_days` (90), `per_user_daily_budget_tokens` (200000).

---

## `mcp` — Model Context Protocol

Servers are managed in the admin UI (global) / per user (self-hosted). **The `MCP_ENCRYPTION_KEY` env (64 hex) is required.** `call_timeout_seconds` (60), `max_binary_size_mb` (20), `max_output_files_per_job` (10), `max_output_size_mb_per_job` (200), `tool_cache_ttl_seconds` (600), `oauth_pending_ttl_minutes` (10), `allow_private_addresses` (for MCP servers on a private network, default false).

---

## `ssh` — SSH tool (OFF by default)

`enabled`, `allow_private_addresses` (global default; admins can grant per-connection), `call_timeout_seconds` (30), `max_output_bytes` (32768), `max_{upload,download}_size_mb` (100), `audit_retention_days` (90), `admin_bypasses_grants` (true), abuse detection (`abuse_window_minutes`/`abuse_failure_threshold`/`abuse_lock_minutes`).

**Interactive Console** (`ssh.console`): `enabled`, `idle_timeout_seconds` (1800), `max_session_duration_seconds` (14400), `scrollback_bytes` (524288), `max_sessions_per_connection` (3), and others. For the procedure, see [ssh.md](ssh.md).

---

## `notifications.push` — Web Push (V2, optional)

HTTPS hosting required (iOS requires a PWA install). `enabled`, `vapid_subject` (RFC 8292), `vapid_current_path` (auto-generated, mode 0600), `vapid_history_dir`, `payload_max_bytes` (3072, max 4096), `queue_concurrency` (8), `per_send_timeout_ms` (10000). Key rotation: `npm run vapid-rotate`.

---

## Environment variable overrides

Some settings can be overridden by environment variables:

| Environment variable | Overrides |
|----------|------------|
| `OLLAMA_BASE_URL` | LLM endpoint |
| `OLLAMA_MODEL` | Model name |
| `WORKTREE_DIR` | `storage.worktree_dir` |
| `CONCURRENCY` | `concurrency` |
| `DB_PATH` | SQLite DB path |
| `PORT` | bridge HTTP port (default 9876) |
| `LOG_LEVEL` | `debug`/`info`/`warn`/`error` (default info) |
| `MCP_ENCRYPTION_KEY` | Encryption key for MCP/SSH secrets (required when using MCP) |
