Skip to content
Original
Juejin · AI coding· ZzT·· 3 hours agoSelectedAI score74

OpenRig teardown: using YAML to turn Claude Code and Codex into a team

AI overview

OpenRig is an open-source multi-agent harness that defines team topology with a YAML-based RigSpec, turning sessions like Claude Code and Codex into a team. This week it climbed GitHub trending with 2,028 stars, bringing the total to nearly 7,000. The current version is 0.6.10, under the Apache-2 license.

Why it matters

A teardown of OpenRig's engineering approach: defining multi-agent teams in YAML and handing off tasks through queues instead of chat logs—an approach you can carry over to your own multi-agent orchestration.

Full text · AI translation

OpenRig is an open-source multi-agent harness. It was created on April 1, and this week it gained 2,028 stars on GitHub trending, bringing its total close to 7,000. The current version is 0.6.10, under the Apache-2 license. Its README opens with: "A harness wraps a model. A rig wraps your harnesses." Claude Code and Codex are each harnesses that wrap a model; OpenRig wraps multiple harnesses into a team. It doesn't modify any agent—each agent is still a regular Claude Code or Codex session running in a tmux session you can attach to at any time. OpenRig adds four things: a team topology described in YAML, a mechanism for delivering messages into terminals, a queue that records who owns what work, and snapshots that restore the team after a restart. This article breaks down its source code along those four parts, and ends with the config changes you need to know about before installing.

The most interesting thing about this project is the answer it gives to "what do multiple agents actually collaborate through?"

Common multi-agent setups have agents message each other and hand off tasks in conversation. OpenRig's built-in team rules explicitly forbid this: "Do not use chat text as the work record." Messages only wake the other side up; the task itself lives in a SQLite queue, with ownership, status, and a handoff record. A daemon scans the queue every 5 minutes, finds entries that were claimed but not done or handed off but never picked up, and writes new entries back to the responsible agent. The team topology works the same way: who assigns work to whom, who can see whose output—all written in YAML, not in some agent's prompt.

An agent's context gets compacted, sessions drop, processes restart—promises made in conversation can vanish at any moment. OpenRig puts everything that needs to survive those interruptions outside the agent. That's the precondition for a team to keep working over long stretches.

Define a team in one YAML file: groups, roles, and five kinds of relationships

