Skip to content
mana-bytePublic

About

TUI for simple cross-harness agent orchestration

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

🎭 Theater

Local cross-harness orchestration for coding agents.

Run the whole show from one terminal.

CI Release Python 3.12+ tmux

Theater régie coordinating four coding-agent CLIs around a staged terminal

Theater lets Claude Code, Codex, opencode, Pi, and Vibe work together on your machine. Any agent can spawn, manage, and communicate with other harnesses, coordinating work across CLI boundaries while you follow the entire tree from one live control view.

Open any agent's real terminal, inspect its tools and results, and keep an eye on usage without replacing the CLIs you already use. Their accounts, permissions, and sessions remain their own; Theater gives them one stage—and gives you the control room.

🎬 See it in action

FINAL.mov
Theater régie showing a cross-harness participant tree, a staged Codex pane, and usage by model

One stage for every agent

See who is working, waiting, idle, or done. Move from the full cast to any agent's real terminal in one keypress.

Theater trajectory view showing a live agent turn, tool calls, timing, costs, and event details

See the work, not just the answer

Follow model turns, tool calls, files, timing, cost, and results as they happen.

✨ What Theater gives you

Capability What it gives you
One live view Follow agent lineage, status, current work, and usage (per harness and per agent) from the régie.
Your actual CLIs Step into the original Claude Code, Codex, opencode, Pi, or Vibe terminal at any time.
Cross-harness orchestration Agents can spawn, manage, and communicate with other coding-agent harnesses.
Input requests await_sessions reports detected prompts as awaiting_input once its presence gate is clear, while the child's job stays running.
Parallel worktrees Give a task its own Git worktree, or deliberately share one between cooperating agents.
Sessions that keep going Leave the régie, come back later, and resume previous sessions from the command palette.
Local control Theater's state stays on your machine; there is no Theater-hosted control plane.

Install

Requirements

  • Python 3.12+
  • git
  • At least one supported coding-agent CLI, installed and authenticated

tmux is required only when using the bundled Régie tmux bridge. Native runtime-backed harnesses can run without it; another terminal provider may be selected instead.

Theater installs its own Python packages. It does not install agent CLIs or provide their subscriptions and API credentials.

Agent Command
Claude Code claude
Codex codex
opencode opencode
Pi pi
Vibe vibe

Nix

The flake exposes separate Theater and Régie packages with matching versions, Python 3.12, tmux, git, and all Python dependencies, including the observability extra for OTLP export (still disabled unless configured):

nix profile add github:mana-byte/theater/v1.0.0rc11#theater github:mana-byte/theater/v1.0.0rc11#regie

Drop /v1.0.0rc11 to track main instead. From a local checkout, use nix profile add .#theater .#regie instead. nix run .#theater -- --help and nix run .#regie -- --help run either CLI without adding it to your profile. The default app remains Theater. Neither package exposes Python or dependency executables in your profile. An existing tmux or git on PATH takes precedence over the bundled fallback.

Install profiles bundle the packages above; each adds to the previous one:

Profile Installs
theater-base (also default) Theater and Régie
theater-plus theater-base plus Beads (bd 1.3.1, the only version Theater accepts)
theater-full theater-plus plus the supported coding-agent CLIs (claude, codex, opencode, pi, vibe)
nix profile add github:mana-byte/theater#theater-plus   # or #theater-base, #theater-full

Profiles are on main; tagged releases before them still treat the default package as Theater only. theater-full includes unfree packages (claude-code and textual-speedups, a Vibe dependency); the flake allows exactly those two. Profiles link only executables, so man pages and shell completions are not installed.

Adding or upgrading a profile next to a separately installed #theater or #regie fails with a bin/theater or bin/regie conflict and leaves the profile unchanged (the upgrade error suggests no fix). Run nix profile list to find the element names, nix profile remove them, then add the profile, or add it with --priority.

With uv

Install git (and tmux when using the tmux bridge) with your system package manager first. The packages are not published on PyPI; install both from the release tag, and Régie picks up the matching Theater from the same checkout:

uv tool install "theater @ git+https://github.com/mana-byte/theater@v1.0.0rc11"
uv tool install "regie @ git+https://github.com/mana-byte/theater@v1.0.0rc11#subdirectory=packages/regie"
theater --version
regie --help

The wheels and sdists are also attached to the GitHub release.

Quick start

regie

