-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
English | 日本語
How maestro turns an issue into a pull request — components, data flow, and trust boundaries.
flowchart TB
subgraph triggers [Triggers]
UI[WebUI]
API[HTTP API]
Poller[GitHub poller]
end
subgraph maestro [maestro process]
Queue[Run queue]
Exec[Run execution]
Registry[Agent registry]
DB[(SQLite)]
Gateway[MCP Gateway]
end
subgraph anthropic [Anthropic]
Parent[maestro-orchestrator]
Child[maestro-implementer]
Vault[Vault credentials]
Env[Environment / sandbox]
end
subgraph external [External]
GH[GitHub API + GitHub MCP]
Linear[Linear MCP]
Stdio[stdio MCPs via proxy]
end
UI --> Queue
API --> Queue
Poller --> Queue
Queue --> Exec
Exec --> Registry
Exec --> DB
Exec --> Parent
Parent --> Child
Parent --> Vault
Child --> Env
Vault --> GH
Vault --> Linear
Vault --> Gateway
Gateway --> Stdio
Parent -->|create_sub_issue / create_final_pr| GH
Code lives under src/features/* (use cases) and src/shared/* (cross-cutting). Entry wiring is src/index.ts.
| Feature | Role |
|---|---|
run-api |
REST + SSE for runs |
run-queue |
Serialize / schedule run execution |
run-execution |
Orchestration pipeline for one run |
decomposition |
Parent tool: create sub-issues |
finalize-pr |
Parent tool: open the final PR |
dashboard |
Hono SSR WebUI |
github-trigger |
Poll labeled issues / @bot run comments |
github-review-webhook |
Optional PR review hooks |
mcp-gateway |
Bearer auth → loopback mcp-proxy |
dev-tunnel |
Local ngrok path for MCP |
stale-run-reaper |
Fail/cancel wedged running rows |
auth |
Optional OIDC for dashboard/API |
ingress-proxy |
Split app vs MCP hostnames |
preflight |
GitHub + Anthropic access checks |
repo-chat |
Repo-scoped chat (WebUI) |
| Name | Role | Topology |
|---|---|---|
maestro-orchestrator |
Parent / coordinator | Multi-agent coordinator |
maestro-implementer |
Child implementer | Roster entry on the parent |
Registry (src/shared/agents/registry.ts):
- Ensure child agent exists (create/update)
- Embed child
{id, version}in parentmultiagent.coordinatorroster - Persist ids/versions in DB table
agent_registry_state
Parent custom tools (only these two — no spawn_child_task):
| Tool | Purpose |
|---|---|
create_sub_issue |
Record a decomposed unit of work on GitHub |
create_final_pr |
Open the consolidated pull request |
Child work is delegated through Managed Agents threads, not a custom spawn tool. Observable event names include:
session.thread_created-
agent.thread_message_sent/agent.thread_message_received session.thread_status_*
sequenceDiagram
participant T as Trigger
participant Q as Run queue
participant E as Run execution
participant A as Anthropic session
participant G as GitHub
T->>Q: enqueue run
Q->>E: start
E->>G: preflight + read parent issue
E->>A: ensure agents, vault, environment
E->>A: sessions.create + first turn
A->>A: orchestrator plans / decomposes
A->>G: create_sub_issue (custom tool)
A->>A: child threads implement
A->>G: push branches via GitHub MCP / git
A->>G: create_final_pr
E->>Q: terminal status + events
Typical phases (visible in WebUI / run events): resolve origin → preflight → vault/MCP credentials → session → decomposition → implementation threads → finalize PR → complete / fail / abort.
origin |
Input | Notes |
|---|---|---|
github_issue (default) |
issue number or GitHub issue URL; optional repo
|
URL can supply both repo and number |
linear_issue |
linearIssue identifier/URL + required repo
|
Needs enabled Linear MCP (https://mcp.linear.app/mcp) |
Same pipeline after origin resolution: work still lands as GitHub branches + PR on the target repo.
| Trigger | How |
|---|---|
| WebUI | Form on dashboard |
POST /api/runs |
JSON body (see Configuration → API) |
| GitHub poller | Repos in polled_repositories (WebUI Repositories). Label default agent-run; comment @bot run
|
Poller config env (cadence / keywords only — not the repo list):
-
GITHUB_TRIGGER_POLL_INTERVAL_SECONDS(default 60) -
GITHUB_TRIGGER_LABEL(defaultagent-run) -
GITHUB_BOT_MENTION(defaultbot)
| Store | Path / table | Contents |
|---|---|---|
| SQLite | default .maestro/dashboard.db (container: /data/app/dashboard.db) |
runs, events, prompts, MCP servers, polled repos, registry state, … |
| Runtime files | .maestro/ |
lock, state JSON (gitignored) |
DB is source of truth for operator-managed data: prompts, polled repositories, MCP servers, repo prompts/environments/chat, agent registry. Schema lives in src/shared/persistence/db.ts (SCHEMA_SQL).
SQLite = single writer. For HA, prefer one writer + optional replica tooling (e.g. Litestream in the image) owned by ops.
Managed Agents only speak remote Streamable HTTP MCP. stdio servers never attach directly.
Managed Agent
→ HTTPS Remote MCP URL
→ (edge / CIDR allowlist)
→ MCP Gateway (Bearer MCP_GATEWAY_TOKEN)
→ mcp-proxy loopback
→ stdio process (mcp-proxy.json)
Builtin GitHub MCP:
- name:
github - URL:
https://api.githubcopilot.com/mcp/ - Auth: per-repo GitHub App installation token in Vault (
static_bearer), not a shared PAT
Credential model:
- Agent definition lists
mcp_servers+mcp_toolset - Vault stores credentials keyed by
mcp_server_url -
sessions.createpassesvault_idsonly — Anthropic matches URL → credential
Details: MCP-Servers
| Mode | How | Code execution |
|---|---|---|
| Cloud (default) | maestro creates/uses Anthropic environments | Anthropic sandbox; optional github_repository mount |
| Self-hosted |
ANTHROPIC_ENVIRONMENT_ID on the app |
Your poller/worker; bootstrap clones under /workspace/maestro-runs/<sha256-run-id>/...
|
Self-hosted specifics:
- App never holds
ANTHROPIC_ENVIRONMENT_KEY - Fixed shared
VAULT_IDis disallowed; per-run managed vaults hold MCP credentials only - Worker needs
git,bash,curl,jq,openssl, GNUtimeout, and GitHub App PEM for credential helper - Full contract:
docs/self-hosted-sandboxes.md
┌─ Trusted (your infra) ─────────────────────────────┐
│ maestro app, SQLite, GitHub App private key, │
│ MCP_GATEWAY_TOKEN, OIDC secrets, worker keys │
└────────────────────────────────────────────────────┘
│ API + vault_ids
▼
┌─ Anthropic Managed Agents ─────────────────────────┐
│ orchestrator/implementer sessions, vault secrets, │
│ cloud sandbox (or your self-hosted worker) │
└────────────────────────────────────────────────────┘
│ GitHub MCP / git / tools
▼
┌─ GitHub / Linear / Figma / … ──────────────────────┐
Rules of thumb:
- Never put long-lived cloud SA keys or GitHub PEMs in prompts or client-side code
- Prefer repo-scoped App installation
- On multi-repo GitHub App installs, avoid one shared
VAULT_ID— MCP credentials are URL-keyed and installation tokens can overwrite each other - Gateway token is a secret; rotate deliberately and keep stable per environment (churn creates orphan vault credentials)
-
Run events — durable stream in SQLite; WebUI live tail +
GET /api/runs/:id/events(SSE) - Audit middleware — HTTP / session / tool structured audit
-
OpenTelemetry — off by default;
OTEL_ENABLED=true(+ OTLP endpoint). Sensitive fields are redacted (no prompts, tokens, bodies)
| Concern | Start here |
|---|---|
| Process boot | src/index.ts |
| Config schema | src/shared/config.ts |
| Agent definitions | src/shared/agents/ |
| Parent tools | src/parent-tools.ts |
| Vault / MCP creds | src/shared/vault.ts |
| Constants (URLs, names) | src/shared/constants.ts |
Next: Configuration · MCP-Servers