Claude → Codex → Opencode reply one after another (or all at once in parallel mode), inside a clean full-screen developer TUI. The roster is configurable, so bring your own agents.
English · Português
multiagent turns your terminal into a group chat between AI agents. You type one
message; Claude, Codex and Opencode answer one after another, and every
agent reads the full transcript before replying, so they build on (and argue with) each
other instead of answering in a vacuum.
It looks and feels like a real developer tool: a two-pane TUI with the conversation on the left and a live technical panel (execution status, logs, consensus, meta) on the right.
Instructions for AI agents working on this repo
Read this README first, then inspect magent/cli.py, magent/tui.py,
magent/agents.py, and agents.json before changing behavior.
Keep the Windows-first CLI assumptions intact unless the task is explicitly about POSIX
support. The agent CLIs receive prompts through STDIN, sessions are stored under
sessions/, and the configurable roster lives in agents.json.
Do not push to a remote unless the human explicitly asks for it.
- 🔀 Sequential and parallel modes : by default agents reply in turn, each reading what the others said. In parallel mode they all receive the same snapshot and reply simultaneously, like using multiple AI web UIs at once. Toggle at any time with
Ctrl+Tor start with--parallel. - 🗣️ Mode tag per message : every agent reply is labeled
(sequential)or(parallel)so the transcript is always self-explanatory. - 📋 System prompt visible on open : the exact instructions sent to every agent appear as the first dimmed message in the chat so you always know what context they are working from.
- 🧵 Full shared context : every agent receives the entire transcript each turn.
- 🖥️ Full-screen TUI : two-pane layout, color-coded participants, live status, logs, consensus and meta panels. The active mode is always visible in the top bar.
- 💾 Resumable sessions :
--session <name>saves tosessions/<name>.jsonevery round; reuse the name to pick up exactly where you left off (history, messages, consensus, tokens, runtime, mode). - 🌍 Bilingual : English by default, full Portuguese with
--pt(UI and the prompts sent to the agents). Set a default withMULTIAGENT_LANG. - 🖱️ Mouse + keyboard : wheel-scroll the chat,
Shift+drag to select/copy, plus keyboard shortcuts for everything. - 🧰 Graceful degradation : no
prompt_toolkitor no real terminal? It drops to a clean linear mode automatically (parallel is supported there too, viaThreadPoolExecutor). - 📝 Plain-text logs : every run writes a human-readable
session_*.txttranscript (and, with--debug, the exact prompt sent to each agent).
Each agent is a real CLI invoked per turn, and the accumulated transcript is delivered through STDIN, never as a command-line argument.
Why STDIN? On Windows the
codex/opencodeCLIs are npm shims (.cmd/.ps1). Passing a long, multiline transcript as an argument gets mangled when it crosses the batch shim, so the later agents would silently lose the conversation. Feeding the prompt on STDIN keeps the multiline context intact. The launcher resolves.exedirectly and routes.cmd/.ps1throughpowershell -File, which forwards STDIN to the real executable.
The TUI runs each agent in a background executor, so the interface stays responsive and
the status panel updates live: waiting to analyzing… to done.
- Python 3.8+
- prompt_toolkit (the TUI engine)
- The agent CLIs in your roster installed and authenticated, on your
PATH. The default roster is:claude(Claude Code), invoked asclaude -pcodex, invoked ascodex exec --skip-git-repo-checkopencode, invoked asopencode run
🪟 Platform: built and tested on Windows (the CLI resolution is PowerShell/npm-shim aware). POSIX support is on the roadmap.
Missing one of the CLIs? The app still runs; that agent's turn just reports it's unavailable and the loop keeps going.
git clone <your-repo-url> multiagent
cd multiagent
pip install prompt_toolkitRun it:
python multiagent.pypython multiagent.py # start empty, type your first message
python multiagent.py "should we ship this on Friday?" # start with an initial prompt
python multiagent.py --parallel "..." # start in parallel mode
python multiagent.py --pt "vamos enviar na sexta?" # Portuguese UI + prompts
python multiagent.py --session design-review "..." # named, resumable session
python multiagent.py --debug "..." # log the exact prompt per agent| Flag | Description |
|---|---|
--session <name> |
Named session. Reusing the same name resumes it (mode is restored too); a new name starts fresh. |
--parallel |
Start in parallel mode (all agents reply simultaneously, no cross-contamination within the round). Toggle at runtime with Ctrl+T. |
--lang {en,pt} |
Interface and agent-prompt language. Overrides $MULTIAGENT_LANG. |
--pt |
Shortcut for --lang pt. |
--debug |
Write the full prompt sent to each agent into the session log. |
| Key | Action |
|---|---|
Enter |
Send message |
Ctrl+J |
New line (multiline input) |
PgUp / PgDn |
Scroll the chat |
Ctrl+T |
Toggle parallel / sequential mode |
Ctrl+L |
Toggle the side panel |
Ctrl+K |
Clear the chat / context |
Alt+N |
New topic (reset context, keep the screen) |
Ctrl+C |
Quit |
🖱️ Mouse wheel scrolls the chat. To select and copy text, hold
Shiftwhile dragging (the terminal's native selection).
The roster lives in agents.json at the project root. Edit it to add, remove or
reorder agents, no code changes needed. The array order is the execution order, and the
last agent gives the round's consensus.
[
{ "label": "Claude", "cmd": "claude", "flags": ["-p"], "color": "#b07cff" },
{ "label": "Codex", "cmd": "codex", "flags": ["exec", "--skip-git-repo-check"] },
{ "label": "Opencode", "cmd": "opencode", "flags": ["run"] },
{ "label": "Gemini", "cmd": "gemini", "flags": ["-p"], "color": "#f7768e" }
]Only label and cmd are required. Optional per agent: flags (CLI arguments), color
(hex; a palette color is assigned if omitted), key, name and cmd_label. Every agent
must read its prompt from STDIN (that is how the transcript is delivered).
Point at a different file with the MULTIAGENT_AGENTS environment variable. If the file
is missing or invalid, the app falls back to a built-in default roster.
English is the default. Three ways to switch, in precedence order:
python multiagent.py --pt # 1. flag (highest priority)
export MULTIAGENT_LANG=pt # 2. environment variable (bash/zsh)
$env:MULTIAGENT_LANG = "pt" # ...or PowerShell
setx MULTIAGENT_LANG pt # ...or persistent on Windows
# 3. default is enSwitching the language changes the whole UI and the instructions sent to the agents, so they reply in your language too.
Sequential (default): agents reply one at a time. Each one receives the full transcript including the previous agents' replies from the same round, so they build on each other.
Parallel: all agents get the same snapshot (the conversation up to, but not including, the current round's replies). They run concurrently and responses appear as they arrive. After every agent has finished, their replies are appended to the history in roster order, so the next round's sequential or parallel context is deterministic.
sequential: Claude sees [history]
Codex sees [history + Claude's reply]
Opencode sees [history + Claude's reply + Codex's reply]
parallel: Claude, Codex, Opencode all see [history] -- no cross-contamination
(responses arrive as they finish; history updated in roster order)
Every agent message is tagged (sequential) or (parallel) so the transcript is
self-explanatory when you mix modes mid-session. The active mode is always visible in the
top bar and is saved with the session.
Every run logs to a human-readable session_YYYYMMDD_HHMMSS.txt. With --session,
the full state is also persisted as JSON:
python multiagent.py --session design-review "let's review the API"
# ...chat, then quit...
python multiagent.py --session design-review # resumes right where you left offRestored on resume: conversation history, on-screen messages, consensus, token estimate and accumulated runtime. Saved atomically every round, on clear, on new topic and on exit.
A thin launcher over the magent package, one responsibility per module:
multiagent.py # launcher: fixes UTF-8 streams, calls magent.cli.main()
agents.json # the agent roster (editable, see "Configuring agents")
magent/
├── i18n.py # translation table (EN/PT) + L() + set_lang()
├── config.py # UI colors, tunables, agent-roster loader
├── agents.py # prompt building + CLI execution (never raises)
├── sessions.py # save/resume sessions as JSON
├── utils.py # input sanitizing, log writing, formatting, git
├── tui.py # full-screen prompt_toolkit app (chat + side panel)
└── cli.py # argparse, language resolution, TUI/fallback routing
Modules are layered with no import cycles: i18n and sessions are leaves; config
and utils depend on i18n; agents on those; tui on everything below it; and cli
ties it together.
No prompt_toolkit, or piping input (no TTY)? multiagent automatically switches to a
linear mode that runs the same agents in order and prints their replies, handy for
scripting and CI:
echo "summarize this in one line" | python multiagent.py- Configurable agent roster and order (
agents.json) - Parallel mode (all agents reply simultaneously, toggle with
Ctrl+T/--parallel) - POSIX (macOS/Linux) CLI invocation
- Real token accounting per CLI (current count is an estimate)
- Per-session export (Markdown)
MIT. See LICENSE.
