Maestro

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/$id is the runs view: schedule strip, stats, recent runs with timeline pills.
  • /orchestras/$id/settings is 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

FieldEditable whereNotes
idn/aURL-safe identifier; never changes after creation.
namesettings pageDisplay name.
tagsettings pageCategorisation chip (Outreach, Inbox, Research, Monitor, Marketing, Content, CRM).
descriptionsettings pageFree text shown on the runs dashboard.
cronsettings pageStandard 5-field cron expression. Empty = no automatic firing; manual Run-now still works.
score_idn/a (v1)Which score graph this orchestra plays. Switching scores requires creating a new orchestra — historical run-row shape depends on the originating graph.
enabledruns dashboard topbarOperator’s gate; the scheduler only fires cron when this is true.
statusruntime-computedrunning / idle / scheduled / paused.
skillsn/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.
instructionsn/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_idn/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:

  1. Score to play — dropdown of every workspace score (template + custom). Required.
  2. Name — display name.
  3. Tag — category chip. Defaults from the score’s pipelineKind when left as Auto (outreach → Outreach, content → Content, seo → Research).
  4. Cron schedule (optional) — standard 5-field expression. Empty = manual-only.
  5. 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:

  • statusqueued / running / succeeded / failed / completed
  • started_at / finished_at / duration_ms
  • output — the human-readable summary line (e.g. “3 drafts written · 5.4K tokens · $0.04”)
  • cost_cents — computed at finalize from run_steps token 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 when true does 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 within poll_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:

  1. Open Composer, clone the score you want (or build it from scratch).
  2. Open the workspace’s orchestra list (sidebar, “Orchestras · N”).
  3. Click ”+ New” and create a new orchestra pointed at the new score.
  4. 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.

  • Scores — what orchestras play.
  • Composer — where scores are edited.
  • Agents — distinct concept; lives inside scores’ LLM nodes.
  • Pipelines — where orchestra outputs land for outreach scores.