Orchestras
An orchestra is the cron-attached deployment of a score in a workspace. The orchestra holds the schedule, the enabled toggle, the secret bindings, and the runtime status. The score is the graph; the orchestra is “this graph plays in this workspace on this cadence.”
The metaphor: Maestro conducts orchestras playing scores from agents and skills.
In the dashboard:
- The bottom of the sidebar lists every orchestra under “Orchestras · N.” Click one to open its dashboard.
/orchestras/$idis the runs view: schedule strip, stats, recent runs with timeline pills./orchestras/$id/settingsis the metadata editor (name, tag, description, cron, plays-score).
The DB table is orchestras (renamed from score_runners in v0.3.0; before that, agents until v0.1.31). The legacy names persist in column-history comments only.
Orchestra fields
| Field | Editable where | Notes |
|---|---|---|
id | n/a | URL-safe identifier; never changes after creation. |
name | settings page | Display name. |
tag | settings page | Categorisation chip (Outreach, Inbox, Research, Monitor, Marketing, Content, CRM). |
description | settings page | Free text shown on the runs dashboard. |
cron | settings page | Standard 5-field cron expression. Empty = no automatic firing; manual Run-now still works. |
score_id | n/a (v1) | Which score graph this orchestra plays. Switching scores requires creating a new orchestra — historical run-row shape depends on the originating graph. |
enabled | runs dashboard topbar | Operator’s gate; the scheduler only fires cron when this is true. |
status | runtime-computed | running / idle / scheduled / paused. |
skills | n/a (v1) | Legacy field from the LLM-loop runtime; ignored by graph orchestras (the score’s nodes own this). Will drop in a future migration. |
instructions | n/a (v1) | Legacy field from the LLM-loop runtime; null on every graph orchestra (retired in v0.1.40). Will drop in a future migration. |
handoff_to_agent_id | n/a (v1) | Legacy LLM-loop chain pointer; null on every graph orchestra. Will drop in a future migration. |
Creating an orchestra
The sidebar’s ”+ New” button at the top of the orchestras section opens the OrchestraBuilder — a single-page modal:
- Score to play — dropdown of every workspace score (template + custom). Required.
- Name — display name.
- Tag — category chip. Defaults from the score’s
pipelineKindwhen left as Auto (outreach→ Outreach,content→ Content,seo→ Research). - Cron schedule (optional) — standard 5-field expression. Empty = manual-only.
- Description (optional) — surfaced on the dashboard.
Submit → POST /api/orchestras → router navigates to the new orchestra’s dashboard. Every orchestra ships disabled, so flip Enable in the topbar after wiring the secrets the score’s skills need.
Runs
Every cron firing (or manual Run-now) creates a runs row referencing the orchestra via runs.orchestra_id. The row carries:
status—queued/running/succeeded/failed/completedstarted_at/finished_at/duration_msoutput— the human-readable summary line (e.g. “3 drafts written · 5.4K tokens · $0.04”)cost_cents— computed at finalize fromrun_stepstoken counts ×model_pricing
Per-step detail lives in run_steps (cost capture, tool name, payload). Live updates flow over SSE via Postgres pg_notify, so the dashboard’s run timeline streams as the orchestra executes.
Enable / disable + Run now
The runs dashboard topbar:
- Disabled / Enabled toggle — flips
orchestras.enabled. Only whentruedoes the cron scheduler fire the orchestra. - Settings — links to
/orchestras/$id/settings. - Run now — POSTs to
/api/runs/by-orchestra/:id, queueing a run that the worker picks up withinpoll_interval_s. Bypasses the cron gate (works even when disabled).
The toggle ships every orchestra as enabled: false so a fresh install never auto-fires emails before the operator has reviewed everything.
Settings page
/orchestras/$id/settings. Form fields: name, tag, description, cron. A read-only “Plays score” section links to the score graph this orchestra plays. Save → PATCH /api/orchestras/:id.
The page deliberately doesn’t expose score_id editing. If you need an orchestra pointing at a different score:
- Open Composer, clone the score you want (or build it from scratch).
- Open the workspace’s orchestra list (sidebar, “Orchestras · N”).
- Click ”+ New” and create a new orchestra pointed at the new score.
- Disable + delete the old orchestra (or leave it disabled if you want the run history accessible).
This is more steps than an in-place re-wire but avoids the historical-run-row-shape problem: every runs row’s payload structure depends on the score graph that produced it, and dropping an orchestra across graphs would mix incompatible row shapes in the same timeline.
Multiple orchestras per score
The architecture doesn’t constrain this — you could play the same cold-leads-v2 score from two orchestras on different schedules. The OrchestraBuilder lets you pick any score, including ones already wired to other orchestras. Useful when you want, say, a hourly cold-leads run during business hours and a separate manual-only orchestra for one-off ICP experiments against the same graph.
Conductor / score / orchestra / agent — disambiguation
Four nouns, all easily confused. The crisp definitions:
- Maestro — the conductor. The platform itself.
- Score (scores.md) — the graph definition. A workflow shape.
- Orchestra (this page) — a workspace’s cron-attached deployment of a score.
- Agent (agents.md) — a reusable LLM-node config (system prompt + model + tools). LLM nodes inside scores reference agents.
A useful mental analogy: scores are like Docker images, orchestras are like running containers, agents are like the model+prompt configurations baked into the image.