Skip to main content
Songbird development is driven from a Linear board. Moving a card from one column to the next isn’t just bookkeeping — each move triggers an automated action: an AI agent starts planning, reviewers fan out, an implementation begins, a PR gets merged. This page explains the workflow end-to-end and how to work with it as a human contributor. The automation is a small Rust service called the linear-orchestrator. It lives in its own repository (studiocollective/linear-orchestrator) and runs as a background service that listens to Linear webhooks. You don’t need to run or deploy it to use it — you just move cards on the board.

The mental model

A board column is a phase. Moving a card forward into a column runs that phase’s action. The agent that owns the ticket does the work; the orchestrator just routes.
Two consequences fall out of this that are worth internalizing up front:
  • Only forward moves trigger anything. Dragging a card backward (Testing → Execution, Merged → Testing) or sideways never re-fires a phase. The orchestrator records the new position but stays quiet. This lets you freely pull a card back to fix something without spamming kickoff comments.
  • Agents are engaged by @mention. The orchestrator drives an agent by posting a comment that @mentions it (a Linear profile link in a comment body is an @mention, which wakes that agent’s session). So everything the automation does is visible in the issue’s comment thread — there’s no hidden channel.

The board at a glance

Columns not in this table (backlog states like Idea, Researching, Designed, and terminal states like Archived, Canceled) are unmanaged — the orchestrator ignores them.

A ticket’s life, step by step

1. Planning

Drag a ready ticket from Todo → Planning. The primary agent is @mentioned and will:
  1. Read AGENTS.md / CLAUDE.md and draft a plan as a checklist of build steps in the issue description. It’s told to keep scope tight — build exactly what’s asked, reuse existing helpers rather than duplicate, and avoid premature abstraction. If it needs a decision from you it asks in a comment and stays in Planning until you answer; otherwise it produces a self-contained plan.
  2. Run a conflict check. It lists every other in-flight ticket (Planning through Review) and, for those with a PR, compares changed files against what this ticket will touch. If there’s material overlap that would cause a merge conflict, it marks this issue blocked by that ticket, explains which files collide, and moves the card to Blocked (see below).
  3. Run a regression check. It assesses the blast radius — which existing behavior, public APIs, shared modules, or downstream callers the change could break — and lists each risk with how it’ll be guarded.
This is the stage to argue about what and how before any code exists.

2. Discussion

When the planner finishes its turn, the ticket advances to Discussion automatically — you don’t drag it (a planner that asked you a question stays in Planning until you reply). The orchestrator then posts one review request per configured reviewer, each with a distinct lens so you get complementary critiques instead of the same note twice:
  • an architecture & scope lens (fit with existing patterns, scope creep, duplication, simpler/alternative approaches), and
  • a correctness & risk lens (edge cases, concurrency, security, performance, test gaps, and regressions / breaking changes / affected consumers).
Reviewers are asked to comment only, not take the ticket — if a reviewer agent assigns the issue to itself, the orchestrator reverts the assignee automatically. After the fan-out, the primary is asked to reply to each critique and revise the plan, weighing feedback on its merits (it owns the decision — this avoids design-by-committee). New comments from reviewers or teammates on a managed issue are relayed to the primary so it keeps responding to feedback through the discussion.

3. Execution

Drag Discussion → Execution. The primary implements the plan by running two sub-agents in parallel: an implementer writing production code and a test author writing unit tests / scenarios / e2e (including regression tests for the behavior the change touches). They keep implementation and test files disjoint so the two streams don’t collide, then reconcile and get the suite green before opening the PR.
If a card reaches Execution while it still has unresolved blockers, the orchestrator bounces it back to Blocked rather than letting conflicting work proceed.

4. Testing

Drag Execution → Testing. The orchestrator inspects the PR’s changed files and routes to the right tester:
  • touches Mac-only surfaces (native audio, GL/WebGPU, the real Tauri app, plugin editors) → the Mac agent (Studio Claude), which can drive real hardware and capture screenshots;
  • otherwise → the default headless agent.
The tester runs ./utils/validate, the relevant scenario, and headless e2e / agent-browser as needed, then uploads screenshots to the issue.

5. Review

Drag Testing → Review. The primary opens the PR with verify-and-ship, gets CI green, auto-reviews, and is asked to call out any breaking or behavior changes in the PR description so they’re visible before merge.

6. Merged

Drag Review → Merged when you’re satisfied. This is a manual gate — the orchestrator merges the linked PR only if GitHub already considers it mergeable:
  • a required (blocking) check failing or incomplete, merge conflicts, a branch behind base, or a draft → the card is bounced back to Review with the reason, and nothing is merged;
  • only non-required (non-blocking) checks pending or failing → still merges (a non-blocking check isn’t a blocker);
  • clean and mergeable → merged via gh, with the result commented on the issue.
The orchestrator never enables GitHub auto-merge — the card drag is the merge action.

Blocked tickets & conflict avoidance

The whole point of the Planning conflict check is to keep two agents from editing the same files on parallel branches and creating merge hell. When a conflict is found:
  1. The ticket is marked blocked by the conflicting ticket (a Linear relation), and the card moves to the Blocked column.
  2. It sits in Blocked — a no-op holding pen — doing nothing.
  3. When the blocker merges, the orchestrator automatically moves the dependent back to Planning (not straight to Execution) with a note to rebase onto the latest and confirm the plan still holds — because the merge may have changed the very code it conflicts on.
You can also set a blockedBy relation yourself; the same enforcement applies.

Status labels

Independently of the columns, the orchestrator keeps a status label on every issue with an active agent session, polled every 30s:
  • Working — the agent is actively working.
  • Needs Input — the agent is waiting on you (a question, an approval).
Watch for Needs Input to know when a ticket needs your attention.

The prompts

Every action above is a comment built from a prompt template. Most are tunable in the orchestrator’s config.toml under [prompts] (planning, discussion, execution, testing, review, relay) and per-reviewer prompt fields — no code change needed. A few (the Blocked/Merged notes and the bounce/unblock status lines) live in code. The canonical list of every template is kept on the TIV-69 issue; propose wording changes there.

Working with it: practical tips

  • Move cards forward to make things happen; move them back freely to fix things. Backward moves never re-trigger a phase.
  • Talk to the agent in the issue thread. During Planning/Discussion it’s watching your comments and will respond. Be specific.
  • Don’t drag straight to Merged to “save time.” It only merges a clean PR; a half-done one just bounces back to Review.
  • If a ticket is parked in Blocked, don’t force it to Execution — it’ll bounce. Let the blocker merge (it auto-returns to Planning) or resolve the blockedBy relation.
  • Reviewers advise; the primary decides. If you disagree with the synthesis, say so in the thread — the primary will re-weigh.

Where the automation lives (for the curious)

Implementation details, configuration, and deployment all live in that repo’s README and config. This page is the developer-facing “how the board behaves” guide; the orchestrator repo is the “how it’s built” guide.