theater is the daemon, agent, and management CLI; bare theater prints help and points here. regie owns UI startup: it connects to a compatible running public API, starts the matching installed daemon only when none is available, ensures its persistent bridge is ready, then creates or reuses a Régie window on that bridge's exact tmux server and attaches to it. It never replaces a reachable incompatible daemon.

For the bundled tmux terminal provider, start or inspect the bridge without opening the UI:

regie bridge start
regie bridge status
regie bridge stop

Your first five keys:

Key Action
o Open the spawn menu
Ctrl+P Open the command palette for spawn, resume, and views
j / k or arrows Move through the agent tree
Enter Show the selected agent on the right
q Leave the régie without stopping your agents

Tip

Press o and choose an installed CLI. The new session appears in the tree; select it and press L to enter its normal terminal.

Usage

🎟️ Everyday orchestration prompts

Press o, choose a harness, then open it with L and ask it to use Theater. The agent can spawn, manage, and communicate with other harnesses while every session appears in the régie. Be as specific as you like about models, reasoning levels, and roles.

Accelerated Theater régie demo showing cross-harness test orchestration spawning and managing agent sessions Three real Theater prompts: review a patch with Codex in an isolated worktree; debate a fix with Codex GPT-5.6 Sol xhigh; and orchestrate Pi GLM-5.3 max workers with Claude Code Opus 5 xhigh as reviewer
Copy these prompts
Use Theater to have Codex review this patch in an isolated worktree.

Use Theater to debate this fix with a Codex GPT-5.6 Sol xhigh session.

Use Theater to orchestrate the implementation with Pi GLM-5.3 max workers and
Claude Code Opus 5 xhigh as reviewer.

Skills

Every harness connected to Theater can discover and use the same built-in and custom skills, so a workflow written once works from any of your agents.

  • theater-debate — challenge a decision with a second model.
  • theater-configure — set up or personalize Theater.
  • theater-recover-tmux — recover sessions after a tmux restart.
  • theater-delegate — hand a task to an existing peer or a builder and reviewer pair.
  • hierarchy — a play shipped by the default Beads plugin: a master delegates to members or leads, with a shared task board for milestones, progress, and outcomes.
  • pair — a play: a builder and an independent reviewer debate to agreement in a shared worktree.

Hand a skill to another agent. Name it in skills=[...] on spawn_session or send: Theater appends its instructions after your task, so the receiver needs no load_skill call. A child gets only the skills you name, never yours, and attached skills stay under 16 KiB combined.

Run a play. A play is a team structure: skills/<play>/PLAY.toml plus one skill per member, named <play>/<member> (hierarchy/lead). An agent that loads the master skill (hierarchy/master) becomes the play's master. Use load_skill(name="hierarchy/master", preview=true) to read it without starting a play. A spawn that attaches it starts a new master. While the master lives, every spawn below it attaches exactly one position its spawner may give, plus at most one task role (hierarchy/worker, hierarchy/reviewer, hierarchy/debater); outside a live play, positions and roles cannot be attached. A parent gives an existing child its position with send(skills=["hierarchy/lead"]); it takes effect once Theater confirms delivery (if the child still shows no play position after the job ends, send it again), and a queued one fails unsent if the play ends first. When the master dies the play ends and its rules lift. list_skills shows each play's positions and roles; whoami shows the positions you may give a child now, each with the task roles that fit it. A play may list positions as disposable (hierarchy/member): an agent may retire a finished child holding one without asking the user, while terminating any other child still needs the user's explicit yes.

Track play progress. Install Beads with brew install beads or npm install -g @beads/bd. The default beads MCP plugin exposes eight task tools, usable only by authorized positions in a play declaring plugins = ["beads"]. Each play instance gets its own board; agents select it through their membership. Boards expire seven days after Theater observes the play ended; configure [mcp.plugins.beads] board_ttl_seconds to change retention. Remove beads from [mcp] enabled to disable the plugin and its hierarchy play, then restart the daemon and start new agent sessions. See plugin configuration and tools.

Make Theater yours. Turn any workflow you repeat into a custom skill—your preferred harnesses, models, roles, worktrees, checks, and handoffs. Add it at $THEATER_HOME/skills/<name>/SKILL.md (~/.theater by default), and every connected harness can use it.

Régie key mappings

Agent tree

