Typer-based CLI for tmux-backed Codex orchestration sessions
Project description
tmux-orche
Control plane for tmux-backed agent orchestration.
tmux-orche exists for one job: let agents call other agents as durable subagents, with explicit routing, recoverable terminal state, and human takeover when needed.
It is not just a wrapper around tmux panes. It gives your agent graph stable session names, control-loop routing, and a way to inspect or attach to the exact live terminal that is doing the work.
Installation
Full install guide: https://github.com/parkgogogo/tmux-orche/raw/main/install.md
Install the latest prebuilt binary without Python:
curl -fsSL https://github.com/parkgogogo/tmux-orche/raw/main/install.sh | sh
Supported prebuilt targets: darwin-arm64, darwin-x64, linux-x64.
Update a binary install in place:
orche update
Install from PyPI:
pip install tmux-orche
Install with uv:
uv tool install tmux-orche
Install from source:
git clone https://github.com/parkgogogo/orche
cd orche
python3 -m venv .venv
source .venv/bin/activate
pip install -U pip
pip install .
Why It Exists
If one agent is going to supervise another, you need more than "run a command in some pane".
You need:
- a stable session name for each worker
- an explicit route for results to come back
- terminal state that survives beyond one prompt
- a way to inspect progress without stealing the TTY
- a way to take over the live terminal when automation is not enough
That is the gap orche fills.
Control Loops
orche is most useful when you want a real loop to close, not just a one-shot command to finish.
OpenClaw -> Codex or Claude -> Discord
Use discord:<channel-id> when OpenClaw is supervising the worker and the loop should close back into Discord/OpenClaw.
This is the "external supervisor" path:
- OpenClaw opens or reuses a worker session
- the worker runs in tmux with durable state
- completion or needs-input events route back through Discord notify
- OpenClaw can decide what to do next
Codex reviewer -> worker -> tmux bridge
Use tmux:<session> when another agent session is the supervisor.
This is the "in-terminal reviewer" path:
- a reviewer session delegates work to a worker session
- the worker reports back to the reviewer through tmux bridge
- the reviewer can inspect, continue delegation, or escalate to a human
That is the core model: orche is the control plane that lets one agent session address another agent session reliably.
Why Named Sessions Matter
Raw tmux panes are not a control plane.
With orche, you work with repo-reviewer, repo-worker, or auth-fixer, not %17.
That difference matters because a named session can carry:
- a working directory
- an agent type
- a persistent tmux pane
- an explicit notify route
- later inspection and human takeover
Core Workflow
The normal loop is:
openprompt- leave
statusorreadlaterattachif a human needs to take over
Quick Start
Fast native attach shortcuts
Open a new native session in the current directory and attach immediately:
orche codex --model gpt-5.4
orche claude -- --print --help
These shortcuts:
- always use the current directory as
cwd - forward trailing args to the underlying agent CLI
- create a fresh session name like
<repo>-<agent>-<random>
Reviewer-worker loop via tmux bridge
Open a reviewer that receives worker results:
orche open --cwd /repo --agent codex --name repo-reviewer
Open a worker that reports back to the reviewer:
orche open \
--cwd /repo \
--agent codex \
--name repo-worker \
--notify tmux:repo-reviewer
Send work to the worker:
orche prompt repo-worker "implement the parser refactor"
Check the reviewer later:
orche read repo-reviewer --lines 120
orche status repo-worker
Take over the worker if needed:
orche attach repo-worker
OpenClaw loop via Discord
Open a worker that reports back through Discord:
orche open \
--cwd /repo \
--agent codex \
--name repo-worker \
--notify discord:123456789012345678
Send work:
orche prompt repo-worker "analyze the failing tests and propose a fix"
Inspect later or attach directly:
orche status repo-worker
orche read repo-worker --lines 120
orche attach repo-worker
Best Fit Scenarios
tmux-orche is a good fit when you want:
- one reviewer session coordinating multiple workers
- OpenClaw supervising Codex or Claude through Discord notify
- durable worker sessions that accept multiple follow-up prompts
- explicit session-to-session routing inside tmux
- a live terminal takeover path when the loop gets stuck
It is less useful when you only need one short-lived command and do not plan to revisit the session.
Testing
The repo keeps normal unit/integration tests separate from real end-to-end tests.
Real E2E means:
- real
orcheCLI - real
tmux - real
codex - real session-to-session prompt and notify flow
The real E2E suites are:
tests/test_notify_e2e.pytests/test_session_collaboration_e2e.py
They are opt-in and require a working local environment:
ORCHE_RUN_E2E=1 python3 -m pytest -q tests/test_notify_e2e.py tests/test_session_collaboration_e2e.py
If tmux or codex is missing, or Codex is not logged in, those suites skip instead of simulating success.
Managed vs Native Sessions
Managed session
Use managed mode for normal orchestration:
orche open --cwd /repo --agent codex --name repo-worker --notify tmux:repo-reviewer
This is the default recommendation because orche can manage session metadata and routing coherently.
Native session
Use native mode when you need raw agent CLI args:
orche open --cwd /repo --agent claude -- --print --help
Rules:
- raw agent args must come after
-- - native sessions do not use
--notify - do not mix raw agent args with managed notify routing
Command Model
orche openCreate or reuse a named control endpoint.orche codex/orche claudeOpen a fresh native session for the current directory and attach immediately.orche promptDelegate work into an existing session.orche statusCheck whether the pane and agent are alive, and whether a turn is pending.orche readInspect recent terminal output without taking over the TTY.orche attachAttach your terminal to the live tmux session.orche inputType text without pressing Enter.orche keySend special keys such asEnter,Escape, orC-c.orche listList locally known sessions.orche cancelInterrupt the current turn but keep the session alive.orche closeEnd the session and clean up state.orche whoamiPrint the current session id.orche configRead or update shared runtime config.
CLI Entry Shortcuts
Use the short flags on CLI entry surfaces:
orche -h
orche -v
orche config -h
Notes:
-his supported on the root command and command groups-vis supported on the root command only- leaf commands still use
--help, for exampleorche attach --help
Notify and Routing
Notify is how control loops close.
orche open --notify accepts:
tmux:<target-session>discord:<channel-id>
Use tmux:<session> when another agent session should receive the result:
orche open --cwd /repo --agent codex --name repo-worker --notify tmux:repo-reviewer
Use discord:<channel-id> when the supervisor is OpenClaw or another Discord-facing control loop:
orche open --cwd /repo --agent codex --name repo-worker --notify discord:123456789012345678
Notes:
- routing is explicit; there is no implicit global default
- changing the notify target means opening a new session
tmuxrouting is for agent-to-agent loopsdiscordrouting is for OpenClaw or external supervision loops
Config
orche config list
orche config get claude.command
orche config get claude.home-path
orche config set claude.command /opt/tools/claude-wrapper
orche config reset claude.command
orche config set claude.home-path ~/custom/.claude
orche config set claude.config-path ~/custom/claude.json
orche config set discord.bot-token "$BOT_TOKEN"
orche config set discord.mention-user-id 123456789012345678
orche config set managed.ttl-seconds 1800
orche config set notify.enabled true
orche config get/set/reset/list reads and writes the same JSON config file. You can update values through the CLI or edit the file directly.
Config file:
~/.config/orche/config.json
If XDG_CONFIG_HOME is set, orche uses:
$XDG_CONFIG_HOME/orche/config.json
State directory:
~/.local/share/orche/
If XDG_DATA_HOME is set, orche uses:
$XDG_DATA_HOME/orche/
Supported user config keys:
claude.commandOverride the Claude CLI command thatorchelaunches. Default isclaude.claude.home-pathOverride the Claude source home directory mirrored into managed runtimes. Default is~/.claude.claude.config-pathOverride the Claude source config path used for trust sync. Default is~/.claude.json.discord.bot-tokenSet the Discord bot token used for bot-token delivery.discord.mention-user-idSet the Discord user id to mention in delivered notifications.discord.webhook-urlSet the Discord webhook URL used for webhook delivery.managed.ttl-secondsSet the managed-session idle TTL in seconds. Default is3600;<= 0disables TTL expiry.notify.enabledEnable or disable notify delivery globally.
Notes:
config.jsonmay also contain session or runtime fields written byorcheitself.- Those internal fields are not part of the stable hand-edited config surface.
- Prefer the keys above for user-managed configuration.
Claude custom config
Use these when your Claude installation is wrapped or its source home/config is not in the default location.
Set a custom Claude executable:
orche config set claude.command /opt/tools/claude-wrapper
Set a custom Claude source home path:
orche config set claude.home-path ~/custom/.claude
Set a custom Claude source config path for trust sync:
orche config set claude.config-path ~/custom/claude.json
Reset one of these keys back to its default:
orche config reset claude.command
What each key changes:
claude.commandchanges the binary or wrapper command thatorcheexecutes when it launches Claude.claude.home-pathchanges which Claude home directoryorchemirrors into managed Claude runtimes.claude.config-pathchanges which Claude config fileorchereads when it syncs trust settings into a managed worker runtime.
Typical cases:
- your system command is not literally named
claude - you use a wrapper script such as
/opt/tools/claude-wrapper - your Claude home directory is not
~/.claude - your Claude config lives somewhere other than
~/.claude.json
Example config.json:
{
"claude_command": "/opt/tools/claude-wrapper",
"claude_home_path": "/Users/you/custom/.claude",
"claude_config_path": "/Users/you/custom/claude.json"
}
Notes:
claude.home-pathandclaude.config-pathaffect the source Claude state thatorchemirrors into managed Claude sessions.- after changing any of these keys, new Claude sessions use the updated value immediately.
- managed Codex runtimes keep using an isolated
CODEX_HOME;orchealso writescheck_for_update_on_startup = falseand[notice].hide_rate_limit_model_nudge = truethere to avoid startup update checks and model-switch nudges interfering with managed sessions.
Prerequisites
tmuxcodexCLI and/orclaudeCLI- Python
3.9+
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tmux_orche-0.4.58.tar.gz.
File metadata
- Download URL: tmux_orche-0.4.58.tar.gz
- Upload date:
- Size: 100.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5928e9966de5a58c8d35e34663880aac057698dd0e0e807c991c42cf539857ce
|
|
| MD5 |
070bd79a647bcf758dc3dfed5bd6b40a
|
|
| BLAKE2b-256 |
82e86880da08afac709f771651c232eee8c32d9d70e3f9eb29ad437d44fa82fd
|
Provenance
The following attestation bundles were made for tmux_orche-0.4.58.tar.gz:
Publisher:
publish.yml on parkgogogo/tmux-orche
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tmux_orche-0.4.58.tar.gz -
Subject digest:
5928e9966de5a58c8d35e34663880aac057698dd0e0e807c991c42cf539857ce - Sigstore transparency entry: 1261868140
- Sigstore integration time:
-
Permalink:
parkgogogo/tmux-orche@dc02fccaa31beb627d0ca17471bf987a9ae02022 -
Branch / Tag:
refs/tags/v0.4.58 - Owner: https://github.com/parkgogogo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@dc02fccaa31beb627d0ca17471bf987a9ae02022 -
Trigger Event:
push
-
Statement type:
File details
Details for the file tmux_orche-0.4.58-py3-none-any.whl.
File metadata
- Download URL: tmux_orche-0.4.58-py3-none-any.whl
- Upload date:
- Size: 69.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
77e7a968e4de4eb3173544367e70c8f655e7e691b127fc6a7014aa96bab7bbdf
|
|
| MD5 |
e0f9933061f6f429e0cdd0d1c42f27e8
|
|
| BLAKE2b-256 |
febf527f15a1443715c83136f80edad2f5c30b57841c3d89d641cfbbb9763c49
|
Provenance
The following attestation bundles were made for tmux_orche-0.4.58-py3-none-any.whl:
Publisher:
publish.yml on parkgogogo/tmux-orche
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tmux_orche-0.4.58-py3-none-any.whl -
Subject digest:
77e7a968e4de4eb3173544367e70c8f655e7e691b127fc6a7014aa96bab7bbdf - Sigstore transparency entry: 1261868159
- Sigstore integration time:
-
Permalink:
parkgogogo/tmux-orche@dc02fccaa31beb627d0ca17471bf987a9ae02022 -
Branch / Tag:
refs/tags/v0.4.58 - Owner: https://github.com/parkgogogo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@dc02fccaa31beb627d0ca17471bf987a9ae02022 -
Trigger Event:
push
-
Statement type: