npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ghostlygawd/symphony

v0.1.0

Published

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

Downloads

43

Readme

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:

  1. Reloads WORKFLOW.md if it changed on disk (no restart needed).
  2. Reconciles running workers: stall detection + refresh each issue's tracker state (terminal → stop & clean up the workspace).
  3. Processes the retry queue: due continuations (1s after a clean finish) and exponential-backoff retries after failures.
  4. Validates config; if invalid it keeps reconciling but pauses dispatch and surfaces the error.
  5. 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

| Tracker | State lives in | Auth | Out of the box? | |----------|----------------|------|-----------------| | local (default) | Markdown files in .symphony/issues/ | none | ✅ yes | | github | GitHub issue + a status:<state> label | GITHUB_TOKEN | needs a token | | linear | Linear workflow states | LINEAR_API_KEY | needs 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 Symphony | This project | |---|---| | Coding agent: Codex app-server subprocess | Claude Code: claude -p --output-format stream-json | | Auth: Codex / API | Claude subscription via the CLI (no API key) | | Reference impl: Elixir/BEAM | Node.js (zero deps), tested with node --test | | Tracker: Linear | local (default) · GitHub · Linear | | linear_graphql client-side tool | agent 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.