Key Action
j / k or ↑ / ↓ Move through the agent tree
J / K Move the selected agent or separator among its siblings
- Add a named separator above the selected row
Enter on a separator Fold or unfold its section (or click anywhere on it but its name); the heading counts its agents
Enter Stage the selected agent
h / l Stage its trajectory / live terminal; press again to focus
H / L Open and focus its trajectory / live terminal immediately
s / f / i Send a message / queue a followup / interrupt the selected agent
o Open the spawn menu
Ctrl+P Open the command palette
Esc Close a focused trajectory and return to the tree
<tmux prefix> h Return from a staged terminal or a trajectory to the tree
r Rename the selected agent's live alias or separator in place (or click its name); Enter saves, Esc or a click elsewhere cancels
x Kill the selected agent's pane, or delete the selected separator; a folded one also kills every agent it hides
$ Show or hide the usage footer (hidden by default; also in the palette)
q Leave the régie; agents keep running

While you work in a staged terminal or trajectory, a small animation plays in the empty space under the agent tree, and fades out when you come back to the tree. Choose it with tree_ambience in Régie's config: footer (default), leaves, fire, aquarium, stars, or none; set tree_ambience_when = "tree" to play it while the tree has focus instead. Your own ambiences are plugins in $THEATER_HOME/regie/plugins/ (see packages/regie/README.md).

The tmux prefix is usually Ctrl+B unless you changed it. Messages are typed in a bar that opens under the tree. A new separator is named on its heading, and a spawned agent's directory is typed on its own row, where the directory will show; Tab completes it. Enter submits; Esc or a click elsewhere cancels.

Trajectory view

The timeline sits above the selected span's details. J / K move focus down to the details or back up to the timeline; the focused panel's header is tinted.

On the timeline:

Key Action
j / k or ↓ / ↑ Focus the lane below / above (MODEL, TOOLS, MCP, …)
h / l or ← / → Previous / next span in the focused lane
H / L First span / latest span, following the live tail
+ / - Zoom in / out
/, then n / N Search, then jump to the next / previous match
f Show only matching spans; press again to restore all spans
Enter or J Focus the details
b Return to the previously viewed trajectory
r Clear search and zoom and return to the live tail
R Retry loading the trajectory
E Export the loaded trajectory as JSON and Markdown
y Copy the selected span's current details section
Esc Close the trajectory and return to the tree

In the details:

Key Action
j / k or ↓ / ↑ Move between sections and foldable data
h / l or ← / → Scroll
Enter Fold or expand what the cursor is on
y / Y Copy the section / the whole page to the clipboard
K or Esc Back to the timeline

Everything also works with the mouse: click a span to select it (double-click for its details), click a section bar to fold it, and click a footer key hint to run it.

CLI utilities

The standalone regie command is the normal interface. Theater commands are useful for setup, troubleshooting, and scripts:

theater                         # show Theater help and the Régie migration hint
regie                           # start the standalone UI
theater harnesses               # show detected coding-agent CLIs
theater ls --tree               # print the current agent tree
theater config                  # show effective settings and their source
theater config path             # print the config file location
theater models                  # show allowed model and reasoning choices
theater reload                  # apply [rails], [models], [reasoning], [skills] disabled in place
theater restart                 # apply any config change; agents keep running
theater stop                    # stop Theater's background service

Run theater --help for the complete command list.

Configuration

Theater configuration is machine-wide at $THEATER_HOME/config.toml, normally ~/.theater/config.toml. Régie owns a separate optional $THEATER_HOME/regie/config.toml, containing only its [regie] table. Theater rejects a legacy [regie] table in its config and never moves either file for you.

Defaults

These are the defaults most people will notice:

Setting Default
Favourite agent None; choose one when spawning
Terminal provider tmux (the selected provider must be registered)
Maximum delegation depth 3 levels
Maximum agents in one tree 20

Régie's defaults include the Textual theme, working-directory participant detail, 52-column sidebar, hidden event panel, and today's cost window. Put those settings in its separate config file.

Example

This is a real multi-agent setup, shortened to keep the model lists readable. The model and reasoning entries are choices Theater may pass to a CLI; they do not replace that CLI's own default.

[theater]
favourite = "vibe"

[rails]
budget = 100

[terminals]
default_provider = "tmux"

