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 从公开仓库中收录这些内容。

举报或申请下架