Sign In

@ghostlygawd/symphony

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ghostlygawd/symphony

Claude Code-native orchestration: turn an issue tracker into autonomous, isolated implementation runs. Runs on a Claude subscription — no API key required.

latest
Source
npmnpm
Version
0.1.0
Version published
Weekly downloads
2
100%
Maintainers
1
Weekly downloads
 
Created
Source

Symphony

Claude Code-native orchestration — turn an issue board into autonomous, isolated implementation runs.

Symphony watches an issue tracker, gives every open task its own isolated workspace and a Claude Code agent, lets those agents work autonomously, and surfaces the results for you to review. You manage work, not coding agents.

It runs on your Claude subscription through the claude CLI you already use. No ANTHROPIC_API_KEY required.

This is an independent, Claude-native implementation of the open-source Symphony spec (originally published by OpenAI for Codex, Apache-2.0). It is not affiliated with OpenAI or Anthropic. See NOTICE.

Why

The original Symphony is an orchestration spec: Linear is the state machine, the coding agent is the worker, PRs are the output. Symphony polls the board, spins up an isolated run per ticket, restarts agents that crash, and keeps going until the work leaves the active states.

This implementation keeps that model but is built for Claude Code:

  • 🎫 Subscription-native. It drives the same claude CLI you use interactively, so it authenticates with your Pro/Max subscription. The init event literally reports apiKeySource: "none". No API keys, no separate billing.
  • 📦 Ships and runs out of the box. Zero runtime dependencies. npx-able. A built-in local file tracker means you can go from clone to a running orchestrator in under a minute with nothing but Claude Code installed.
  • 🧩 Faithful to the spec. Workflow loader (WORKFLOW.md), polling orchestrator with bounded concurrency, per-issue workspaces with lifecycle hooks, exponential-backoff retries, stall detection, tracker-state reconciliation, dynamic reload, and an optional status dashboard.
  • 🔌 Pluggable trackers. Local Markdown board (default), GitHub Issues, or Linear.

Quickstart

Prerequisites: Node.js ≥ 18 and Claude Code installed and logged in (claude auth login).

Once published, the fastest path is npx — no clone, no install:

# 1. Scaffold a board + WORKFLOW.md in your project
cd /path/to/your/project
npx @ghostlygawd/symphony init

# 2. Check your environment (Claude Code present? logged in? config valid?)
npx @ghostlygawd/symphony doctor

# 3. Run it — opens a live dashboard at http://127.0.0.1:4173
npx @ghostlygawd/symphony start --port 4173

Prefer to run from a clone of this repo:

# 1. Get Symphony (from this repo)
git clone https://github.com/ghostlygawd/symphony-clone.git
cd symphony-clone
npm link            # makes the `symphony` command available (optional)

# 2. Scaffold a board + WORKFLOW.md in your project
cd /path/to/your/project
symphony init

# 3. Check your environment (Claude Code present? logged in? config valid?)
symphony doctor

# 4. Run it — opens a live dashboard at http://127.0.0.1:4173
symphony start --port 4173

No global install? Run it directly:

node /path/to/symphony-clone/bin/symphony.js start --port 4173

That's it. Symphony will pick up every Todo issue from .symphony/issues/, give each its own workspace and a Claude Code agent, and run them in parallel. Edit an issue's state: (or let the agent do it) to move it through your workflow.

See it work in one shot

symphony start --once runs a single tick, lets the dispatched agents finish, and prints a snapshot — perfect for trying it out or for CI/cron:

symphony start --once

This is exactly the flow used to verify Symphony end-to-end: a real Claude Code agent picked up SYM-1, created WELCOME.md in its isolated workspace, transitioned the issue to In Review, and the orchestrator recorded the token usage and cost — all on a subscription with no API key.

How it works

                         WORKFLOW.md  (YAML config + prompt template)
                              │  (hot-reloaded on change)
                              ▼
   ┌──────────────┐     ┌───────────────────────────────────────────────┐
   │ Issue tracker │◀────│                Orchestrator                    │
   │ local/github/ │     │  poll → reconcile → retry queue → dispatch     │
   │   linear      │────▶│  (bounded concurrency, stall detection)        │
   └──────────────┘     └───────────────┬───────────────────────────────┘
        ▲  state                          │ one worker per issue
        │  transitions                    ▼
        │                       ┌──────────────────────┐
        │                       │   Workspace Manager   │  per-issue dir +
        │                       │  after_create/before_ │  lifecycle hooks
        │                       │  run/after_run hooks   │
        │                       └──────────┬────────────┘
        │                                  ▼
        │                       ┌──────────────────────┐  claude -p
        └───── agent edits ─────│   Claude Code agent   │  --output-format
            board / opens PR    │  (subscription auth)  │  stream-json
                                └──────────────────────┘