[models]
claude = ["fable", "opus", "sonnet", "haiku"]
codex = ["gpt-5.5", "gpt-5.6-sol", "gpt-5.6-luna", "gpt-5.6-terra", "gpt-6-astra"]
pi = ["mistral/zai-glm-5-3", "foundry-anthropic/claude-sonnet-5", "foundry-openai/gpt-6-astra"]
opencode = ["anthropic-foundry/claude-sonnet-5", "openai-foundry/gpt-5.5", "mistral/zai-glm-5-3"]
vibe = ["glm-5-3 [high]", "opus-5 [high]", "gpt-6-astra [high]"]

[reasoning]
codex = ["none", "minimal", "low", "medium", "high", "xhigh", "max", "ultra"]
claude = ["low", "medium", "high"]
pi = ["off", "minimal", "low", "medium", "high", "xhigh", "max"]

The corresponding Régie file is $THEATER_HOME/regie/config.toml:

[regie]
theme = "catppuccin-mocha"
sidebar_width = 52

Themes include nord, dracula, tokyo-night, rose-pine, and the Catppuccin variants. The Theater example config and Régie example config list their respective settings and defaults.

To choose models or reasoning levels explicitly, ask the installed CLI what it offers and paste the generated block into your config:

theater models --discover codex
theater models

After editing the file:

theater config      # its last line says whether the daemon needs a reload or a restart
theater reload      # [rails], [models], [reasoning] and [skills] disabled, in place
theater restart     # any other setting; agents keep running
regie bridge start

theater reload never starts a daemon. It refuses the whole file, applying nothing, when any setting outside those four changed — except the two the daemon never reads, which need neither command: theater.favourite (read by theater spawn when no harness is named, and by Régie at launch) and observability.mcp_timing (read by each new Theater MCP process).

Or ask a managed agent: “Use theater-configure to set up Theater with me.”

Tip

Advanced: bring your own tools. If your favourite coding-agent CLI is not built in, teach Theater about it with a custom harness plugin. To let an MCP server use explicitly granted Theater capabilities, connect it through an MCP-server plugin.

Data and troubleshooting

  • Theater data lives under $THEATER_HOME—normally ~/.theater/.
  • Human-readable logs live under $THEATER_HOME/var/logs/.
  • For local traces, metrics, and logs, see the optional Docker observability stack.
  • Régie keeps its config, bridge PID/lock/status, and bridge log below $THEATER_HOME/regie/.
  • theater harnesses shows which coding-agent CLIs Theater can find.
  • theater config validates the config and shows whether each value came from your file or a default.
  • Quitting the régie only detaches the interface. It does not kill agents.
  • Scratchpad entries are machine-wide, TTL-aware coordination data. They are not scoped to a Git tree and reads do not renew their expiry.
  • Worktrees are retained after completion. Explicitly killing a participant cleans its unique worktree and merged branch after exit is verified; dirty or still-used worktrees and unmerged branches are retained with a cleanup result. Named shared worktrees require explicit cleanup. Inspect with theater workspaces get <id>; remove with theater workspaces cleanup <id> --delete-branch. Omit --delete-branch to retain the branch. Force flags are separate choices.

Upgrading a drained RC9 installation

RC10 is a guarded, drained upgrade—not a live handoff. Before the schema transition, inspect every RC9 session and job and preserve any work you need. RC9 kill and retirement paths can still discard worktrees and unmerged branches; RC10's guarded cleanup is not in effect until the upgrade has completed.

  1. Drain sessions and jobs, then stop the RC9 daemon and MCP sidecars. Keep a consistent backup of the stopped database, config, and needed worktrees.
  2. Install the matching theater==1.0.0rc11 and regie==1.0.0rc11 distributions. The migration refuses non-dead participants or running jobs; it never kills or rewrites them to pass the check.
  3. Move the existing [regie] table intact from $THEATER_HOME/config.toml to $THEATER_HOME/regie/config.toml manually. Neither command rewrites configuration.
  4. Choose a registered terminal provider in [terminals], such as default_provider = "tmux", then start regie bridge start or launch regie.
  5. Verify provider readiness and create a test session through the normal API.

The migration deliberately discards RC9 tree-scoped scratchpad contents rather than merging scopes. There is no supported live downgrade: if rollback is necessary, stop RC10 and restore a consistent pre-upgrade database/config backup with matching RC9 binaries after preserving new work. Never point RC9 at an RC10-migrated database.

Learn more

Give every agent a pane. Give every task a stage.

About

TUI for simple cross-harness agent orchestration

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages