Skip to content

Agent Types

Symphony dispatches four agent types, each with a specialized role. Agents are Claude CLI subprocesses that communicate with Symphony through MCP tools over stdio.

Phase-Aware Dispatch

Agents are dispatched based on both their profile (capability) and the issue's current phase (assignment mode):

Phase LabelDispatched ProfileBehavioral Contract
phase:researchresearcherprompts/phases/research.md
phase:architectureresearcherprompts/phases/architecture.md
phase:groomingplannerprompts/phases/grooming.md
phase:readyworkerprompts/phases/ready.md

Profile = capability (what kind of agent). Phase = assignment mode (what artifact to produce). The phase contract defines the behavioral mode, not the agent type alone. A researcher dispatched for phase:architecture behaves differently than one dispatched for phase:research, because each receives a different contract.

Write Permissions by Phase

Pre-ready agents have restricted write access enforced via phase contract prompts:

PhaseMay WriteMay NOT Write
phase:researchdocs/tickets/<ID>/research.md, findings/commentsSource code, app/, server/, tests/
phase:architecturedocs/tickets/<ID>/design.md, findings/commentsSource code, app/, server/, tests/
phase:groomingdocs/tickets/<ID>/grooming.md, findings/commentsSource code, app/, server/, tests/
phase:readyAny file in the worktree, PRsN/A (full access)

Worker

The default agent type. Workers implement issues — writing code, running tests, and creating PRs.

Trigger: todo issues with phase:ready label (or no phase label in migration mode), resolved dependencies, no needs-planning label.

Lifecycle:

  1. Orchestrator creates a git worktree and sets issue to in_progress
  2. Worker reads the issue, plans an approach, implements changes
  3. Worker runs quality gate commands (tests, build, lint)
  4. Worker commits changes and calls create_pr with diff and gate results
  5. Issue moves to review

On failure: Retried up to max_retries times with exponential backoff. After max retries, moved to backlog.

On exit without status change: Treated as a continuation — retried with context from previous attempts.

Prompt: prompts/profiles/worker.md + prompts/phases/ready.md

Key behaviors

Workers follow a six-phase session model: Orient (read issue + prior findings/learnings) → Plan (decide approach, list files) → Implement (write code with tests) → Validate (run full test suite + build/lint) → Commit (git add -A && git commit) → Report (create_pr, add_finding, add_learning).

Hard constraints:

  • Never remove tests that cover unique behavior — fix the code, not the test. Consolidating redundant tests into parameterized equivalents is encouraged.
  • Never remove existing features — only implement the assigned issue
  • Must run the full test suite, not just related tests
  • Must commit; changes in the worktree are lost without a commit
  • No external research (no WebSearch/WebFetch) — the implementation plan is already approved

Error recovery:

  • Test failure: check if pre-existing (git stash && test && git stash pop); if caused by your change, fix the code
  • Stuck after 2+ attempts: commit partial work with wip: prefix, add a gap finding with root-cause theory, set status to todo
  • Merge conflict: git fetch origin main && git rebase origin/main; complex conflicts → commit, add finding, set todo
  • Flaky test: run again to confirm; if non-deterministic, add finding and proceed

Judge

Reviews PRs created by workers. Judges are autonomous — they approve, reject, or block.

Trigger: Issues in review status with an open PR, respecting a 5-minute cooldown between judge attempts.

Lifecycle:

  1. Orchestrator dispatches judge with the PR diff included in the prompt
  2. Judge reads the issue requirements and reviews the diff
  3. Judge runs quality gate commands to verify
  4. Judge calls one of:
    • approve_pr — PR is approved, issue stays in review for human merge
    • reject_pr — PR is rejected, issue returns to todo for rework
    • update_issue_status to blocked — needs human input

On exit without calling a tool: Left in review for retry. The judge's text output alone is not recorded as a decision — only MCP tool calls count.

Cooldown: 5 minutes between judge attempts per issue. Only counts judge profile runs, not worker runs.

Phase review: When reviewing phase artifacts (not PRs), the judge receives approve_phase and reject_phase tools instead of approve_pr/reject_pr. The MCP config is context-aware.

Prompt: prompts/profiles/judge.md

Key behaviors

The judge approves only when quality gates are green and the code fulfils the documented requirements. Both conditions must hold — a passing gate alone is not sufficient if requirements are unmet, and met requirements do not override failing gates.

Context sections provided to the judge (in addition to the diff):

  • Change Summary — file-level stats (files changed, insertions, deletions per file)
  • Risk Assessment — risk level, line/file counts, sensitive paths touched
  • Worker's Approach — the worker's implementation finding (what they did and why)
  • Gate Results — test/lint/build pass-fail status

Each section degrades gracefully if unavailable. The diff, description, and previous output each have separate context-budget allocations; all three are truncated proportionally before any one is dropped entirely.

Must-call-tool rule: The judge's text output is never recorded as a decision. Only MCP tool calls count. If the judge exits without calling a verdict tool, the issue stays in review for retry after the 5-minute cooldown.

Planner

Decomposes complex issues into smaller, independent sub-tasks. Disabled by default.

Trigger: todo issues with needs-planning label or large size (when plannerEnabled is true in project config).

Lifecycle:

  1. Orchestrator dispatches planner for the complex issue
  2. Planner reads the issue and project context
  3. Planner creates 2-6 sub-tasks using create_subtask
  4. Parent issue is set to blocked until all sub-tasks are done
  5. When all sub-tasks complete, parent auto-unblocks to todo

Rules:

  • Planners do NOT write code — they only create sub-tasks
  • Each sub-task should be completable in a single worker session
  • Sub-tasks should include specific file paths and acceptance criteria

Phase dispatch: Also handles phase:grooming tickets via the grooming contract, producing task breakdowns as artifacts.

Prompt: prompts/profiles/planner.md (+ prompts/phases/grooming.md for phased tickets)

Key behaviors

  • Minimum one sub-task required: A planner that exits without calling create_subtask is considered a failure and is added to the retry queue with reason planner-no-subtasks. If the issue doesn't need decomposition, it should not have the needs-planning label.
  • Parent blocking: The parent issue is automatically set to blocked when the first sub-task is created. It auto-unblocks to todo when all children reach done.
  • Sub-task constraints: Each sub-task should be completable in a single worker session and should include specific file paths and acceptance criteria.
  • Dispatch exclusion: When plannerEnabled is true, issues with needs-planning or size large are removed from the worker dispatch queue entirely — workers cannot claim them until decomposition completes.

Scanner

Scans the codebase for improvements and creates backlog items. Disabled by default.

Trigger: Runs as a background agent when:

  • No todo items are waiting
  • Backlog has fewer than 10 items
  • Configured interval has elapsed (default: 10 minutes)

