Sketch of a Claude Code port of openai/symphony — a daemon-style orchestrator that polls an issue tracker, dispatches isolated worker agents per issue, and reconciles state across ticks. Tracker-agnostic by design: the project's CLAUDE.md documents how to talk to whatever tracker is in use (GitHub Issues, Gitea, tracker CLI, Linear, etc.); the plugin reads those instructions rather than shipping per-tracker adapters. Includes: - /symphony-init for first-time setup (detects gh/gitea/tracker, writes the tracker section into project CLAUDE.md, drops WORKFLOW.md, offers to schedule the tick) - /symphony-tick fired by /schedule cron entries (idempotent, silent, never prompts) - per-issue worker agent in isolated worktrees - on-disk state in .symphony/state.json (survives cron cold starts) Known divergences from the spec are documented in the plugin CLAUDE.md (no streaming agent telemetry; no codex.* knobs; hooks run inside the worker rather than the orchestrator). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
126 lines
5.8 KiB
Markdown
126 lines
5.8 KiB
Markdown
---
|
|
name: symphony-init
|
|
description: First-time setup for the Symphony plugin in a project. Detects the issue tracker, writes a tracker integration section into the project's CLAUDE.md, drops a starter WORKFLOW.md, and optionally schedules the orchestrator tick. Use when the user runs /symphony-init or asks to "set up Symphony" / "configure Symphony for this repo". Idempotent — re-running detects existing config and offers updates rather than overwriting.
|
|
---
|
|
|
|
# Symphony — project initialization
|
|
|
|
You are running an interactive setup. The user wants Symphony configured for this repo
|
|
with as little hand-holding as possible. **Detect first, ask second.** Never ask a
|
|
question you can answer by probing the environment.
|
|
|
|
## Detection pass (silent, no questions)
|
|
|
|
Run these checks in parallel before asking anything:
|
|
|
|
### Tracker probes
|
|
- `gh auth status` exit 0 → GitHub Issues available. Run `gh repo view --json nameWithOwner`
|
|
to record the repo.
|
|
- `mcp__gitea__get_me` reachable → Gitea MCP available. Note the user's orgs.
|
|
- `[ -d .tracker ] && [ -f .tracker/config.toml ]` → local `tracker` CLI is in use.
|
|
The `tracker-usage` skill is the canonical reference.
|
|
- `[ -f .linear/config ]` or `LINEAR_API_KEY` set → Linear configured.
|
|
|
|
If exactly one tracker is detected, default to it and confirm with the user before
|
|
writing. If multiple, list them and ask. If none, ask which the project will use.
|
|
|
|
### Existing-config probes
|
|
- `[ -f ./WORKFLOW.md ]` → already initialized at least partially. Read it; show the
|
|
user a diff of proposed changes rather than overwriting.
|
|
- `[ -f ./CLAUDE.md ]` and grep for an existing `## Issue tracker` (or similar)
|
|
section → don't duplicate; offer to update in place.
|
|
- `[ -d .symphony ]` → state directory already exists; leave it alone.
|
|
- `cron list` (via `/schedule`) → check whether `/symphony-tick` is already scheduled.
|
|
|
|
### Project shape probes (used to prefill WORKFLOW.md hooks)
|
|
- `package.json` → `npm install` in `before_run`.
|
|
- `pyproject.toml` → `uv sync` in `before_run`.
|
|
- `Cargo.toml` → `cargo fetch`.
|
|
- `go.mod` → `go mod download`.
|
|
- Default branch name from `git symbolic-ref refs/remotes/origin/HEAD`.
|
|
|
|
## Interview (only what detection couldn't answer)
|
|
|
|
Ask in one batch where possible. Suggested order:
|
|
|
|
1. **Tracker** — only if detection didn't yield exactly one. Prefer
|
|
`AskUserQuestion` so the user picks from a list.
|
|
2. **Active states** — names used for "ready to be picked up" issues.
|
|
Suggest defaults per tracker:
|
|
- github: `open` (filtered by label `ready` or `in-progress` if the user uses labels)
|
|
- gitea: `open`
|
|
- tracker: read from `.tracker/config.toml` if present
|
|
- linear: `Todo`, `In Progress`
|
|
3. **Terminal states** — names that mean "done, don't touch". Defaults:
|
|
- github / gitea: `closed`
|
|
- linear: `Done`, `Cancelled`, `Duplicate`
|
|
4. **Concurrency cap** — default `3`. Mention the user can change this in WORKFLOW.md
|
|
later without re-running init.
|
|
5. **Branch naming** — pattern for worker branches. Default
|
|
`{{ issue.identifier }}` (or `issue-{{ issue.id }}` if the tracker has no
|
|
human identifier).
|
|
6. **Schedule cadence** — default every 5 minutes. Offer to skip and have the user
|
|
run `/symphony-tick` manually.
|
|
|
|
Keep the interview short. Anything that has a sensible default should default.
|
|
|
|
## Write phase
|
|
|
|
1. **Tracker section in `./CLAUDE.md`** — append (or update in place if it already
|
|
exists) a section under heading `## Issue tracker` documenting:
|
|
- Which tracker the project uses.
|
|
- The exact commands to **list active issues**, **get one issue**, **transition
|
|
state**, and **comment on an issue**. Use real commands the worker can run, not
|
|
descriptions. Examples:
|
|
|
|
```markdown
|
|
## Issue tracker
|
|
|
|
This project uses GitHub Issues (repo: `acme/widgets`). Symphony workers should:
|
|
|
|
- **List active**: `gh issue list --repo acme/widgets --state open --json number,title,body,labels,state,updatedAt`
|
|
- **Get one**: `gh issue view <number> --repo acme/widgets --json state,title,body,labels`
|
|
- **Transition**: we use labels — `gh issue edit <number> --repo acme/widgets --add-label in-review --remove-label ready`
|
|
- **Comment**: `gh issue comment <number> --repo acme/widgets --body "..."`
|
|
|
|
Active label set: `ready`, `in-progress`. Terminal: closed issues.
|
|
```
|
|
|
|
If the project's CLAUDE.md doesn't exist yet, create it with just this section.
|
|
Do not invent other content.
|
|
|
|
2. **`./WORKFLOW.md`** — copy from the plugin's `templates/WORKFLOW.md`, with
|
|
detected values substituted (tracker.kind, active_states, terminal_states,
|
|
concurrency cap, hook commands appropriate to the project's build system).
|
|
If a `WORKFLOW.md` already exists, show the diff and ask before overwriting.
|
|
|
|
3. **`.symphony/`** — create the directory with an empty `state.json`:
|
|
`{ "running": {}, "retry_attempts": {}, "claimed": [], "completed": [], "totals": { "ticks": 0 } }`.
|
|
|
|
4. **`.gitignore`** — append `.symphony/state.json` and `.symphony/logs/` if not
|
|
already ignored. The state file is local-runtime, not source.
|
|
|
|
## Schedule offer
|
|
|
|
If the user opted in to scheduling, invoke the `schedule` skill to create a routine
|
|
that fires `/symphony-tick` at the chosen cadence. Confirm with the user before
|
|
creating; do not silently schedule.
|
|
|
|
## Final summary
|
|
|
|
End with a 4-line summary:
|
|
|
|
```
|
|
Tracker: github (acme/widgets)
|
|
Workflow: ./WORKFLOW.md (3 concurrent, retry cap 10m)
|
|
Schedule: /symphony-tick every 5m (cron id: <id>)
|
|
Next: run /symphony-tick once now to verify, or wait for cron
|
|
```
|
|
|
|
## Re-run behavior
|
|
|
|
If `WORKFLOW.md` and a CLAUDE.md tracker section both already exist:
|
|
- Detect drift (e.g. user changed tracker, repo moved orgs).
|
|
- Show what would change. Apply only with confirmation.
|
|
- Never delete `.symphony/state.json` — losing it strands in-flight workers.
|