Each tick the orchestrator:

  • Reloads WORKFLOW.md if it changed on disk (no restart needed).
  • Reconciles running workers: stall detection + refresh each issue's tracker state (terminal → stop & clean up the workspace).
  • Processes the retry queue: due continuations (1s after a clean finish) and exponential-backoff retries after failures.
  • Validates config; if invalid it keeps reconciling but pauses dispatch and surfaces the error.
  • Fetches candidates and dispatches eligible issues within the concurrency limits.

A worker, in turn, creates the workspace, runs before_run, then runs Claude Code turn-by-turn (resuming the same session for continuations) — re-checking the tracker between turns — until the issue leaves the active states or max_turns is hit.

Handoff, not "Done". A successful run typically ends at a review state (e.g. In Review), not Done. The agent does the work and hands it back to a human. Symphony stops working an issue the moment it leaves the active states.

Configuration: WORKFLOW.md

A single Markdown file with YAML front matter (the config) and a Markdown body (the prompt template). The full default is created by symphony init; here's the shape:

---
tracker:
  kind: local                       # local | github | linear
  dir: .symphony/issues
  active_states: [Todo, "In Progress"]
  terminal_states: [Done, Cancelled]

polling:
  interval_ms: 10000

workspace:
  root: .symphony/workspaces

hooks:
  after_create: |                   # runs once when a workspace is created
    [ -n "$SYMPHONY_PROJECT_DIR" ] && cp -R "$SYMPHONY_PROJECT_DIR"/. .
  before_run: |                     # runs before each agent attempt
    npm install
  timeout_ms: 120000

agent:
  max_concurrent_agents: 3
  max_turns: 8
  permission_mode: bypassPermissions   # full autonomy (sandboxed envs only)

claude:
  command: claude
  # model: sonnet
  stall_timeout_ms: 300000
---
You are an autonomous engineer working on {{ issue.identifier }}: {{ issue.title }}.

{{ issue.description }}
{% if attempt %}This is a continuation (turn {{ attempt }}).{% endif %}

When finished, edit `{{ issue_file }}` and set its `state:` to `In Review`, then stop.

The prompt template supports {{ variable }}, {% if %}/{% elsif %}/{% else %}, {% for x in list %}, and filters (default, upcase, downcase, join, length, truncate). Available variables: issue (all fields + labels/blocked_by), attempt, turn, max_turns, issue_file, board_dir, project_dir.

Run symphony validate to check it. See docs/configuration.md for every setting and default.

Context your hooks and agents get

Every hook and agent run is given these environment variables: SYMPHONY_ISSUE_ID, SYMPHONY_ISSUE_IDENTIFIER, SYMPHONY_ISSUE_TITLE, SYMPHONY_ISSUE_STATE, SYMPHONY_ISSUE_FILE, SYMPHONY_BOARD_DIR, SYMPHONY_PROJECT_DIR, SYMPHONY_WORKSPACE.

Trackers

TrackerState lives inAuthOut of the box?
local (default)Markdown files in .symphony/issues/none✅ yes
githubGitHub issue + a status:<state> labelGITHUB_TOKENneeds a token
linearLinear workflow statesLINEAR_API_KEYneeds a key

With the local tracker, each issue is a Markdown file with front matter (identifier, title, state, priority, labels, blocked_by) and a Markdown body (the description). State transitions are just edits to state: — which the agent performs as part of its run. Fully local, no external service. See docs/trackers.md.

All three trackers can transition an issue, not just read it: the agent (or symphony move) swaps a GitHub status:<state> label and closes/reopens the issue, or moves a Linear workflow state. For a real-repo clone → branch → PR workflow driven by GitHub Issues, see the worked example in examples/github-pr/.

Authentication: subscription, not API key

Symphony never asks for an API key. It launches claude exactly as you would interactively, so it uses whatever the CLI is logged in with:

  • Recommended: a Claude Pro/Max subscription via claude auth login (or claude setup-token).
  • If ANTHROPIC_API_KEY happens to be set in your environment, Claude Code will use it (API billing). To force subscription usage, unset it — or set claude.unset_api_key: true in WORKFLOW.md and Symphony will drop it for the agent processes.

symphony doctor tells you which mode you're in. More in docs/claude-code.md.

Safety & the trust boundary

Autonomous agents that edit files and run commands are powerful — and a footgun outside a sandbox. Symphony makes the trust boundary explicit:

  • permission_mode: acceptEdits (the code default) auto-accepts file edits but limits command execution.
  • permission_mode: bypassPermissions gives the agent full autonomy (the default in the scaffolded WORKFLOW.md). Use it only in isolated/sandboxed environments — containers, CI runners, VMs, or throwaway machines. When Symphony runs as root in a container it automatically sets IS_SANDBOX=1 so this works.
  • Workspaces are always per-issue, name-sanitized, and confined under workspace.root; the agent's working directory is validated before launch.
  • Secrets use $VAR indirection and are never logged.

Recommended hardening: run Symphony in a container with scoped credentials and a restricted network, filter which labels/projects are eligible, and keep max_concurrent_agents sane for your budget.

Run in a container (sandboxed)

The repo ships a Dockerfile and docker-compose.yml so you get that sandbox out of the box — Node 22, the Claude Code CLI, and Symphony, with IS_SANDBOX=1 set so bypassPermissions is honored safely inside the container:

# Mounts the current repo into /work and your Claude login (read-only)
docker compose up            # dashboard at http://127.0.0.1:4173

Use your Claude subscription (mount ~/.claude read-only or claude setup-token); keep ANTHROPIC_API_KEY unset. Full guide — credentials and network-egress posture — in docs/sandbox.md.

Commands

symphony init [dir]      Scaffold WORKFLOW.md + an example local board
symphony start           Run the orchestrator (poll the tracker, dispatch agents)
  --port <n>               Serve the live dashboard
  --host <addr>            Dashboard bind address (default 127.0.0.1; non-loopback requires a token)
  --once                   Run a single tick, wait for workers, print a snapshot, exit
  --verbose                Debug logging
symphony status          Show a runtime snapshot (from a running server, or one-shot)
symphony validate        Load and validate WORKFLOW.md
symphony doctor          Check your environment (Claude Code, auth, config)
symphony move <id> <st>  Transition an issue's state — local, github, or linear (handoff helper)
symphony version | help
  --workflow <path>        Use a specific WORKFLOW.md (default ./WORKFLOW.md)

Watch it from your phone. Set SYMPHONY_DASHBOARD_TOKEN (or server.auth_token in WORKFLOW.md) to put a login on the dashboard, then expose 127.0.0.1:4173 through a tunnel (ngrok / Cloudflare / Tailscale) and open https://<tunnel-url>/?token=YOUR_TOKEN. Symphony refuses to bind a non-loopback address without a token. Full recipe: docs/remote-access.md.

How this maps to OpenAI's Symphony

OpenAI SymphonyThis project
Coding agent: Codex app-server subprocessClaude Code: claude -p --output-format stream-json
Auth: Codex / APIClaude subscription via the CLI (no API key)
Reference impl: Elixir/BEAMNode.js (zero deps), tested with node --test
Tracker: Linearlocal (default) · GitHub · Linear
linear_graphql client-side toolagent edits the board via an auto --add-dir, or symphony move
WORKFLOW.md, polling loop, concurrency, retries, stall detection, reconciliation, dynamic reload, snapshot API✅ all implemented

See SPEC.md for the Claude-native specification.

Development

npm test          # run the full suite (node --test), zero dependencies

The suite is the gate. A git pre-push hook (.githooks/pre-push) runs node --test before every push and blocks on failure; npm install wires it automatically (or run git config core.hooksPath .githooks once). GitHub Actions (.github/workflows/test.yml) is manual-only (Actions-minutes), triggerable from the Actions tab.

The codebase is small and readable: src/yaml.js (mini YAML), src/workflow.js (config), src/template.js (prompt rendering), src/trackers/*, src/workspace.js, src/agent/claude.js (the Claude Code adapter), src/runner.js, src/orchestrator.js, src/server.js, src/cli.js.

Roadmap

The original follow-up backlog — GitHub & Linear state-transition write paths, a real-repo clone→branch→PR example, a publishable npx release, a sandboxed container image, and a gated live test (BL-1…BL-6) — is now implemented. See docs/BACKLOG.md for per-item status and the remaining nice-to-haves (durable runtime state, per-issue cost caps, webhook-driven polling, dashboard per-issue drill-down).

License

Apache-2.0. Not affiliated with OpenAI or Anthropic; see NOTICE.

Keywords

claude

FAQs

Package last updated on 31 May 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts