# MAESTRO 設定ファイル (v2 layout) # # このファイルを config.yaml にコピーして編集してください: # cp config.yaml.example config.yaml # # ─── v2 への移行 (v1 → v2) ───────────────────────────────────── # 旧構造 (provider.* / 平置きの worktree_dir 等) は 1 リリース分だけ # 読み取り互換が残っています。手元の config.yaml が旧形式の場合は: # # scripts/migrate-config.sh --dry-run # 変換後を確認 # scripts/migrate-config.sh # in-place で書き換え (.bak を自動保存) # # v3.0 で v1 形式は起動 fatal になる予定です。 # v2 schema バージョン (必須)。 # - 2 : このリリースの正規形 (= 本ファイル) # - 1 / 未指定 : v1 互換読み取り + 起動 warning # - その他 : 起動 fatal (typo / 未来形式の混入防止) config_version: 2 # ─── LLM ───────────────────────────────────────────────────── # ジョブ実行時に LLM 呼び出し先として使う接続群と、retry / timeout / metrics。 llm: timeout_minutes: 10 # アイドルタイムアウト (分)。チャンク受信ごとにリセットされる。default 10 # max_stream_minutes: 20 # 1 LLM 呼び出しの総時間ハードキャップ (分)。timeout_minutes と違い # チャンクが届いてもリセットしない。停止トークンを出さずにトークンを # 吐き続ける暴走 (反復生成など) を確実に打ち切る。未指定なら # timeout_minutes の2倍。0 で無効 (非推奨: 暴走時に中断するまでハングする) # max_thinking_chars: 100000 # 1 LLM 呼び出しで受け取る思考 (reasoning) の文字数の上限。上限を超えた時点で # 本文もツール呼び出しも 1 つも来ていなければ、思考の中で堂々巡りしていると # 見なしてストリームを打ち切り、会話の末尾に短い問いかけを 1 件足して送り直す。 # 送り直しは retry.max_attempts を 1 消費し、使い切ったらエラーで中断する。 # 未指定なら 100000。0 で無効 # retry — LLM 1 呼び出しあたりの投げ直し。**既定値のまま使うならこのブロックごと # コメントアウトしたままにしておくこと。**ここに書いた値は既定値の変更より優先 # されるので、書き写しただけで将来の改善が届かなくなる (issue #1160)。 # # 既定 (未指定時): max_attempts 10 / backoff_ms [500, 500, 1000, 2000, 3000, # 5000, 7000, 10000, 10000] / retryable_status [429, 500, 502, 503, 504] # # backoff_ms は「投げ直す直前に待つ ms」を先頭から順に使い、足りなければ最後の値を # 使い回す。max_attempts が 10 なら待つのは 9 回。合計 39 秒。 # # 429 (混雑) だけは別扱い。応答に Retry-After があればその値を待ち、60 秒を超える # 指定なら投げ直しをやめる。指定が無い 429 は 5 秒を下回らない。5xx と接続失敗は # 並びの値をそのまま使う。 # # retry: # max_attempts: 10 # backoff_ms: [500, 500, 1000, 2000, 3000, 5000, 7000, 10000, 10000] # retryable_status: [429, 500, 502, 503, 504] # workers[] — この AAO がジョブ実行時に呼ぶ接続先。 # # connection_type: # direct — Ollama / llama.cpp / vLLM 等の OpenAI 互換 backend に直接接続 # 生存確認は /slots → /health。**api_key は送らない** # (自前サーバーのアクセスログに平文で残るのを避けるため) # aao_gateway — 別 AAO Gateway 経由で接続 (Gateway Key 必須) # 生存確認は /health。api_key を送る # external_api — 事業者が運用する外部の OpenAI 互換サービス (api_key 必須) # 生存確認は /v1/models。api_key を送る # # 種別は自動判定しない。鍵を送るか送らないかの判断なので、必ず明示すること。 # 未指定は direct 扱い (=鍵を送らない側) で、従来の挙動と同じ。 # # トップレベル `gateway.*` (この AAO 自身が gateway として動く設定) と # 単語衝突を避けるため、worker 側は `aao_gateway` と prefix 付き。 # # model はワーカーごとに明示。`default_model` は廃止された。 # roles: 用途別 (auto / fast / quality / dictionary / document_question / # title / reflection 等) のフィルタ。 # max_concurrency: 1ワーカーが同時実行するジョブ数 (A1スロット方式)。デフォルト1。 # >1 はオプトイン。注意: shutdown drain は粗く、fairness は低下し、 # LLM provider 側の rate limit は別途。browser を使うワーカーで >1 にする場合は # セッション作成は mutex 済みだが本番投入前に dogfooding すること。 # capabilities はモデルが扱える種類。image はその会話に画像を渡せるかを指定。 # audio / video は対応情報の保存用(直接入力・委譲・動画ツールは未対応)。 # 古い vlm は capabilities.image として読み続ける。両方あると新しい指定を優先。 # 画像を扱えないワーカーの画像認識を、capabilities.image: true のワーカーへ回す。 # 空き枠のある候補を選び、1回きりの説明文を受け取る。画像自体は元の会話に載せない。 # offload: # image: false # audio: false # video: false workers: - id: local-ollama connection_type: direct endpoint: http://localhost:11434/v1 model: qwen3:32b roles: [auto, fast, quality] max_concurrency: 1 enabled: true capabilities: image: false audio: false video: false streaming: true # 例: Markdown の辞書モード専用ワーカー。短い回答の速度を優先する。 # dictionary が未設定または利用できない場合は、必要条件を満たす # fast → title の順で自動的に代替する。辞書回答には endpoint、model、 # streaming 対応が必要(未指定の既存設定は許容、明示 false は不可。 # tool calling、tokenizer は不要)。 # - id: dictionary-fast # connection_type: direct # endpoint: http://localhost:11434/v1 # model: qwen3:8b # roles: [dictionary] # max_concurrency: 4 # enabled: true # capabilities: # streaming: true # 例: Markdown の「文書について質問」専用ワーカー。 # streaming と tool_calling の両方に対応するモデルを割り当てる。 # context_window は 8192 以上にし、実際のモデル上限と一致させる。 # - id: document-question # connection_type: direct # endpoint: http://localhost:8080/v1 # model: document-chat-model # roles: [document_question] # max_concurrency: 2 # enabled: true # capabilities: # streaming: true # tool_calling: true # context_window: 32768 # tokenizer_endpoint: http://localhost:8080/tokenize # # tokenizer_api_key: ${DOCUMENT_TOKENIZER_API_KEY} # # 上の例は `llama-server --port 8080 --alias document-chat-model ...` と対応する。 # document_question が未設定または利用できない場合は、以下の必要条件を # すべて満たす quality → auto → fast の順で自動的に代替する。 # 互換ワーカーがない場合は、Settings と質問パネルに不足設定が表示される。 # tokenizer_endpoint は POST `{ "content": "...", "add_special": false }` を受け、 # `{ "tokens": [...] }` を返す llama.cpp server の API。Ollama の `/tokenize` ではない。 # 回答と異なる数え方を避けるため、回答モデルと同じ tokenizer/model を使う。 # HTTPS endpoint は常に利用できる。HTTP は loopback、または回答 worker の # endpoint と同じ hostname なら利用でき、ポートは異なっていてもよい。 # 認証が必要な場合は tokenizer_api_key に専用キーを設定する。このキーだけが # tokenizer へ送られ、未指定でも LLM 用 api_key は代用・転送されない。 # 例: 別 AAO Gateway 越しに共有 GPU プールを使う # - id: team-gateway # connection_type: aao_gateway # endpoint: http://gateway.example.com:9876/v1 # api_key: ${TEAM_AAO_GATEWAY_KEY} # gateway 発行の sk-aao-*** virtual key # model: qwen3:32b # roles: [quality] # max_concurrency: 2 # enabled: true # 例: 事業者が運用する外部の OpenAI 互換サービスを使う # api_key は必須。生存確認 (/v1/models) と実行時の呼び出しの両方で送られる。 # - id: external-llm # connection_type: external_api # endpoint: https://api.example.com/v1 # api_key: ${EXTERNAL_LLM_API_KEY} # model: <サービスが公開しているモデル名> # roles: [quality] # max_concurrency: 4 # enabled: true # 例: タイトル生成用ワーカー (chat ジョブは受け付けない)。 # 注意: タスク作成時にタイトル用 LLM はもう呼ばれない (実行中にエージェントが # Mission Brief の goal からタイトルを派生する)。このワーカーは # 「AIでタイトルを再生成」ボタン (POST /api/local/tasks/:id/regenerate-title) # のオンデマンド生成にのみ使われる。未設定なら先頭ワーカーが代替する。 # - id: title-worker # connection_type: direct # endpoint: http://localhost:11434/v1 # model: qwen3:8b # roles: [title] # max_concurrency: 4 # enabled: true # 例: Reflection 専用ワーカー (cheap モデルで memory 更新を回す) # - id: reflector # connection_type: direct # endpoint: http://localhost:11434/v1 # model: qwen3:8b # roles: [reflection] # max_concurrency: 1 # enabled: true # 例: extra_body / reasoning_efforts / reasoning_effort_mode # (vLLM で reasoning effort を渡す)。 # # extra_body: OpenAI 互換リクエストボディへそのまま浅くマージされる任意 JSON。 # model / messages / stream / stream_options / tools / tool_choice / # temperature は予約キーとしてクライアント側で無視される。 # ここに API キー等の秘密情報を書かないこと — /api/config はこの値を # マスクしない (config.yaml に平文で残る)。 # reasoning_efforts: このワーカーが対応する effort の宣言リスト (後続フェーズで # ジョブ単位の effort 指定に使われる)。 # reasoning_effort_mode: effort をリクエストボディへ注入する形。 # body (既定) = トップレベル reasoning_effort。vLLM 向け。 # chat_template_kwargs = chat_template_kwargs.reasoning_effort。 # llama-server (llama.cpp) 向け — llama-server はトップレベルの # reasoning_effort を黙って無視するため、llama-server を使う場合は # chat_template_kwargs を明示すること。 # reasoning_replay: 返ってきた思考を、会話に残る assistant 発話の `reasoning` 欄に # 載せ直して以後の呼び出しにも見せる (既定 false)。 # 注意 1: 入にした直後の 1 回だけ、進行中の会話の prefix cache が落ちる。 # 注意 2: 思考が履歴に積み上がるので、呼び出しごとの入力量が増える。 # 欄名が `reasoning` なのは、vLLM v0.16〜v0.21 が入力側の # `reasoning_content` を黙って捨てるため。 # false のワーカーが思考入りの会話を継続で拾ったときは、そのまま送る # (剥がすと接頭辞が変わってキャッシュが落ちる)。 # - id: vllm-reasoning # connection_type: direct # endpoint: http://localhost:8000/v1 # model: deepseek-r1 # roles: [quality] # max_concurrency: 1 # enabled: true # extra_body: # reasoning_effort: max # reasoning_efforts: [low, medium, high, max] # reasoning_effort_mode: body # reasoning_replay: false # 例: backend_metrics — バックエンドの Prometheus /metrics の在りか (issue #1104)。 # # ノードの速さ (prefill / decode) と prefix cache・KV cache の状態は、 # バックエンドの /metrics を 2 回読んで累積カウンターの差分から出す。 # 直結ワーカーは endpoint の隣 (/metrics) を既定で読むので、 # 通常この欄は要らない。書くのは次の 2 つの場合: # # 1. ゲートウェイ (connection_type: aao_gateway / proxy: true) 経由。 # ゲートウェイの /health は上流の /metrics を中継しないので、 # 実機の URL を node_id (ゲートウェイが名乗るデプロイ名) に紐づける。 # 2. 直結でも /metrics が既定の場所に無いとき。 # # ここに書かなかったノードは未計測のまま表示される (0 とは区別される)。 # # 資格情報の欄は無い。この URL へ Authorization を送ることは一切しない # ——ワーカーの api_key はゲートウェイの認証面に向けて発行されたもので、 # 実機へ横流しすると上流のアクセスログに平文で残る。認証が必要な # /metrics は対象外とし、到達制御はネットワーク側で行うこと。 # # vLLM 側に必要な起動オプション: # --enable-prefix-caching prefix cache のカウンターを出す # --enable-prompt-tokens-details 1 コールごとの再利用トークン数を返す # --enable-per-request-metrics 1 コールごとの TTFT / 生成時間 / 間隔を返す (任意) # per-request metrics は高並行時に CPU を食う可能性があるので、必要なときだけ。 # # - id: pool # connection_type: aao_gateway # endpoint: http://litellm:4000/v1 # model: qwen3-32b # roles: [task] # max_concurrency: 4 # enabled: true # backend_metrics: # - node_id: vllm-a # url: http://10.0.0.5:8000/metrics # - node_id: vllm-b # url: http://10.0.0.6:8000/metrics # Prometheus exporter (worker side). default で enabled。 # /metrics が bridge HTTP server (PORT, default 9876) に mount される。 # access control: default では localhost (127.0.0.1 / ::1) のみ通る。 # 本番では (a) bearer_token を設定するか、(b) allowed_hosts で前段 IP を許可。 # env: AAO_WORKER_METRICS_BEARER_TOKEN / AAO_WORKER_METRICS_ALLOWED_HOSTS (CSV) でも上書き可。 metrics: enabled: true prefix: aao_worker # /^[a-z][a-z0-9_]*$/ # bearer_token: env:AAO_WORKER_METRICS_BEARER_TOKEN # allowed_hosts: # - 127.0.0.1 # - ::1 # - localhost # # - 0.0.0.0 # 全許可。前段で firewall を必ず使う運用前提 # ─── Markdown 文書質問チャット ─────────────────────────────── # 上の workers[] から document_question 専用ワーカーを優先する。 # 専用ワーカーが利用できなければ、全要件を満たす quality → auto → fast の順で # 自動的に代替する。context_window は 8192 以上、output_tokens は 2048 以上が必要。 document_chat: role: document_question output_tokens: 2048 max_concurrent_per_user: 1 max_concurrent_total: 4 # ─── 辞書モード ────────────────────────────────────────────── # Markdown プレビューで単語を選んだときの回答設定 (#998)。 # 単語の意味を出すだけの軽い用途なので、推論強度の既定は low。 # off にすると何も指定せず、接続先の既定に任せる。 # 実際に送られるのは、そのワーカーが reasoning_efforts で対応を宣言している # 値だけ。宣言に無い値は送らない(受け付けない接続先で拒否されるため)。 dictionary: reasoning_effort: low # off / low / medium / high など # ─── AAO Gateway Server ────────────────────────────────────── # この AAO 自身を OpenAI 互換 LLM Gateway として公開する設定。 # 有効化すると `/v1/chat/completions` などが同 process で立ち上がる。 # # Virtual Keys (sk-aao-*** 形式) は **admin REST API での発行を推奨**: # POST /api/admin/gateway/keys # config.yaml の virtual_keys[] は bootstrap / backup 用途のみで、 # DB に自動 import される (source='config-import')。rotation は admin API 経由でのみ。 # # 同 process / separate process の deploy 方法は docs/aao-gateway-overview.md を参照。 # UI からは Settings → LLM → Gateway Server で全て編集可能。 # gateway: # enabled: false # true で同 process gateway が即時起動 # # (ConfigManager hot reload 対応、再起動不要) # listen_port: 4000 # separate-deploy 時のみ有効 (default LiteLLM 互換) # request_timeout_sec: 600 # 1 リクエスト全体 (streaming 込み) # upstream_timeout_sec: 30 # 各 upstream fetch の TTFB 上限 # shutdown_graceful_sec: 30 # SIGTERM 後、in-flight SSE の drain 上限秒 # # # この AAO 自身が自分の gateway を db virtual key で叩く構成のときだけ指定。 # # ここに挙げた team の下流リクエストは「使用量」ダッシュボードの時間粒度集計 # # (source=gateway_downstream) に二重計上しない (自分の分は source=gateway で # # 既に記録済み)。判定は認証済み team で行うのでクライアントからは偽装不可。 # # internal_teams: [orchestrator] # # backends: # # role ベース routing: worker はジョブの role (auto/fast/quality/reflection) # # を routing key として送り、Gateway はその role を担う最も空いている # # backend に振る。異なる model 名の GPU でも同じ role でまとめられる。 # # roles 未指定の backend は全 role を担当 (アップグレード後も従来どおり動く)。 # - id: gpu-a # `x-aao-backend-id` に出る ID # endpoint: http://gpu-a:11434/v1 # model: qwen3:32b # backend が積むモデル (role が無い時の fallback 一致キー) # roles: [quality] # この backend は quality ティア専用 # max_slots: 2 # llama-server -np と合わせる # api_key: ${GPU_A_API_KEY} # backend が bearer 必須な場合のみ # - id: gpu-b # endpoint: http://gpu-b:11434/v1 # model: qwen3:8b # 別 GPU は別モデルでも OK # roles: [fast, auto] # fast/auto ティアを担当 # max_slots: 2 # # # Bootstrap / Backup 専用 virtual_keys (新規発行は admin API 経由を推奨)。 # # virtual_keys: # # - key: ${TEAM_ALPHA_KEY} # 起動時に DB へ idempotent import # # team: alpha # # allowed_models: [qwen3:32b] # # # tokens_budget: 1000000 # 月次 token 上限 (UTC 月初に reset) # # # rate_limit_rpm: 60 # 1 分あたり最大リクエスト数 # # # Prometheus exporter (gateway side)。default enabled。 # # team / key_prefix / backend ラベルが出るので auth 必須運用 (default localhost のみ)。 # # env: AAO_GATEWAY_METRICS_BEARER_TOKEN / AAO_GATEWAY_METRICS_ALLOWED_HOSTS (CSV) で上書き可。 # # metrics: # # enabled: true # # prefix: aao_gateway # # bearer_token: env:AAO_GATEWAY_METRICS_BEARER_TOKEN # # allowed_hosts: # # - 127.0.0.1 # # - ::1 # # # - 0.0.0.0 # 前段 firewall 必須 # ─── Storage / Paths ───────────────────────────────────────── # 旧 worktree_dir / custom_pieces_dir / user_folder_root / # tools.task_upload_max_size_mb / tools.trash_retention_days # は normalizer により storage.* に集約された。 storage: worktree_dir: ./data/workspaces # ジョブ実行時の作業ディレクトリのベース # custom_pieces_dir: ./custom-pieces # リポジトリ内の pieces/ に加えて読みに行く Piece dir (任意) user_folder_root: ./data/users # {root}/{userId}/ 配下に AGENTS.md/browser-macros 等を保存 task_upload_max_size_mb: 50 # /api/local/tasks と /comments の body 上限 (MB) # base64 で乗るので実ファイル目安は値 × 0.75。範囲 [1, 1000] trash_retention_days: 30 # data/users/{userId}/trash/ の自動 sweep (起動時 + 24h 周期) # 0 で sweep 毎に全削除 file_trash_retention_days: 30 # タスクのファイルのごみ箱を残す日数 (起動時 + 24h 周期) # 画面から消したファイル/フォルダは物理削除せず # 作業場の外のごみ箱へ退避し、ここで指定した日数を # 過ぎたものだけを掃除が本当に消す。 # 0 以下で掃除しない (上の trash_retention_days とは # 別の置き場・逆の意味なので注意) llm_call_log_retention_days: 30 # LLM へ送った本文の記録 (logs/llm-calls-*.jsonl) を残す日数 # (起動時 + 24h 周期)。過ぎたファイルは丸ごと消える # (途中で切らないので、記録が半分だけ読めない状態にならない) # 0 以下で掃除しない = 期限なし # system_agents_path: ./data/system/AGENTS.md # システム共通の指示 (設定 → システム共通の指示) の保存先 # data/system/ 配下のファイルのみ許可 (外・ディレクトリ・ # user_folder_root 配下を指すと警告して既定へフォールバック) # 変更はサーバー再起動で反映 # ─── Execution ─────────────────────────────────────────────── # ジョブ全体の並列度・movement 上限・ジョブ retry。 concurrency: 4 # 全 worker 合算の最大並列ジョブ数 (env: CONCURRENCY) max_movements: 200 # 1 ジョブ内の最大 movement 数 (loop 防止) retry: max_attempts: 3 # ジョブ失敗時の最大再試行回数 backoff_seconds: [60, 300, 900] # 各 attempt 間の待機秒 # 利用者ごとの実行枠 (issue #1191 段 1) # ワーカー 1 台ごとの上限 (外側) とは別に、1 人が同時に走らせられる本数を用途ごとに絞る。 # 数え方は「全体で」。ワーカーの台数が増えても 1 人の取り分は増えない。 # 数えるのは実行中のものだけで、待ち行列・回答待ち・サブタスク待ち・再試行待ちは数えない。 # 0 は「その枠では数えない」。agent と reflection はそれで無制限になる。 # dictionary だけは無制限にならず、この設定を入れる前の歯止めへ戻る # ——辞書引きはワーカー 1 台あたり 2 本、資料への質問は document_chat の # max_concurrent_per_user (既定 1)。3 つとも 0 にしたときも同じ戻り方をする。 # 認証を使っていない環境では、この枠そのものが効かない (持ち主が全員 local になるため)。 user_concurrency: agent: # 人が起こしたタスク・定期実行・切り出し・サブタスク user: 1 admin: 2 dictionary: # 辞書引きと資料への質問が共有する枠 (合算して数える) user: 1 admin: 2 reflection: # 内省の実行 user: 1 admin: 2 # ASK (ユーザーへの質問) 制御 ask: max_per_job: 2 # 1 Job あたりの ASK 上限 # Subtask 制御 subtasks: max_depth: 2 # SpawnSubTask のネスト最大深度 max_per_parent: 10 # 1 ジョブが生成できるサブタスクの最大数 spawn_stagger_ms: 1000 # SpawnSubTask の連続発火を間引く遅延(ms)。一斉着地で GPU 優先順位を飛び越えるのを防ぐ。0 で無効 # ─── Python パッケージ(ワークスペース単位の wheel オーバーレイ)──────── # 既定 OFF。有効化すると、各ワークスペースの設定 → Python から admin/オーナーが # wheel を追加でき、そのワークスペースのエージェントだけが import できる。 # インストールはネットワークを許可した分離 bwrap で out-of-band 実行(ワークスペース / # シークレットには触れない)。wheels のみ(--only-binary=:all:)で sdist の任意コード # 実行を回避。エージェント自身の sandbox は従来どおりネットワーク遮断のまま。 # python_packages: # enabled: false # true で機能を有効化 # dir: ./data/python-packages # オーバーレイの保存先ルート # index_url: https://pypi.org/simple # 固定 index(リクエストで上書き不可) # install_timeout_sec: 180 # 1 回のインストールの上限秒(最大 1800) # max_packages_per_space: 30 # 1 ワークスペースが固定できるパッケージ数 # ─── Context (LLM コンテキスト管理) ─────────────────────────── # context: # limit_tokens: 128000 # 省略時は接続先へ自動で問い合わせる(Ollama /api/show → llama.cpp # # /props → OpenAI 互換 /v1/models の max_model_len)。全部駄目なら 128000 # thresholds: # - ratio: 0.7 # action: warn # - ratio: 0.85 # action: prompt # - ratio: 0.95 # action: force_transition # ─── Safety (エージェント自爆防止) ──────────────────────────── # safety: # max_iterations: 200 # 1 movement 内の最大イテレーション # max_revisits: 3 # 同一 movement の最大再訪問 # max_tool_loop_repeats: 5 # 全く同じツール呼び出し(名前+引数)を連続で繰り返した回数がこの値に達したらループとみなし強制中断 (2以上) # max_thinking_only_retries: 6 # 思考だけ(本文もツール呼び出しも無い)の応答が連続でこの回数に達したら中断 (1以上)。 # 思考が返っている=バックエンドは健全なので、空応答(3回固定)とは別に数える # max_job_minutes: 180 # 1 ジョブの実行時間ハードデッドライン (分)。これを超えたジョブは # 強制 abort し、占有していた同時実行スロットを解放する (プロセス # 再起動不要)。サブタスク待機に入るジョブは即座にスロットを返すため # これに達するのは真のハングのみ。**default 180**。0 で無効。 # 設定 → セーフティ からも変更できる # prompt_guard_ratio: 0.8 # コンテキスト上限の何 % まで prompt を許容するか (0.5–0.95) # history_summarization: # 古い turn を構造化要約に置換して粘る (Opencode 方式) # enabled: true # default true # tail_turns: 2 # 末尾何 turn を必ず保護するか # preserve_recent_budget: 8000 # 末尾保護の最大トークン数 # bash_unrestricted: false # true: コマンドホワイトリストを撤廃し任意コマンド実行可。 # # 代わりに bwrap サンドボックスで workspace 単位の # # ファイルシステム隔離を強制 (タスク間の横断アクセス防止)。 # # 前提: コンテナで user namespace が有効 (nesting=1)。 # # 起動時に bwrap の動作確認を行い、失敗時はエラー終了。 # # Bash サンドボックス機構: # # auto (既定) bwrap があれば sandbox、無ければ hardened-whitelist にフォールバック # # always sandbox を強制。bwrap 不在なら起動失敗(本番推奨) # # off bwrap を使わない(env スクラブは維持)。デバッグ用、非推奨 # # ⚠ 下の 2 行をこのまま外すと、bwrap の無いホストでは起動しない (#1235)。 # # auto の hardened フォールバックには外向き通信を遮断する仕組みが無いので、 # # 遮断を選んだまま (bash_allow_network: false) だと起動時に断られる。 # # bwrap を入れるか、bash_allow_network: true を明示するか、bash_sandbox: off にする。 # bash_sandbox: auto # bash_allow_network: false # true: サンドボックスで host network を許可 # # (--unshare-net を外す)。pip/npm install/curl 等が # # 可能になる。⚠ 隔離が弱まり情報漏えい/SSRF のリスク。 # # 既定 false (ネット遮断)。sandboxed 時のみ有効。 # # 表明ではなく生きたスイッチ。bwrap が無い間の # # 逃げ道として true にしたら、bwrap を入れた時点で # # false へ戻すこと(戻さないと通信が本当に開く)。 # ─── Search Filter (WebSearch の機密情報漏洩防止) ───────────── # search_filter: # blocked_patterns: # カスタムブロックパターン (完全一致で除去) # - secret-project # - internal-codename # auto_block: # 自動検出 (default: 全 true) # private_ip: true # 10.* / 172.16-31.* / 192.168.* / 127.* # internal_domain: true # .local / .internal / .lan / .intranet / .corp / .home # email: true # phone: true # 日本の電話番号 # ─── Browser Runtime (BrowseWeb / BrowserAction) ────────────── # browser: # page_timeout: 60000 # ms # action_timeout: 30000 # ms # display_mode: novnc # 'headless' (default) / 'novnc' # # novnc = Browser タブのライブ表示 / InteractiveBrowse / # # CAPTCHA 解決を有効化 (ホストに Xvfb/x11vnc/websockify 必須)。 # # 旧 'captcha_solve' は自動で display_mode に移行される (非推奨)。 # max_captcha_pages: 5 # 人が解けるように残す CAPTCHA ページの上限 (display_mode: novnc 時のみ)。 # # 閉じられなかったページもこの枚数に数える。上限の 2 倍に達したら # # ブラウザ検索を止めて SearXNG のみで応答する # max_captcha_sessions: 3 # CAPTCHA を人が解く画面をスペースごとに持つときの同時枚数上限。 # # 1 枚につき Xvfb / x11vnc / websockify / Chromium の 4 プロセスが常駐する。 # # 上限に達したら最も古い画面を捨てる。閉じ損ねが居座って 2 倍に達したら # # 新しい画面を作らず headless に落とす (max_captcha_pages とは別の歯止め) # captcha_session_idle_ttl: 1800 # 画面を何秒アイドルしたら捨てるか。検索・閲覧のたびに延命される # captcha_block_threshold: 3 # ブラウザ検索が CAPTCHA で全滅した連続回数。ここに達したら休止する # captcha_block_cooldown_sec: 600 # 休止する秒数。検索が 1 回でも通れば即解除される # captcha_engine_cooldown_sec: 1800 # 確認画面を出した検索先 1 つを、次の検索から何秒飛ばすか。 # # 上の 2 つ (全部塞がれたときの休止) とは別の歯止めで、 # # 検索先 1 つだけが塞がれている状態を止める。 # # 人が「解決した」を押すとそのワークスペースぶんは即座に戻る。0 で無効 # channel: chrome # 'chromium' (default) / 'chrome' / 'msedge' # executable_path: /usr/bin/google-chrome # channel と排他 # ─── Tool packs (環境全体で群ごと止める) ───────────────────── # # ツールを「群」の単位で、この環境から丸ごと外す。書いた群のツールは # エージェントに渡るツール一覧からも、ワークスペースの設定画面のツール一覧からも # 消える。ワークスペース側で入れ直すことはできない (層の向きは環境が上)。 # # **反映は再起動時のみ。** 走行中のジョブのツール一覧を入れ替えると、 # LLM 側のプロンプトキャッシュが全損する (遷移ごとに約 2 万トークンの再評価)。 # 設定を保存しただけでは何も変わらない。サーバーを再起動すること。 # # 書ける名前 (2026-08-15 時点): # x X (旧 Twitter) の検索・投稿取得 (XSearch / XUserPosts / XPostDetail / # XTimeline / XFetchCardMedia) # youtube YouTube の字幕取得・検索 (GetYouTubeTranscript / SearchYouTube) # maps 地図の検索・経路・逆ジオコーディング (SearchPlaces / GetDirections / ReverseGeocode) # amazon Amazon の商品検索と Keepa の価格 (SearchAmazon) # speech 音声を文字にする (TranscribeAudio) # speak 文章を音声にする (Speak) # ms-learn Microsoft Learn の文書検索 (SearchMicrosoftLearn ほか 3 本) # slide .pptx を組み立てる (SetTheme / AddSlide / BuildPptx / ResetSlides) # # 一覧に無い名前を書くと、起動時のログに ERROR で出る (何も止まらない)。 # 一覧に無い群 (Web / ブラウザ / Office / SSH など) は、ここでは止められない。 # 名前の定義は src/engine/tools/tool-pack-ledger.ts。 # # tool_packs: # disabled: # - x # - youtube # ─── Tools (Web & Search / Media / External) ──────────────── # UI 上は 4 カテゴリに分かれて編集可能 (Web & Search / Browser Runtime / # Media & Documents / External Services)。YAML は # 互換のため `tools` 1 ブロックで管理。 tools: # Web & Search searxng_url: http://localhost:8080 # WebSearch フォールバック先 (通常は Playwright + Google) webfetch_timeout: 30 # WebFetch / DownloadFile timeout (sec) # websearch_timeout: 15 # webfetch_allowed_hosts: # SSRF 例外 (private IP / .local 等を許可する場合) # - my-internal-host.local # ページの魚拓 (BrowseWeb が開いたページの画像を source/images/ に溜める) # どれも中身の意味は見ない歯止め。0 にすると実質その歯止めで全部落ちる # browse_image_max_per_page: 20 # 1 ページあたりに残す枚数 (default 20) # browse_image_max_size_mb: 5 # 画像 1 枚あたりの容量上限 (default 5) # browse_image_min_bytes: 1024 # これ未満のバイト数は落とす (default 1024) # browse_image_min_dimension: 32 # 縦横どちらかがこれ未満の px なら落とす (default 32) # Media & Documents # modality_endpoints: # image: # model: qwen2-vl:8b-instruct # base_url: http://localhost:11434/v1 # api_key: sk-xxxx # 認証が必要な場合のみ。画像対応ワーカーは自身のキーを優先 # timeout: 60 # max_tokens: 1024 # audio: {} # 音声モデルへの直接入力・委譲用の予約設定 # video: {} # 動画ツール用の予約設定 # ocr_model: glm-ocr # OCR用モデル(画像接続先へ問い合わせる) # office_excel_max_size_mb: 10 # ReadExcel / SplitExcelSheets / 画面のセル保存の上限 (default 10) # office_docx_max_size_mb: 10 # ReadDocx / SplitDocxSections 上限 # office_pdf_max_size_mb: 10 # ReadPdf 上限 # office_pptx_max_size_mb: 50 # ReadPPTX 上限 # office_preview_max_size_mb: 50 # 画面の Excel プレビュー専用の上限 (default 50)。眺めるだけの経路なのでエージェント側とは別のつまみ # office_pptx_max_uncompressed_mb: 200 # ZIP 展開後上限 (zip-bomb 検知)。OOXML を開く経路すべてで共有 (Read 系 3 種・分割 2 種・Edit 系 3 種・画面の Excel プレビュー / セル保存) # office_max_entries: 10000 # ZIP 内の項目数上限 (zip-bomb 検知)。展開後上限と同じ経路で共有。申告件数と実際に並んでいる件数の両方に効く # office_msg_max_size_mb: 25 # ReadMsg 上限 (default 25) # speech_server_url: http://localhost:8000/v1 # speech_timeout: 300 # speech_language: ja # 読み上げ (Speak)。文字起こしとは別の接続先を指定できる # speak_server_url: http://localhost:8001/v1 # 未設定なら Speak は使えない # speak_model: tts-1 # speak_voice: alloy # 使える名前はサーバーごとに違う(選択肢は持たない) # speak_format: mp3 # mp3 / opus / aac / flac / wav / pcm はサーバー次第 # speak_timeout: 120 # speak_max_chars: 4096 # 超えたら断る(黙って切り詰めない) # External Services # x_cli_command: ["twitter"] # twitter-cli 実行コマンド # x_timeout: 90 # x_auth_token: "..." # 任意: auth_token cookie # x_ct0: "..." # 任意: ct0 cookie # x_proxy: http://127.0.0.1:7890 # 任意: twitter-cli 用 proxy # x_chrome_profile: "Profile 2" # Chrome cookie 抽出 profile # x_download_media: auto # 'auto' (default) / 'never' # x_download_video: thumbnail # 'thumbnail' (default) / 'full' / 'never' # x_media_max_mb: 25 # x_media_fetch_timeout_seconds: 15 # google_maps_api_key: "..." # 未設定なら Nominatim / OSRM # maps_timeout: 30 # amazon_affiliate_tag: "your-tag-22" # keepa_api_key: "..." # User browser-macros (RunUserScript) # user_scripts_enabled: false # true で browser-macros の実行を許可 # user_scripts_allow_userids: # 未指定 = 全ユーザー許可 (user_scripts_enabled に従う) # - alice-id # - bob-id # ─── サーバー TLS (オプション) ─────────────────────────────── # 【フレッシュインストール】setup.sh が server.tls.enabled: true を自動書き込む。 # 【アップグレード】server ブロック未記載の場合は false のまま(既存デプロイを壊さない)。 # 【リバースプロキシ構成】このブロックを省略するか enabled: false のままにすること。 # プロキシが TLS を終端しているので、ここで有効にすると二重終端になり接続が壊れる。 # # server: # port: 9876 # HTTP(S) 待ち受けポート (default 9876)。環境変数 PORT (.env 含む) が優先。反映には再起動が必要 # # 外から見えているアドレス。外部サービスとの接続 (OAuth) で使う折り返し先 # # (redirect_uri) を組み立てる、いちばん強い出どころ。画面に表示する値も # # 実際に送る値もここから作られるので、両者が食い違うことはない。 # # OAuth で省略時は次の順に探す: # # 1. auth のコールバック URL (auth.providers.*.callback_url) のアドレス部分 # # 2. 届いたリクエスト (X-Forwarded-Proto / X-Forwarded-Host、無ければ Host) # # 3. http://localhost:{待ち受けポート} # # リバースプロキシがこれらのヘッダを転送しない構成では、ここに明示すること。 # # パスは無視され scheme + ホスト + ポートだけを使う。 # # webhooks / chat の個別 public_base_url が空欄なら、この値をリンクに使う。 # # OAuth への反映は再起動不要。通知・チャット連携への反映は再起動後。 # public_base_url: "https://maestro.example.com" # tls: # enabled: true # フレッシュインストールのデフォルト; ブロック未記載=アップグレード時 false # cert_file: null # PEM 証明書パス (任意); cert_file と key_file は両方設定するか両方省略 # key_file: null # min_version: TLSv1.2 # self_signed_dir: ./data/tls # self_signed_hosts: [] # localhost / 127.0.0.1 / ::1 / hostname は常に含まれる # http_redirect: true # http_redirect_port: 9080 # HTTP→HTTPS リダイレクトの待ち受けポート。単一値か配列で複数指定可 (例: [80, 9876])。 # # 各ポートは HTTPS ポートと異なる必要があり、1024 未満 (80 等) の bind には権限が必要 # redirect_host: null # リダイレクト先のホスト; null かつワイルドカード bind の場合はリクエストの Host ヘッダから導出 # hsts: false # 既定 false。HSTS (Strict-Transport-Security) を送るかどうか。 # # true にするとブラウザを HTTPS に固定し、後からオフにしても解除できなくなる # # (自己署名証明書では害だけ大きい)。正式な証明書がある場合のみ true。 # # false の間は TLS 応答で max-age=0 を送り、過去に固定されたブラウザを解除する # # リバースプロキシ構成: このブロックを省略するか enabled: false のままにすること。 # # プロキシが TLS を終端している場合に native TLS を有効にすると二重終端になり壊れる。 # # noVNC / SSH コンソールを wss で使う場合は「信頼済み証明書」が必要 # # (自己署名の wss はブラウザに click-through がない) — # # cert_file / key_file で実証明書を指定するか、OS の信頼ストアに自己署名 CA を登録すること。 # ─── 認証 (オプション) ──────────────────────────────────────── # 未設定なら認証なしで動作 (従来互換)。 # auth: # # 空のままだと data/secrets/session-secret.key に固定値を自動生成して使う (再起動でセッション維持)。 # # 明示設定したい場合は `openssl rand -hex 32` 等で生成した固定値を入れる (複数ノードで共有する場合は必須)。 # # ⚠ プレースホルダ文字列をそのまま使わない (公開された secret は偽造・改ざんに使われる)。 # session_secret: "" # session_max_age: 86400000 # 無操作タイムアウト (ms)。アクセスごとに延長 (rolling)。未設定時は30日 # secure_cookie: false # HTTPS 環境では true (TLS 終端の背後では必須) # admin_emails: # - "admin@example.com" # # primary_provider: gitea # 'google' | 'gitea' | 'local'。複数有効時に明示 # providers: # google: # client_id: "" # client_secret: "" # callback_url: "http://localhost:3000/auth/google/callback" # gitea: # client_id: "" # client_secret: "" # base_url: "https://gitea.example.com" # callback_url: "http://localhost:3000/auth/gitea/callback" # # ローカルアカウント (email + password)。OAuth を立てずにパスワード保護したい時。 # # ここが未設定のまま新規インストールが loopback 以外で待ち受ける場合 (Docker 等) は、 # # 起動時に enabled: true が自動で書き込まれ、admin のパスワードが生成・出力される # # (#1024)。パスワードは DB にハッシュで入り、ここには書かれない — bootstrap_admin は # # 毎起動 DB へ再適用されるので、生成値を置くと変更が再起動で巻き戻るため。 # # 既存の no-auth デプロイに後付け可: 起動時に bootstrap_admin を id='local' で冪等 seed し、 # # no-auth 時代に 'local' 所有で溜まったデータをそのまま admin が引き継ぐ。 # local: # enabled: true # allow_signup: false # true でセルフ登録 (status=pending → admin 承認) # bootstrap_admin: # 初回 admin (id='local')。seed 後は Settings/CLI で変更 # email: "admin@example.com" # password: "強いパスワードを設定" # 平文保存される。初回ログイン後に変更推奨 # ─── Branding (オプション) ──────────────────────────────────── # config.yaml / data/branding/ は .gitignore 済みで git pull 影響なし。 # Settings → System → Branding で GUI 編集可 (admin)。 # branding: # app_name: "My Team AI" # primary_color: "#2563eb" # login_page_title: "My Team AI" # logo_url: "/branding/logo-abc123.svg" # favicon_url: "/branding/favicon-def456.png" # footer_text: "© 2026 Your Team" # ─── Secrets ───────────────────────────────────────────────── # secrets: # master_key_path: ./data/secrets/master.key # 32-byte key, auto-generated on first start (mode 0600) # session_secret_path: ./data/secrets/session-secret.key # auth.session_secret 未設定時の自動生成先 (mode 0600) # ─── Reflection ("Hermes" mode) ────────────────────────────── # default OFF。ON にすると毎ジョブ完了後に user memory を LLM が自動更新する。 # snapshot は data/users/{userId}/.reflection-history/ に残り UI から revert 可。 # reflection: # enabled: false # 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) ──────────────────────────── # Individual servers は admin UI (global) または各ユーザー (self-hosted) で管理。 # MCP_ENCRYPTION_KEY env (64 hex chars) が必須。 # mcp: # 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: false # 自前 MCP server を private 網に置く場合 true # ─── SSH (off by default) ──────────────────────────────────── # 有効化手順は docs/ssh.md / config.yaml.example のコメント (旧版) を参照。 # Operator runbook: docs/ssh.md # Sample piece: pieces/ssh-console.yaml # # ssh: # enabled: false # # # allow_private_addresses: false # global default。admin は per-connection で grant 可 # # call_timeout_seconds: 30 # # max_output_bytes: 32768 # # max_upload_size_mb: 100 # # max_download_size_mb: 100 # # audit_retention_days: 90 # # admin_bypasses_grants: true # # abuse_window_minutes: 10 # # abuse_failure_threshold: 5 # # abuse_lock_minutes: 30 # # # ── Interactive SSH Console (live PTY-backed shell) ── # console: # enabled: false # true で SshConsole* tools + UI Terminal タブを公開 # idle_timeout_seconds: 1800 # 30min I/O-less = auto close # max_session_duration_seconds: 14400 # 4h hard cap # scrollback_bytes: 524288 # 512KB scrollback / session # max_sessions_per_connection: 3 # max_sessions_per_task: 5 # 同一タスクが開ける同時コンソール数の上限 # max_sessions_per_user: 20 # ユーザー単位の同時コンソール数の上限 (0 = 無制限) # max_input_bytes_per_send: 16384 # auto_inject_screen_lines: 24 # default_cols: 120 # default_rows: 32 # ── Browser Notifications V2 (Web Push) ─────────────────────────────── # Requires HTTPS hosting + (for iOS) PWA installation on the client side. # notifications: # push: # enabled: false # true で V2 を有効化 # vapid_subject: "https://maestro.example.com/" # RFC 8292 — operations URL preferred (運用サイトの URL か mailto:) # vapid_current_path: "./data/secrets/vapid.json" # 自動生成 (mode 0600) # vapid_history_dir: "./data/secrets/vapid-history" # payload_max_bytes: 3072 # JSON byte length cap (上限 4096) # queue_concurrency: 8 # per_send_timeout_ms: 10000 # # 起動時に vapid_current_path に鍵が無ければ自動生成、mode 0600 で保存。 # 鍵をローテーションする場合: npm run vapid-rotate # ── ワークスペース Webhook 通知 (Discord / Slack / Teams) ──────────────────── # Spec: issue #797(Discord / Slack / Teams いずれも実装済み)。 # 通知先 URL はワークスペースごとに設定 UI から登録し、DB に AES-256-GCM で # 暗号化して保存する(config.yaml には書かない)。 # このブロックは 設定 → Webhook 通知 からも編集できる(反映には再起動が必要)。 # 数値は範囲外(0・負数・数値以外)だと起動時に既定値へ戻し、警告をログに出す。 # 0 に意味があるのは max_redirects と retry.max_attempts の 2 つだけ。 # webhooks: # enabled: false # true で有効化。false のときは送信を no-op する # timeout_ms: 10000 # 1 送信あたりの HTTP タイムアウト(1 以上) # payload_max_bytes: 8192 # 送信 payload の上限(バイト・1 以上) # max_redirects: 5 # ssrfSafeFetch が辿るリダイレクト上限(0 で追わない) # queue_concurrency: 8 # 送信キューの同時実行数(1 以上) # retry: # max_attempts: 2 # 429 / 5xx / timeout 時の再試行回数(初回 + 2 = 最大 3 回送信。0 で再試行しない) # backoff_ms: 500 # 再試行のベース backoff(指数バックオフ + jitter・1 以上) # public_base_url: "https://maestro.example.com" # 通知本文のタスクリンクに使う絶対 URL # # 空欄なら server.public_base_url を使う。 # # 両方未設定ならリンクを省く。反映には再起動が必要。 # ── A2A OAuth2 Authorization Server ────────────────────────────────────────── # Requires auth to be active (consent screen uses req.user). # # a2a: # enabled: false # issuer: "https://localhost:8080/oidc" # 認可サーバーの issuer(公開 URL) # resource_audience: "https://localhost:8080/a2a" # トークン audience(A2A endpoint) # limits: # rate_per_minute: 30 # ingress requests/min per delegation (token bucket) # max_concurrent_tasks: 5 # simultaneous in-flight A2A tasks per delegation # max_payload_bytes: 65536 # HTTP body + message size cap # max_stream_seconds: 600 # max SSE stream duration (task + resubscribe) # skill_budget_per_hour: 100 # accepted tasks per rolling hour per delegation # max_concurrent_resubscribe: 5 # simultaneous tasks/resubscribe streams per delegation