Lifecycle:

  1. Orchestrator creates a temporary worktree for the scanner
  2. Scanner scans the codebase for gaps, tech debt, missing tests, etc.
  3. Scanner checks existing issues to avoid duplicates
  4. Scanner creates backlog items using create_issue
  5. Worktree is cleaned up on exit (scanner doesn't produce code)

What the scanner looks for:

  • Missing tests or low coverage
  • TODOs, FIXMEs, HACKs in code
  • Error handling gaps
  • Performance issues
  • Security concerns
  • Documentation gaps
  • Dead code or unused dependencies

Config toggle: scannerEnabled in project config (default: false).

Prompt: prompts/profiles/scanner.md

Key behaviors

  • No auto-commit: Scanners do not commit to git. All output is recorded via MCP tools (create_issue, add_finding, add_learning).
  • Duplicate prevention: Before creating a backlog item, the scanner calls list_issues to check for existing coverage.
  • Worktree cleanup: The temporary worktree is removed on exit; no code artifacts are left behind.

Researcher

A phase agent dispatched to tickets in phase:research or phase:architecture. Unlike the Scanner, the Researcher works on an assigned ticket and produces a required artifact before the ticket can advance.

Trigger: Dispatched by the orchestrator when a ticket carries a phase:research or phase:architecture label and the researcherEnabled toggle is on in project config.

Lifecycle:

  1. Orchestrator dispatches the researcher with the phase contract in the prompt
  2. Researcher reads the issue, explores relevant code, and gathers context
  3. Researcher produces the required artifact (docs/tickets/<ID>/research.md or design.md)
  4. Researcher calls complete_phase — orchestrator validates the artifact and advances the phase label

Key distinction from the Scanner: The Researcher is ticket-bound and contract-bound. It works in a worktree scoped to a specific issue and must deliver a structured artifact with required sections. The Scanner has no assigned ticket, no required artifact, and only creates backlog items.

Config toggle: researcherEnabled in project config.

Prompt: prompts/profiles/researcher.md (+ prompts/phases/research.md or prompts/phases/architecture.md)

Key behaviors

For phase:research — the researcher produces docs/tickets/<ID>/research.md. Required sections are defined by the research phase contract. On calling complete_phase, the orchestrator validates the artifact and advances the label to phase:architecture (or skips ahead for simple tickets via skip_to).

For phase:architecture — the researcher acts as the Architect: synthesizes research into a concrete design doc (docs/tickets/<ID>/design.md) with 6 required sections (Problem, Proposed Approach, Alternatives Considered, Impacted Components, Risks, Rollout). Architecture completion is judge-gated before advancing to phase:grooming.

Design principles applied in architecture mode: simplicity first, incremental delivery, separation of concerns, backward compatibility (use safeAlterTable for schema changes), testability.

Tool restrictions (architecture mode): read-only access to source code; may only write to docs/tickets/<ID>/. Cannot call status, PR, or subtask tools.

External research: If externalResearch is enabled in project config, the researcher may use WebSearch/WebFetch (default max 5 searches per session) to verify library health, check for breaking changes, or find canonical pattern implementations. Safety rule: never search for credentials, keys, or internal URLs.

Idle-only dispatch (scanner mode vs. researcher mode applies only to the Scanner profile; the Researcher profile is dispatched whenever a phase:research or phase:architecture ticket exists, regardless of backlog size).

Setup Wizard

A special agent that runs once per project on first detection. Not a regular dispatch type.

Trigger: New project detected without wizardCompleted or wizardFailed in config.

Lifecycle:

  1. Orchestrator dispatches wizard to analyze the project
  2. Wizard reads project structure, configs, and conventions
  3. Wizard calls configure_project to set quality gates, sensitive paths, and risk thresholds
  4. On success, wizardCompleted is set in project config
  5. On failure, wizardFailed is set to prevent retry loops

Agent Profiles

Agent behavior is customizable through the agent_profiles table:

FieldPurpose
typeplanner, worker, judge, researcher, or custom
systemPromptCustom instructions appended to the default prompt
modelOverride model (null = use project/global default)
projectIdScope to a specific project (null = global default)
isDefaultWhether this is the default profile for its type

Default profiles are seeded on project detection. Per-project profiles override global defaults.

Concurrency and Slot Management

The orchestrator manages agent slots:

  • Global limit: max_concurrent_agents in symphony.config.json (0 = use CPU count)
  • Per-project limit: maxConcurrency in project config
  • Reserved slots: Judge agents get priority to prevent review starvation
  • Dispatch order: Setup Wizard (tier 0, before all else) → Judges → Phase agents → Workers/Planners/Researchers

Retry and Circuit Breaker

  • Max retries: Configurable per-project (default: 15)
  • Backoff: Exponential with configurable max (max_retry_backoff_ms)
  • Circuit breaker: After max retries, issue moves to backlog with a system comment
  • Total run tracking: Counts all runs (not just consecutive failures) to prevent runaway loops