Openai Symphony Autonomous Agents

reason-machines/trending-skills/skills/openai-symphony-autonomous-agents

作者 reason-machines2384a003145a無授權條款83 個星標收錄於 2026年10月8日更新於 2026年10月8日儲存庫3 個月前更新

Symphony turns project work into isolated, autonomous implementation runs, allowing teams to manage work instead of supervising coding agents.

AI 產生的概覽

指導設定 OpenAI Symphony,將任務追蹤系統中的任務轉為隔離的自動編碼代理執行並自動開 PR。

功能
這個技能說明如何安裝與設定 OpenAI Symphony:這是一套 Elixir 系統,會輪詢 Linear 等工作追蹤器中處於特定狀態的任務,並為每項任務啟動一次隔離的代理執行。每次執行都在獨立的 git 分支上作業、建立拉取請求,並在合併前蒐集 CI 狀態、審查意見與複雜度分析等成果證明。文件也介紹核心模組、設定項目、並行上限,以及依 Symphony 規格進行自訂實作的做法。
適用情境
適用於為程式碼倉庫設定 Symphony、將其接到 Linear 看板,或在其他程式庫中實作 Symphony 規格的情境。也適合希望以管理任務、審閱成果的方式使用編碼代理,而非全程監督代理工作階段的團隊。
執行需求
需要 Elixir 與 Mix,以及供 Codex 代理使用的 OpenAI API 金鑰、用於任務追蹤整合的 Linear API 金鑰,和具備倉庫權限的 GitHub 權杖以執行拉取請求操作。還需設定環境變數與目標倉庫路徑;此技能未附任何指令碼。

OpenAI Symphony

Skill by ara.so — Daily 2026 Skills collection.

Symphony turns project work into isolated, autonomous implementation runs, allowing teams to manage work instead of supervising coding agents. Instead of watching an agent code, you define tasks (e.g. in Linear), and Symphony spawns agents that complete them, provide proof of work (CI status, PR reviews, walkthrough videos), and land PRs autonomously.


What Symphony Does

  • Monitors a work tracker (e.g. Linear) for tasks
  • Spawns isolated agent runs per task (using Codex or similar)
  • Each agent implements the task, opens a PR, and provides proof of work
  • Engineers review outcomes, not agent sessions
  • Works best in codebases using harness engineering

Installation Options

Option 1: Ask an agent to build it

Paste this prompt into Claude Code, Cursor, or Codex:

Implement Symphony according to the following spec:https://github.com/openai/symphony/blob/main/SPEC.md

Option 2: Use the Elixir reference implementation

bash
git clone https://github.com/openai/symphony.gitcd symphony/elixir

Follow elixir/README.md, or ask an agent:

Set up Symphony for my repository based onhttps://github.com/openai/symphony/blob/main/elixir/README.md

Elixir Reference Implementation Setup

Requirements

  • Elixir + Mix installed
  • An OpenAI API key (for Codex agent)
  • A Linear API key (if using Linear integration)
  • A GitHub token (for PR operations)

Environment Variables

bash
export OPENAI_API_KEY="sk-..."           # OpenAI API key for Codexexport LINEAR_API_KEY="lin_api_..."      # Linear integrationexport GITHUB_TOKEN="ghp_..."           # GitHub PR operationsexport SYMPHONY_REPO_PATH="/path/to/repo"  # Target repository

Install Dependencies

bash
cd elixirmix deps.get

Configuration (elixir/config/config.exs)

elixir
import Config
config :symphony,  openai_api_key: System.get_env("OPENAI_API_KEY"),  linear_api_key: System.get_env("LINEAR_API_KEY"),  github_token: System.get_env("GITHUB_TOKEN"),  repo_path: System.get_env("SYMPHONY_REPO_PATH", "./"),  poll_interval_ms: 30_000,  max_concurrent_agents: 3

Run Symphony

bash
mix symphony.start# or in IEx for developmentiex -S mix

Core Concepts

Isolated Implementation Runs

Each task gets its own isolated run:

  • Fresh git branch per task
  • Agent operates only within that branch
  • No shared state between runs
  • Proof of work collected before PR merge

Proof of Work

