Overview
The author plans a 1:1 port of the Elixir-based Symphony project to Python 3.12, using AgentScope as the agent foundation library. The source lives in ./symphony/ (Elixir) and the target in ./symphony.py/ (Python 3.12).
Key points
Module mapping (Elixir → Python)
Orchestrator→symphony.orchestrator.Orchestrator(asyncio)AgentRunner→symphony.agent_runner.AgentRunnerWorkflow→symphony.workflow.WorkflowLoader(loadsWORKFLOW.md)Config/Config.Schema→symphony.configwith Pydantic modelsLinear.Client/Linear.Issue→symphony.trackers.linear_client.LinearClientandsymphony.models.issue.Issue(Pydantic)Workspace,PromptBuilder,StatusDashboard,HttpServer(FastAPI),PathSafety,SSH,Tracker(base adapter),Codex.AppServer→ AgentScope client,Codex.DynamicTool→ Linear GraphQL tool- Python ^3.12, agentscope ^1.0, httpx ^0.27, FastAPI ^0.115, Pydantic ^2.9, pydantic-settings, Jinja2, APScheduler, rich, structlog, PyYAML, asyncssh, watchfiles, pytest-asyncio
- Functional: WORKFLOW.md parsing, Linear queries, workspace + hooks, multi-turn agent dispatch, retry/backoff, state reconciliation, live dashboard
- Performance: configurable polling (default 30s) and concurrency (default 10 agents), stable memory
- Quality: >90% type annotations, >80% test coverage, PEP8
- Risks: AgentScope API churn (lock versions), Linear API changes (isolate API layer), asyncio complexity (testing/review), SSH security (strict input validation)
Technology stack
AgentScope integration strategy
Because Symphony needs fine-grained control over agent lifecycle and Codex app-server interaction:
1. Use AgentScope low-level components (Msg, model wrappers, Toolkit)
2. Build a custom SymphonyAgent inheriting from AgentBase
3. Register linear_graphql as an AgentScope tool
4. Do not use the built-in ReActAgent directly — Symphony manages multi-turn dialogue and state itself
OTP → asyncio translation
| Elixir | Python | |--------|--------| | GenServer | asyncio + dataclass | | GenServer.call/cast | asyncio.Queue | | Process.monitor | asyncio.Task.add_done_callback | | Process.send_after | asyncio.call_later | | handle_info | message-handling coroutine |
Configuration schema (Pydantic)
Key models include TrackerConfig (Linear or in-memory tracker, endpoint, active/terminal states), PollingConfig (default 30s), WorkspaceConfig, HooksConfig (lifecycle hooks with 60s timeout), AgentConfig (max 10 concurrent agents, max 20 turns), CodexConfig (approval policy, sandboxing, timeouts), and ServerConfig — all composed into SymphonyConfig.
Orchestrator state machine
Dataclasses track RunningEntry (asyncio task, issue, workspace path, token counts, turn/retry counters), RetryEntry (backoff scheduling), and OrchestratorState (running/claimed/retry/completed sets plus Codex totals and rate-limit info), protected by an asyncio.Lock.
Implementation phases (9 stages)
1. Skeleton & config — project layout, pyproject.toml, Pydantic schema, WORKFLOW.md loader, unit tests
2. Trackers & models — Issue model, base tracker, Linear GraphQL client, in-memory tracker, pagination/normalization
3. Workspace — path safety, lifecycle manager, hooks, optional SSH remote workspaces
4. Agents & prompts — prompt builder, Linear GraphQL tool, ReAct-style agent, AgentScope client
5. Orchestrator core — state, dispatch, retry with backoff, reconciliation, polling loop
6. Dashboard & logging — structlog, rich-rendered terminal dashboard with live refresh and snapshots
7. Web API (optional) — FastAPI server with GET /api/v1/state, GET /api/v1/<issue_id>, POST /api/v1/refresh
8. CLI & integration — argument parsing, python -m symphony entry point, hot config reload, graceful shutdown
9. Testing & docs — >80% unit test coverage, architecture/configuration/API/deployment docs