maestro/docs/architecture.md
oss-sync d061ad08d8
Some checks failed
CI / build-and-test (push) Has been cancelled
sync: update from private repo (e62f5c7)
2026-06-11 01:52:48 +00:00

5.8 KiB

English | 日本語

Architecture Overview

MAESTRO is an agent orchestrator that runs the tasks a user submits with LLM-driven workflows (Pieces). For a code map aimed at contributors, see also ../AGENTS.md.

Execution flow

UI (POST /api/local/tasks)
  → bridge/server.ts (Express API)
  → Repository (SQLite: enqueue into the jobs table)
  → Worker.poll() picks up queued jobs
  → piece-classifier.ts: the LLM classifies the task and selects a Piece
  → piece-runner.ts: reads pieces/*.yaml and runs the movements in order
  → agent-loop.ts: the ReAct loop for one movement (LLM ↔ tool calls)
      ├─ intermediate transition: the transition tool
      └─ termination:             the complete tool (success / aborted / needs_user_input)
  → job complete: update DB + post a progress comment. Deliverables go to workspace/output/
  1. API intakebridge/server.ts receives the task and registers it in the jobs table as queued via the Repository.
  2. Workerworker.ts polls the DB and picks up jobs matching its profiles/task_classes (multiple workers run in parallel).
  3. Classificationpiece-classifier.ts passes the task body and the descriptions of all Pieces to the LLM and chooses the best-fit Piece.
  4. Piece executionpiece-runner.ts iterates through the Piece's movements in order. Feedback from a verify movement is carried over to the next execute, and lessons between movements accumulate via transition.lessons.
  5. ReAct loopagent-loop.ts shuttles between the LLM and tools within one movement. ContextManager tracks token usage from the LLM's usage and fires warn / prompt / force_transition at thresholds (70/85/95%).

Piece and Movement

  • Piece = pieces/*.yaml. Composed of a movements array.
  • Each Movement has allowed_tools (the tools presented to the LLM), edit (whether Write/Edit is allowed), and rules (transition conditions). Tools outside allowed_tools are invisible to the LLM.
  • Transitions: an intermediate hop uses transition (only the destinations listed in rules[].next are selectable); termination uses complete. complete.result is the only final output visible to the user.
  • default_next is an engine-internal sentinel (forced transition on context overflow, fallback at the ASK limit).
  • Progressive pressure: as consecutive revisits to the same movement increase, warnings are injected, and exceeding the threshold triggers ABORT.

Tool runtime

Tools are a set of modules in src/engine/tools/*.ts. tools/index.ts loads and dispatches them dynamically. Each tool has a one-line description (kept concise because it rides on every LLM call), and detailed instructions live in docs/tools/<name>.md (fetched with ReadToolDoc). For the main modules, see the list in ../AGENTS.md.

Read-type tools run in parallel. Write/Edit is only presented when the movement has edit: true, and writes are mostly limited to workspace/output/.

Bash sandbox

The agent's Bash execution is isolated with the bwrap sandbox when available:

  • Filesystem: only the task's workspace is rw-bound, /usr etc. are ro, and other tasks' workspaces and the host /home are invisible.
  • Environment variables: --clearenv + injecting only a minimal allowlist (secret env vars are invisible from inside the sandbox).
  • Network: blocked with --unshare-net (outbound communication is consolidated into WebFetch/MCP with SSRF guards).
  • Each Bash call gets an independent sandbox (volatile /tmp, a fresh namespace each time). Only the workspace persists.

safety.bash_sandbox selects the mode (auto/always/off). When bwrap is absent, it falls back to a hardened fallback (an exec with a command allowlist + path-scope checks + env scrubbing). Runtime pip/npm install are rejected in all modes, and Python packages are pre-baked from runtime/python-requirements.txt. For details, see operations/bash-sandbox-provisioning.md.

Workspace structure (during job execution)

{worktree_dir}/local/{taskId}/
  input/    where uploads and DownloadFile saves go
  output/   deliverables (the main place where Write/Edit is allowed)
  logs/     activity.log / various histories
  subtasks/ results from SpawnSubTask
  skills/   skill files materialized by ReadSkill

Database

SQLite (better-sqlite3). db/schema.sql is the initial schema. Additional columns are applied idempotently in db/migrate.ts with the pattern PRAGMA table_info → existence check → ALTER TABLE ADD COLUMN (no version-management table is used). Main tables: jobs / local_tasks / local_task_comments / audit_log, and others.

Job lifecycle

queueddispatchingrunningsucceeded / failed / waiting_human (waiting for an ASK answer) / waiting_subtasks (waiting for parallel subtasks). On failure, retry re-queues it (up to retry.max_attempts times).

Optional subsystems

  • LLM Gateway (src/gateway/) — exposes MAESTRO itself as an OpenAI-compatible LLM proxy (virtual keys, budgets, Prometheus metrics). For sharing across multiple GPUs/teams. Its env vars and connection type use the historical AAO_*/aao_gateway prefixes.
  • MCP — Model Context Protocol server integration (MCP_ENCRYPTION_KEY required).
  • Reflection — the LLM automatically updates user memory after each job completes (OFF by default, revertible).
  • Authentication — Google/Gitea OAuth via Passport (optional). A private/org/public visibility model.
  • Scheduler — cron-expression scheduled tasks.

Frontend

React + Vite + TailwindCSS + @tanstack/react-query. ui/src/App.tsx is the root. A two-column (list + detail) layout handles the task list, schedule, settings, and skill/Piece management.