Before a PR is accepted, Symphony collects:

  • CI/CD pipeline status
  • PR review feedback
  • Complexity analysis
  • (optionally) walkthrough videos

Key Elixir Modules & Patterns

Starting the Symphony supervisor

elixir
# In your application.ex or directlydefmodule MyApp.Application do  use Application
  def start(_type, _args) do    children = [      Symphony.Supervisor    ]    Supervisor.start_link(children, strategy: :one_for_one)  endend

Defining a Task (Symphony Task struct)

elixir
defmodule Symphony.Task do  @type t :: %__MODULE__{    id: String.t(),    title: String.t(),    description: String.t(),    source: :linear | :manual,    status: :pending | :running | :completed | :failed,    branch: String.t() | nil,    pr_url: String.t() | nil,    proof_of_work: map() | nil  }
  defstruct [:id, :title, :description, :source,             status: :pending, branch: nil,             pr_url: nil, proof_of_work: nil]end

Spawning an Agent Run

elixir
defmodule Symphony.AgentRunner do  @doc """  Spawns an isolated agent run for a given task.  Each run gets its own branch and Codex session.  """  def run(task) do    branch = "symphony/#{task.id}-#{slugify(task.title)}"
    with :ok <- Git.create_branch(branch),         {:ok, result} <- Codex.implement(task, branch),         {:ok, pr_url} <- GitHub.open_pr(branch, task),         {:ok, proof} <- ProofOfWork.collect(pr_url) do      {:ok, %{task | status: :completed, pr_url: pr_url, proof_of_work: proof}}    else      {:error, reason} -> {:error, reason}    end  end
  defp slugify(title) do    title    |> String.downcase()    |> String.replace(~r/[^a-z0-9]+/, "-")    |> String.trim("-")  endend

Linear Integration — Polling for Tasks

elixir
defmodule Symphony.Linear.Poller do  use GenServer
  @poll_interval Application.compile_env(:symphony, :poll_interval_ms, 30_000)
  def start_link(opts \\ []) do    GenServer.start_link(__MODULE__, opts, name: __MODULE__)  end
  def init(_opts) do    schedule_poll()    {:ok, %{processed_ids: MapSet.new()}}  end
  def handle_info(:poll, state) do    case Symphony.Linear.Client.fetch_todo_tasks() do      {:ok, tasks} ->        new_tasks = Enum.reject(tasks, &MapSet.member?(state.processed_ids, &1.id))        Enum.each(new_tasks, &Symphony.AgentRunner.run/1)        new_ids = Enum.reduce(new_tasks, state.processed_ids, &MapSet.put(&2, &1.id))        schedule_poll()        {:noreply, %{state | processed_ids: new_ids}}
      {:error, reason} ->        Logger.error("Linear poll failed: #{inspect(reason)}")        schedule_poll()        {:noreply, state}    end  end
  defp schedule_poll do    Process.send_after(self(), :poll, @poll_interval)  endend

Linear API Client

elixir
defmodule Symphony.Linear.Client do  @linear_api "https://api.linear.app/graphql"
  def fetch_todo_tasks do    query = """    query {      issues(filter: { state: { name: { eq: "Todo" } } }) {        nodes {          id          title          description        }      }    }    """
    case HTTPoison.post(@linear_api, Jason.encode!(%{query: query}), headers()) do      {:ok, %{status_code: 200, body: body}} ->        tasks =          body          |> Jason.decode!()          |> get_in(["data", "issues", "nodes"])          |> Enum.map(&to_task/1)        {:ok, tasks}
      {:error, reason} ->        {:error, reason}    end  end
  defp headers do    [      {"Authorization", System.get_env("LINEAR_API_KEY")},      {"Content-Type", "application/json"}    ]  end
  defp to_task(%{"id" => id, "title" => title, "description" => desc}) do    %Symphony.Task{id: id, title: title, description: desc, source: :linear}  endend

Proof of Work Collection