Image 1: fig-topology.png A team is defined in a YAML file called RigSpec. At the top level is the rig, below it several pods, and each pod contains several members. Each member declares which runtime it uses (claude-code, codex, pi, etc.), which AgentSpec it references (the role's skill, guidance, hook), and which directory it works in. Once started, each member becomes a seat with an address like dev-build@starter: pod dev, member build, in rig starter.

Relationships between members are expressed as edges. The schema has five kinds:

Edge Meaning Constrains startup order?
delegates_to Source assigns work to target Yes
spawned_by Source is pulled up by target; target starts first Yes
can_observe Source can view target's output No
collaborates_with Peer collaboration No
escalates_to Source escalates decisions to target No

The built-in factory team is a complete example: the orchestration pod has a lead (Codex) and an advisor (Claude Code); the development pod has build (Claude Code), qa (Codex), and design (Claude Code); the review pod has r1 (Claude Code) and r2 (Codex). The lead has delegates_to edges to the other five seats; the two reviewers only have can_observe edges—they can see the output of build, design, and qa, but have no assignment relationship, and there are no edges inside the review pod.

This approach turns the org structure into a file you can review and diff. Changing the team means changing the YAML, and rig grow and rig shrink let you add or remove seats at runtime.

Starter team: Claude Code writes, Codex reviews

The smallest built-in team, starter, has just two seats: build runs Claude Code, review runs Codex, with one delegates_to edge from build to review. Its team rules (CULTURE.md) require the builder, after the first meaningful change, to hand the "exact diff and the behavior it promises" to review for independent checking, via rig queue handoff, along with the repo path, candidate commit, checks that were run, and known limitations.

factory keeps the same pairing: build is Claude Code, qa is Codex; of the two independent reviewers, one is Claude Code and one is Codex. The README only says "Claude Code and Codex in the same rig" without explaining why. But looking at the built-in team's config, writing and reviewing are deliberately split across different vendors' models, so review doesn't share the same blind spots as implementation. A model reviewing its own code tends to agree with its own reasoning path; switching to a different model family introduces a reviewer with different training data and preferences into the process.

It works even if you only subscribe to one vendor. After installation, the kernel operator rewrites the starter into a single-vendor version and saves it under the same name.

Message delivery: paste into the tmux pane, then press Enter

Image 2: fig-delivery.png Since agents are unmodified Claude Code and Codex sessions, OpenRig has only one way to send them a message: paste text into the tmux pane, then press Enter. rig send takes exactly this path, implemented in session-transport.ts, in 2,236 lines.

Most of that code deals with one question: when Enter is pressed, is that message really what's in the input box? If the target agent is sitting on a permission confirmation dialog, one Enter press approves an action on the user's behalf. So before delivering, the daemon captures the pane contents to judge the other side's state:

  • Idle: deliver directly.
  • Working: deliver anyway, with a note. The code comment says "busy is NOT a block"; earlier versions would refuse, but it was changed to just a note, on the grounds that you shouldn't block communication waiting for the other side to be free.
  • Sitting on a selection box or permission confirmation: the only hard refusal.

Before pressing Enter there's another check: only the last ❯ input line in the pane counts; numbered option lines are always treated as a dialog; after pasting, the text collapses into a [Pasted text #N +X lines] placeholder, and the line count must match the message—two placeholders means rejection. Another detail is the summary carried in the queue wake-up message: the summary is written by another agent and gets typed into the recipient's terminal, so all control characters, newlines, and zero-width characters are replaced with spaces, to stop a summary from forging the "From:" or "↩ Reply" lines of the message envelope.

This is the most engineering-heavy part of OpenRig. Treating the terminal as the interface between agents means no dependence on any vendor's API, at the cost of handling all the terminal's ambiguities yourself.

The queue is the work record

Image 3: fig-queue.png Messages only wake things up; the work itself is recorded in the queue. Each queue entry has a source seat, target seat, status, and handoff chain. There are eight statuses in all; the ones still moving are pending, in-progress, blocked, the normal endings are done and handed-off, and there are also failed, denied, canceled. A seat claims a task first, then hands it off to the next seat when done; the handoff creates a new entry and records handed_off_from and handed_off_to. The starter's team rules require agents, each time they re-enter, to read the queue and project artifacts first, not redo completed changes, and not re-spawn seats.

The other half of the queue is the daemon's resident scan queue-stuck-sweep. It runs every 300 seconds by default, looking for six kinds of stuck situations, including claimed but not advanced, assigned but not delivered, and unclaimed for over 60 minutes. When it finds one, it doesn't shout in the terminal—it writes a new queue entry for the responsible seat, deduplicated by "stuck entry + problem type," so the same problem only ever has one open reminder. This scan used to be two commands someone had to remember to run; the source comment explains why it became a resident loop: if it depends on someone remembering to check, tasks quietly get stuck.

blocked status is handled separately. Tasks waiting on a human decision or on another entry to finish sit in blocked; the scan treats that as legitimate waiting and doesn't nag.

Seat addresses stay fixed, sessions can change

The README defines a seat as "a stable role and address; the conversation occupying it can change, while the identity and configuration context are preserved." rig down --snapshot saves the whole topology, rig up <name> restores it by name, and each seat gets a definite outcome: original session restored, new session plus startup context, original session unrecoverable and the user must choose, needs manual handling, or failed. Each member can also declare restore_policy in YAML, one of three: restore if possible, always start fresh, or save checkpoints only.

This is the same idea as the queue. Conversations break at any time, so the team relies on addresses and the queue: messages go to dev-build@starter, tasks are recorded in entries addressed to that location, and no matter which session sits behind the address later, the handoff chain doesn't break.

Config changes to know about before installing

OpenRig modifies local config, and the README devotes a whole section to listing it, recommending you read it and back up before installing:

Object Change
Claude Code Write the workspace trust and onboarding completion flags; in the project, add a statusLine and activity hook to .claude/settings.local.json; shared settings resources will set permissions.defaultMode to acceptEdits
Codex Write ~/.codex/config.toml: enable hooks, add an activity reporting command, and pre-write the trust hash, marking the workspace as trusted
skills When the daemon starts, seed three skills into ~/.claude/skills and ~/.agents/skills
tmux rig setup writes a config snippet into ~/.tmux.conf

Permissions are locked down by default: an ordinary team seat can run rig commands, read projects, and run common tests without confirmation, while lifecycle commands like rig up and rig down still prompt; YOLO is off by default. The exception is the kernel rig that manages the whole instance—its Codex seat starts with -s danger-full-access -a never by default. Activity reporting only sends the event type, seat identity, and timestamp, with no prompt text or tool parameters. The README also states that these writes come with no full rollback guarantee.

A reference for building your own multi-agent setup

Your situation Practices worth borrowing
Already running Claude Code and Codex side by side in multiple terminals Give each session a fixed address and role first, then talk about orchestration
Agents hand off tasks through chat Move tasks into storage outside the agents; use messages only to wake them up
Worried tasks will silently stall Replace “remember to check” with a persistent scanner—turn problems into new tasks and route them back to the owner
Want agents to review each other Use models from different vendors for writing and reviewing; give the reviewer observation rights only, not the ability to assign work
Need to automatically send messages into agent terminals Before hitting Enter, confirm the input box holds your message, and never press Enter on a permission pop-up
One person, one repo, a one-off small change You don’t need OpenRig—one session plus a subagent is enough

OpenRig’s value isn’t making agents smarter; it’s letting a team keep going after sessions drop, context compresses, or machines restart. The engineering effort it takes to do this mostly goes outside the agents: queues, scanning, snapshots, and 2,000 lines of code to make sure Enter is pressed in the right place.

References

Source: Juejin · AI coding · juejin.cn