HomePost

OpenAI Symphony를 Claude Code로 돌리기

2026-03-07

OpenAI의 코딩 에이전트 오케스트레이터 Symphony를 fork해서 Claude Code 백엔드를 추가한 이야기

Symphony가 뭔데

Symphony는 OpenAI가 만든 코딩 에이전트 오케스트레이터다. 쉽게 말하면, 이슈 트래커(Linear)에서 할 일을 가져와서 코딩 에이전트한테 자동으로 시키는 서비스다.

동작 방식은 이렇다:

  1. Linear에서 Todo 상태의 이슈를 폴링
  2. 이슈마다 격리된 워크스페이스(git clone)를 생성
  3. 워크스페이스 안에서 코딩 에이전트(Codex) 세션을 실행
  4. 에이전트가 구현 → PR → 리뷰 대기 → 머지까지 자율적으로 처리

팀은 코딩 에이전트를 감독하는 대신, 이슈 관리만 하면 된다. WORKFLOW.md라는 파일 하나로 에이전트의 행동 방침을 정의하고, 나머지는 Symphony가 알아서 돌린다.

문제는 이게 Codex 전용이라는 거다.

왜 Claude Code로 바꾸고 싶었나

요즘 에이전틱 코딩 워크플로우에 대한 관심이 많은데, 직접 처음부터 설계하는 것보다 잘 만들어진 레퍼런스를 기반으로 시작하는 게 훨씬 낫다. Symphony는 OpenAI가 직접 만든 거라 아키텍처 설계나 프로토콜 정의가 탄탄했다. 이슈 폴링, 워크스페이스 격리, 에이전트 라이프사이클 관리, 재시도와 백오프 — 이런 것들을 SPEC.md 하나에 깔끔하게 정리해놓은 게 인상적이었다.

나는 Claude Code를 주력으로 쓰고 있다. Codex도 써봤지만, 내 작업 흐름에서는 Claude Code가 더 맞았다. 그런데 이렇게 잘 정의된 에이전틱 워크플로우가 Codex 전용으로만 묶여 있는 게 아까웠다. Claude Code에서도 돌아가게 하면 좋겠다 싶었다.

거기에 하나 더, 원본 Symphony는 이슈 트래커로 Linear만 지원했는데, 나는 Linear를 쓰지 않는다. GitHub Issues로 충분한 상황에서 Linear를 따로 도입하고 싶지 않았다. 그래서 GitHub Issues를 트래커로 쓸 수 있게 이식하는 것도 목표 중 하나였다.

Symphony의 아키텍처를 보니 둘 다 가능하겠다 싶었다. SPEC.md에 정의된 프로토콜 자체가 범용적이었고, Codex에 강하게 결합된 부분만 분리하면 다른 에이전트도 끼울 수 있는 구조였다.

그래서 두 가지를 만들었다:

  1. symphony-claude: Claude Code를 Symphony 프로토콜로 감싸는 app-server
  2. Symphony fork: 멀티 백엔드를 지원하도록 개조한 오케스트레이터

symphony-claude: Claude Code의 app-server

Symphony가 코딩 에이전트와 통신하는 방식은 JSON-RPC 2.0이다. 스레드를 만들고, 턴을 시작하고, 결과를 스트리밍으로 받는 구조. Codex에는 이미 이 프로토콜을 구현한 app-server가 있는데, Claude Code에는 없었다.

sumansid/clode-app-server라는 프로젝트가 Claude Code를 JSON-RPC로 감싸는 기본 구현을 해놓은 게 있었다. 이걸 fork해서 Symphony의 Codex 프로토콜과 호환되도록 수정했다.

주요 변경 사항:

  • 파라미터 호환: threadId/thread_id 양쪽 다 받도록 (Codex는 camelCase 사용)
  • 응답 포맷 변경: { thread_id: "..." }{ thread: { id: "..." } } 중첩 구조
  • input 배열 지원: Codex 스타일의 input: [{ type: "text", text: "..." }] 처리
  • 토큰/비용 추적: 스트림 이벤트에서 토큰 사용량과 비용을 집계해서 turn/completed에 포함
  • 이벤트명 통일: turn/errorturn/failed 등 프로토콜 맞춤

설치

bash
brew tap sapsaldog/symphony
brew install symphony-claude

설치하면 symphony-claude 명령어가 생긴다. Claude Code CLI가 인증된 상태에서 실행하면 된다.

bash
# WebSocket 모드로 시작 (Symphony가 이걸로 연결)
symphony-claude start
 
# stdio 모드 (직접 파이프할 때)
symphony-claude

Symphony 멀티 백엔드 개조

원본 Symphony는 모든 게 Codex 중심이었다. 설정도 codex: 블록, 이벤트 파싱도 Codex 포맷 전용, 트래커도 Linear만 지원. 이걸 플러거블한 구조로 바꿨다.

코딩 에이전트 추상화

CodingAgent behaviour를 정의하고, Codex와 Claude를 각각 구현체로 분리했다.

text
lib/symphony_elixir/
├── coding_agent.ex          # behaviour 정의
├── codex/
│   ├── coding_agent.ex      # Codex 구현
│   ├── config.ex
│   └── event_humanizer.ex
├── claude/
│   ├── coding_agent.ex      # Claude 구현
│   ├── config.ex
│   └── event_humanizer.ex

CodingAgent behaviour는 start_session, run_turn, stop_session 세 개의 콜백을 정의한다. Codex든 Claude든 이 인터페이스만 맞추면 Symphony가 알아서 디스패치한다.

이슈 트래커 추상화

같은 패턴으로 TrackerConfig behaviour를 만들어서 Linear 외에 GitHub Issues도 지원하게 했다. GitHub Issues는 라벨 기반으로 상태를 관리한다 (symphony:todo, symphony:in-progress 등).

text
├── linear/
│   ├── client.ex
│   ├── config.ex
│   └── tracker.ex
├── github/
│   ├── client.ex
│   ├── config.ex
│   └── tracker.ex

Linear은 유료고 팀용이라 개인 프로젝트에서 쓰기엔 과한 면이 있는데, GitHub Issues면 누구나 바로 쓸 수 있다.

모듈 구조 정리

원래 모놀리식이던 Config 모듈을 백엔드별로 분리하고, 이벤트 정규화(normalize_event/1)와 휴먼라이징도 각 코딩 에이전트 모듈 안으로 옮겼다. 250줄 넘게 있던 포맷 스니핑 코드가 사라졌다.

설치 및 사용법

1. Symphony 설치

bash
brew tap sapsaldog/symphony
brew install symphony

Claude 백엔드를 쓸 거면 app-server도 설치:

bash
brew install symphony-claude

2. Claude Code CLI 인증

bash
claude auth

3. WORKFLOW.md 작성

프로젝트 루트에 WORKFLOW.md를 만든다. YAML front matter에 설정을, 본문에 에이전트 프롬프트를 적는다.

GitHub Issues + Claude Code 조합 예시:

yaml
---
github:
  repo: your-org/your-repo
  label_prefix: symphony
tracker:
  active_states:
    - todo
    - in-progress
    - rework
  terminal_states:
    - done
    - cancelled
polling:
  interval_ms: 10000
workspace:
  root: ~/code/symphony-workspaces
hooks:
  after_create: |
    git clone --depth 1 git@github.com:your-org/your-repo.git .
    yarn install
agent:
  max_concurrent_agents: 3
  max_turns: 30
claude:
  command: symphony-claude
---
 
You are working on GitHub Issue `#{{ issue.identifier }}` in `your-org/your-repo`.
 
{% if attempt %}
Continuation context:
 
- This is retry attempt #{{ attempt }} because the issue is still open.
- Resume from the current workspace state instead of restarting from scratch.
{% endif %}
 
Issue context:
Number: #{{ issue.identifier }}
Title: {{ issue.title }}
Labels: {{ issue.labels }}
URL: {{ issue.url }}
 
Description:
{% if issue.body %}
{{ issue.body }}
{% else %}
No description provided.
{% endif %}
 
Instructions:
 
1. This is an unattended orchestration session. Never ask a human to perform follow-up actions.
2. Only stop early for a true blocker (missing required auth/permissions/secrets).
3. Final message must report completed actions and blockers only.
 
Work only in the provided repository copy. Do not touch any other path.

WORKFLOW.md의 YAML front matter 부분이 설정이고, --- 아래 본문이 에이전트에게 전달되는 프롬프트 템플릿이다. {{ issue.identifier }}{{ issue.title }} 같은 변수는 Symphony가 이슈 정보로 자동 치환해준다. {% if attempt %} 같은 조건문도 쓸 수 있어서, 재시도 시에는 처음부터 다시 하지 말라는 지시를 추가할 수 있다.

실제로는 이 프롬프트 아래에 코드베이스 컨벤션, 상태 전환 규칙, 구현 단계, PR 피드백 처리 절차, 워크패드 템플릿 등을 상세하게 적는다. 프롬프트가 길수록 에이전트가 더 일관성 있게 동작한다. 내가 실제로 쓰고 있는 WORKFLOW.md는 300줄 정도 된다.

4. GitHub Issues에 라벨 생성

Symphony가 이슈를 인식하려면 라벨이 필요하다:

  • symphony:todo — Symphony가 가져갈 이슈
  • symphony:in-progress — 작업 중
  • symphony:done — 완료

5. 실행

bash
symphony /path/to/WORKFLOW.md

실행하면 터미널에 상태 대시보드가 뜨고, 이슈별로 에이전트가 돌아가는 걸 실시간으로 볼 수 있다.

실제로 어떻게 돌아가는지

  1. Symphony가 GitHub Issues를 폴링해서 symphony:todo 라벨이 붙은 이슈를 발견
  2. 이슈별로 워크스페이스 디렉토리를 만들고 after_create 훅 실행 (git clone)
  3. symphony-claude를 통해 Claude Code 세션 시작
  4. WORKFLOW.md의 프롬프트 템플릿에 이슈 정보를 채워서 에이전트에게 전달
  5. Claude Code가 코드를 분석하고, 구현하고, PR을 올림
  6. 에이전트가 완료하면 라벨을 symphony:done으로 변경
  7. 다음 이슈로 넘어감

여러 이슈를 동시에 처리할 수도 있다. max_concurrent_agents로 동시 실행 수를 조절하면 된다.

한계와 주의사항

  • Symphony 자체가 아직 실험적이다. OpenAI도 "engineering preview"라고 명시하고 있다. 프로덕션 환경보다는 개인 프로젝트나 실험용으로 적합하다.
  • Claude Code CLI 비용이 발생한다. 에이전트가 자율적으로 돌아가니까 토큰 사용량을 모니터링하는 게 좋다. symphony-claude에서 턴별 토큰/비용 추적을 지원한다.
  • WORKFLOW.md 프롬프트 품질이 결과를 크게 좌우한다. 에이전트가 뭘 하고 뭘 하지 말아야 하는지 명확하게 적어야 한다.

소스 코드

둘 다 Homebrew tap으로 설치할 수 있다:

bash
brew tap sapsaldog/symphony
brew install symphony symphony-claude

Symphony의 컨셉은 좋지만, Codex에만 묶여 있는 게 아깝다고 느꼈다. 이 작업을 통해 Claude Code 사용자도 같은 자동화를 누릴 수 있게 되었으면 한다. 개선할 점이 있으면 이슈나 PR 부탁한다.