elixir
defmodule Symphony.ProofOfWork do  @doc """  Collects proof of work for a PR before it can be merged.  Returns a map with CI status, review feedback, and complexity.  """  def collect(pr_url) do    with {:ok, ci_status} <- wait_for_ci(pr_url),         {:ok, reviews} <- fetch_reviews(pr_url),         {:ok, complexity} <- analyze_complexity(pr_url) do      {:ok, %{        ci_status: ci_status,        reviews: reviews,        complexity: complexity,        collected_at: DateTime.utc_now()      }}    end  end
  defp wait_for_ci(pr_url, retries \\ 30) do    case GitHub.get_pr_ci_status(pr_url) do      {:ok, :success} -> {:ok, :success}      {:ok, :pending} when retries > 0 ->        Process.sleep(60_000)        wait_for_ci(pr_url, retries - 1)      {:ok, status} -> {:ok, status}      {:error, reason} -> {:error, reason}    end  end
  defp fetch_reviews(pr_url), do: GitHub.get_pr_reviews(pr_url)  defp analyze_complexity(pr_url), do: GitHub.get_pr_diff_complexity(pr_url)end

Implementing the SPEC.md (Custom Implementation)

When building Symphony in another language, the spec defines:

  1. Task Source — poll Linear/GitHub/Jira for tasks in a specific state
  2. Agent Invocation — call Codex (or another agent) with task context
  3. Isolation — each run on a fresh branch, containerized if possible
  4. Proof of Work — CI, review, and analysis before merge
  5. Landing — auto-merge or present to engineer for approval

Minimal implementation loop in pseudocode:

elixir
# Core symphony loopdef symphony_loop(state) do  tasks = fetch_new_tasks(state.source)
  tasks  |> Enum.filter(&(&1.status == :todo))  |> Enum.each(fn task ->    Task.async(fn ->      branch = create_isolated_branch(task)      invoke_agent(task, branch)         # Codex / Claude / etc.      proof = collect_proof_of_work(branch)      present_for_review(task, proof)    end)  end)
  Process.sleep(state.poll_interval)  symphony_loop(state)end

Common Patterns

Limiting Concurrent Agent Runs

elixir
defmodule Symphony.AgentPool do  use GenServer
  @max_concurrent 3
  def start_link(_), do: GenServer.start_link(__MODULE__, %{running: 0, queue: []}, name: __MODULE__)
  def submit(task) do    GenServer.cast(__MODULE__, {:submit, task})  end
  def handle_cast({:submit, task}, %{running: n} = state) when n < @max_concurrent do    spawn_agent(task)    {:noreply, %{state | running: n + 1}}  end
  def handle_cast({:submit, task}, %{queue: q} = state) do    {:noreply, %{state | queue: q ++ [task]}}  end
  def handle_info({:agent_done, _result}, %{running: n, queue: [next | rest]} = state) do    spawn_agent(next)    {:noreply, %{state | running: n, queue: rest}}  end
  def handle_info({:agent_done, _result}, %{running: n} = state) do    {:noreply, %{state | running: n - 1}}  end
  defp spawn_agent(task) do    parent = self()    spawn(fn ->      result = Symphony.AgentRunner.run(task)      send(parent, {:agent_done, result})    end)  endend

Manual Task Injection (No Linear)

elixir
# In IEx or a Mix taskSymphony.AgentPool.submit(%Symphony.Task{  id: "manual-001",  title: "Add rate limiting to API",  description: "Implement token bucket rate limiting on /api/v1 endpoints",  source: :manual})

Troubleshooting

ProblemLikely CauseFix
Agents not spawningMissing OPENAI_API_KEYCheck env var is exported
Linear tasks not detectedWrong Linear state filterUpdate query filter to match your board's state name
PRs not openingMissing GITHUB_TOKEN or wrong repoVerify token has repo scope
CI never completesTimeout too shortIncrease retries in wait_for_ci/2
Too many concurrent runsDefault pool sizeSet max_concurrent_agents in config
Branch conflictsAgent reusing branch namesEnsure task IDs are unique per run

Debug Mode

elixir
# In config/dev.exsconfig :symphony, log_level: :debug
# Or at runtimeLogger.put_module_level(Symphony.AgentRunner, :debug)Logger.put_module_level(Symphony.Linear.Poller, :debug)

Resources

來源與署名

來源:reason-machines/trending-skills位於skills/openai-symphony-autonomous-agents提交2384a00

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架