AgentRadio โ€” passive awareness for multi-agent coding

๐Ÿ“ป AgentRadio

Passive awareness for long-horizon multi-agent collaboration โ€” four coding agents that keep working while they listen

Coral Code Paper GitHub License: Apache 2.0

Benchmark Harbor Modal

Discord Coral Protocol

English | ็ฎ€ไฝ“ไธญๆ–‡ | Espaรฑol | ๆ—ฅๆœฌ่ชž | ํ•œ๊ตญ์–ด | ุงู„ุนุฑุจูŠุฉ

Give four coding agents a shared radio channel. They divide the work, negotiate the plan, and keep broadcasting discoveries while they work โ€” because listening runs as a background task instead of stealing a turn.

This repository contains the code and data to reproduce the experiments of the paper *AgentRadio: Passive Awareness for Long-Horizon Multi-Agent Collaboration* ([arXiv:2607.28430](https://arxiv.org/abs/2607.28430)). > ### โ˜๏ธ Prefer the product? โ†’ **[Coral Code](https://coralcode.dev/)** > > **[Coral Code](https://coralcode.dev/)** is the product version of AgentRadio. > **New users get $30 in free credit.** ### ๐Ÿ† One protocol, four agents โ€” +29.8 points over a single agent | Configuration | What it adds | Task acc. (Opus 4.6) | Task acc. (DeepSeek V4 Pro) | |---|---|:---:|:---:| | **B0** single agent | โ€” | 32.3 % | 29.0 % | | **B1** best of six single runs | 6ร— budget, no coordination | 37.9 % | 31.4 % | | **L1** four agents + division | division of labor | 39.5 % | 31.4 % | | **L2** + negotiation | joint planning + cross-review (blocking receive) | 51.6 % | 39.5 % | | **L3** + passive awareness (**AgentRadio**) | background `wait_for_mention` | **62.1 %** | **50.8 %** | The step from L2 to L3 changes **only** the communication mode. It wins 15 tasks and loses 2 with Opus 4.6 (exact McNemar test, p = 0.0023) and wins 17 while losing 3 with DeepSeek (p = 0.0026). Four Opus 4.6 agents under AgentRadio (62.1 %) surpass the strongest single-agent leaderboard entry, Claude Code with the newer Opus 4.8 (57.2 %). โ†’ [See the full results](#-results) ยท [paper](https://arxiv.org/abs/2607.28430) ยท [run it yourself](#-running-the-four-configurations) ## ๐Ÿ“ฃ News - **2026-08** โ€” AgentRadio was covered by [VentureBeat](https://venturebeat.com/): ["Four AI agents coordinating in real time outperformed Claude Opus 4.8 on enterprise coding tasks"](https://venturebeat.com/orchestration/four-ai-agents-coordinating-in-real-time-outperformed-claude-opus-4-8-on-enterprise-coding-tasks). ๐Ÿ“ฐ - **2026-07** โ€” The AgentRadio paper is released on [arXiv](https://arxiv.org/abs/2607.28430). ๐ŸŽ‰ - **2026-07** โ€” Code, adapters, and the full 124-task SWE-Atlas QnA setup are open-sourced. ๐Ÿš€ ## ๐Ÿ’ก Why AgentRadio * **Communication stops costing work** โ€” `wait_for_mention` runs as a *background task* of the harness, so a teammate's message surfaces at the next step boundary instead of consuming a turn. Agents no longer choose between working and listening. * **Mid-execution correction** โ€” in blocking systems a discovery cannot reach a teammate until the next phase boundary. Under passive awareness it lands immediately, and the teammate folds it into the task already in flight. * **No harness modification** โ€” the harness only has to run a shell command in the background, which mainstream coding harnesses already do. AgentRadio ships as a standalone message server plus three thin shell scripts. * **No extra LLM calls** โ€” the watcher is an ordinary OS process, not an agent step. The only new tokens an agent pays for are the messages that actually surface. * **Model-agnostic** โ€” the same protocol, prompts, and startup scripts run on Claude Opus 4.6 and on DeepSeek-V4-Pro through a LiteLLM translation proxy. * **A clean ablation ladder** โ€” B0 โ†’ L1 โ†’ L2 โ†’ L3 isolates division of labor, negotiation, and passive awareness one layer at a time, on identical harness settings. ## ๐Ÿงฉ How It Works ### The three primitives AgentRadio exposes three operations to every agent: | Primitive | Behavior | |---|---| | `create_thread(name, participants)` | Opens a named conversation on the message server and returns its identifier. | | `send_message(thread, content, mentions)` | Appends a message to a thread and returns immediately, whether or not anyone is listening. May @-mention specific agents. | | `wait_for_mention(timeout)` | Blocks until a message mentioning the caller arrives, then returns it together with a full snapshot of every thread โ€” so the caller never needs a second read to reconstruct context. | The layer takes no position on *when* an agent listens. Where `wait_for_mention` runs is the single degree of freedom separating the two communication modes: - **Foreground** โ†’ *blocking receive*. The agent stops working in order to listen. Every message heard costs a step of work. This is the L2 baseline. - **Background task** โ†’ *passive awareness*. The agent keeps working and any mention surfaces at the next step boundary, with no step spent listening. This is L3, full AgentRadio. Everything else โ€” the primitives, the threads, the protocol โ€” stays fixed. That single-bit difference is what the experiments isolate. ### The five-phase protocol Four agents run a fixed protocol of division of labor and negotiation. Agent-1 additionally serves as the **assembler**: it opens the planning, worklog, and final-answer threads, and gates every transition โ€” a phase ends only after it collects an explicit approval from every agent. 1. **P1 ยท Explore** โ€” every agent starts its background watcher, independently explores the repository, and drafts the sub-questions it sees. Nothing is sent. 2. **P2 ยท Divide** โ€” the assembler opens a planning thread. Agents pool their findings, negotiate a partition of the sub-questions, and revise it until every agent approves. 3. **P3 ยท Execute** โ€” each agent works its own sub-questions. A discovery triggers a worklog post the moment it is made: a finding that bears on a teammate, a contradiction with the agreed plan, an obstacle, or an abandoned dead end. 4. **P4 ยท Review** โ€” each agent broadcasts its findings with evidence in its own results thread. Reviewers post factual conflicts, thin evidence, and unmentioned observations, and can send a sub-question back to P3. 5. **P5 ยท Submit** โ€” the assembler composes the final answer from the approved results, broadcasts the draft for a last round of approvals, and submits. Under blocking receive the same five phases run unchanged, but the live sharing of P3 disappears: hearing a message costs a foreground wait, so agents fall silent while they work and a discovery cannot reach a teammate before P4. ## ๐Ÿ—‚๏ธ Repository Layout ``` data/qa/ 124 SWE-Atlas QnA tasks (harbor dataset scale-ai/swe-atlas-qna) multi_agent/ coral_multi_agent.py L2 adapter: division + negotiation (blocking receive) coral_multi_agent_ablation.py L1 adapter: division only coral_multi_agent_passive.py L3 adapter: full AgentRadio (passive awareness) startup.sh / startup_ablation.sh / startup_passive.sh per-agent bootstrap + protocol prompts (CLAUDE.md) coral-agent*.toml message-server agent definitions passive_scripts/ MCP-over-HTTP shell primitives (create_thread / send_message / wait_for_mention / read_resource) coral-server.jar message server (download from Releases, see below) monitor_coral_log.sh live thread/message monitor for running containers run_config/qa/ claude-token OAuth token helper full_run.sh B0 baseline batch runner (all 124 tasks) run_passive_multi_agent.sh L3 batch runner verify_local.py rubric verifier (LLM judge), run locally on a trial dir ``` Every task directory under `data/qa/` carries the instruction, the pinned execution environment, and the rubric set used by the verifier. --- ## ๐Ÿ“ฆ Setup Runs execute in Docker containers on [Modal](https://modal.com), orchestrated by [Harbor](https://github.com/laude-institute/harbor). One task = one container running the message server plus four Claude Code agents. ### 1. Docker Desktop Install from https://www.docker.com/products/docker-desktop/ and verify with `docker run hello-world`. ### 2. uv ```bash curl -LsSf https://astral.sh/uv/install.sh | sh ``` ### 3. Harbor (pinned to 0.6.4) Newer Harbor releases (0.7+) have breaking API changes that make these adapters fail. Pin the versions: | Component | Working version | |-----------|-----------------| | harbor | **0.6.4** | | modal | **1.4.2** | ```bash uv tool uninstall harbor 2>/dev/null || true uv tool install 'harbor[modal]==0.6.4' harbor --version # must show 0.6.4 ``` ### 4. Modal ```bash pip install 'modal==1.4.2' modal --version # must show 1.4.2 modal setup # opens browser to log in ``` ### 5. Claude Code ```bash curl -fsSL https://claude.ai/install.sh | sh claude --version ``` You need a **Claude Max subscription** for the agents. The verifier additionally needs an **Anthropic API key**. ### 6. Message server JAR The 106 MB server JAR is hosted as an anonymized artifact (too large for a git blob). The `confirm=t` parameter bypasses the large-file scan interstitial so `curl` gets the binary directly: ```bash curl -L -o multi_agent/coral-server.jar \ "https://drive.usercontent.google.com/download?id=17b40_1kXFrAC0pnN8w_7PPY13O7pYVke&export=download&confirm=t" ``` The adapters upload this JAR into each task container. Nothing needs to run locally, so no local JDK is required. ### 7. Token helper and .env ```bash cp run_config/qa/claude-token ~/.local/bin/claude-token chmod +x ~/.local/bin/claude-token cp .env.example .env # then fill in your Anthropic API key ``` ### Before each run: refresh the OAuth token The Claude Code OAuth token rotates. Each container gets a static snapshot at launch, and a stale token kills all four agents with 401 mid-run. Refresh before every session: ```bash claude /login # opens browser security find-generic-password -s "Claude Code-credentials" -w | python3 -c " import json, sys, os data = json.loads(sys.stdin.read()) oauth = data.get('claudeAiOauth', {}) with open(os.path.expanduser('~/.claude/.credentials.json'), 'w') as f: json.dump({'claudeAiOauth': oauth}, f, indent=2) print(f'Token refreshed. Expires at: {oauth.get(\"expiresAt\")}') " ~/.local/bin/claude-token --check source .env ``` --- ## โšก Running the Four Configurations All commands run from the repository root, after `source .env`. Task IDs are the directory names under `data/qa/` (repeat `-i` to batch; drop `-i` entirely to run all 124). `-n` is the number of concurrent tasks (one task = four agents for L1โ€“L3). ### B0 โ€” single agent (baseline) ```bash source .env harbor run \ -p ./data/qa \ -a claude-code \ -m "anthropic/claude-opus-4-6" \ -e modal -k 1 -n 1 \ -i "task-6905333b74f22949d97ba998" \ --ak reasoning_effort=high \ -o results/qa/ \ --job-name "baseline-ba998" \ -y ``` ### L1 โ€” four agents + division of labor Agent-1 explores briefly, partitions the question, and each agent solves its share independently. Answers are merged without review. ```bash source .env export PYTHONPATH="$(pwd):${PYTHONPATH:-}" harbor run \ -p ./data/qa \ --agent-import-path='multi_agent.coral_multi_agent_ablation:CoralMultiAgentAblation' \ -m "anthropic/claude-opus-4-6" \ -e modal -k 1 -n 1 \ -i "task-6905333b74f22949d97ba998" \ --ak reasoning_effort=high \ -o results/qa/ \ --job-name "division-ba998" \ -y ``` ### L2 โ€” + negotiation (blocking receive) The full five-phase protocol โ€” joint exploration, negotiated partition to unanimity, live execution, cross-review, assembled submission โ€” with `wait_for_mention` running in the **foreground**, so agents stop working in order to listen. ```bash source .env export PYTHONPATH="$(pwd):${PYTHONPATH:-}" harbor run \ -p ./data/qa \ --agent-import-path='multi_agent.coral_multi_agent:CoralMultiAgent' \ -m "anthropic/claude-opus-4-6" \ -e modal -k 1 -n 1 \ -i "task-6905333b74f22949d97ba998" \ --ak reasoning_effort=high \ -o results/qa/ \ --job-name "divneg-ba998" \ -y ``` ### L3 โ€” + passive awareness (full AgentRadio) Same protocol, but `wait_for_mention` runs as a **background task**: agents keep working and messages surface between steps. Claude Code gets no MCP config โ€” all communication goes through the thin shell wrappers in `passive_scripts/`. ```bash source .env export PYTHONPATH="$(pwd):${PYTHONPATH:-}" harbor run \ -p ./data/qa \ --agent-import-path='multi_agent.coral_multi_agent_passive:CoralMultiAgentPassive' \ -m "anthropic/claude-opus-4-6" \ -e modal -k 1 -n 1 \ -i "task-6905333b74f22949d97ba998" \ --ak reasoning_effort=high \ -o results/qa/ \ --job-name "passive-ba998" \ -y ``` `run_config/qa/run_passive_multi_agent.sh` wraps the same command as a batch runner, one harbor job per task id. --- ## ๐Ÿ”€ Running with DeepSeek-V4-Pro The multi-agent configurations (L1โ€“L3) can be run with **DeepSeek-V4-Pro** agents instead of Opus 4.6, reproducing the DeepSeek column of the results table. Everything about the protocol, prompts, startup scripts, and resume guard is identical; only the LLM backend changes. Claude Code speaks only the Anthropic Messages API, while DeepSeek is served through OpenRouter (OpenAI-compatible only). We bridge the two with a **LiteLLM translation proxy hosted once on Modal**. The task containers install nothing โ€” they just point `ANTHROPIC_BASE_URL` at the proxy's public URL. The rubric verifier is unchanged: it still uses your Anthropic judge (`OPENAI_API_KEY` / `EVAL_MODEL`). DeepSeek is only the *agent* backend. ### One-time proxy setup ```bash # 1. An OpenRouter API key with deepseek-v4-pro access (https://openrouter.ai/keys) # is stored as a Modal secret โ€” it never leaves your Modal account. modal secret create openrouter-deepseek OPENROUTER_API_KEY=sk-or-... # 2. Deploy the proxy. This prints your personal URL. modal deploy multi_agent/deepseek_litellm_modal.py # -> https://--deepseek-litellm-proxy-serve.modal.run # 3. Put that URL in .env so the adapters can find it: echo 'export AGENTRADIO_PROXY_URL=https://--deepseek-litellm-proxy-serve.modal.run' >> .env source .env ``` The proxy stays warm (`min_containers=1`); redeploy only after editing it. To stop billing when idle: `modal app stop deepseek-litellm-proxy` (a later `modal deploy` brings it back). ### L1 / L2 / L3 with DeepSeek Identical to the Opus commands above, but the import path points at the DeepSeek adapter and `-m "deepseek-v4-pro"` routes through the proxy. `source .env` must have exported `AGENTRADIO_PROXY_URL`. Task IDs and `-i` batching work exactly as above. #### DeepSeek B0 โ€” single agent (baseline) The DeepSeek baseline uses a thin subclass of the built-in `claude-code` agent (it forces the proxy endpoint and drops the OAuth token the built-in agent would otherwise re-mint), so it takes `--agent-import-path` rather than `-a claude-code`. ```bash source .env export PYTHONPATH="$(pwd):${PYTHONPATH:-}" harbor run \ -p ./data/qa \ --agent-import-path='multi_agent.claude_code_deepseek:ClaudeCodeDeepseek' \ -m "deepseek-v4-pro" \ -e modal -k 1 -n 1 \ -i "task-6905333b74f22949d97ba998" \ --ak reasoning_effort=high \ -o results/qa/ \ --job-name "deepseek-baseline-ba998" \ -y ``` #### DeepSeek L1 โ€” division only ```bash source .env export PYTHONPATH="$(pwd):${PYTHONPATH:-}" harbor run \ -p ./data/qa \ --agent-import-path='multi_agent.coral_multi_agent_ablation_deepseek:CoralMultiAgentAblationDeepseek' \ -m "deepseek-v4-pro" \ -e modal -k 1 -n 1 \ -i "task-6905333b74f22949d97ba998" \ --ak reasoning_effort=high \ -o results/qa/ \ --job-name "deepseek-division-ba998" \ -y ``` #### DeepSeek L2 โ€” + negotiation ```bash source .env export PYTHONPATH="$(pwd):${PYTHONPATH:-}" harbor run \ -p ./data/qa \ --agent-import-path='multi_agent.coral_multi_agent_deepseek:CoralMultiAgentDeepseek' \ -m "deepseek-v4-pro" \ -e modal -k 1 -n 1 \ -i "task-6905333b74f22949d97ba998" \ --ak reasoning_effort=high \ -o results/qa/ \ --job-name "deepseek-divneg-ba998" \ -y ``` #### DeepSeek L3 โ€” + passive awareness ```bash source .env export PYTHONPATH="$(pwd):${PYTHONPATH:-}" harbor run \ -p ./data/qa \ --agent-import-path='multi_agent.coral_multi_agent_passive_deepseek:CoralMultiAgentPassiveDeepseek' \ -m "deepseek-v4-pro" \ -e modal -k 1 -n 1 \ -i "task-6905333b74f22949d97ba998" \ --ak reasoning_effort=high \ -o results/qa/ \ --job-name "deepseek-passive-ba998" \ -y ``` The shared proxy injection (which swaps the LLM backend while inheriting all multi-agent logic, startup scripts, and the resume guard) lives in `multi_agent/deepseek_proxy.py`; the B0 baseline subclass is `multi_agent/claude_code_deepseek.py`. ### Resume a cancelled or failed job ```bash source .env export PYTHONPATH="$(pwd):${PYTHONPATH:-}" harbor job resume -p results/qa/ -f CancelledError -f RuntimeError ``` ### Live monitoring (optional, separate terminal) ```bash bash multi_agent/monitor_coral_log.sh # renders coral://state from the running container ``` --- ## ๐Ÿงช Scoring Each trial writes the team's answer to `/agent/answer.txt`. Score it with the benchmark's LLM judge: ```bash source .env python3 verify_local.py # e.g. python3 verify_local.py task-6905333b74f22949d97ba998 \ results/qa/divneg-ba998/task-6905333b74f22949d97ba998__XXXXX ``` This writes `/verifier/reward.txt` (1 only when every rubric passes) and `evaluation_results.json` (per-rubric scores). `pip install openai` if missing. ### Trial output structure ``` task-xxx__randomId/ โ”œโ”€โ”€ config.json / result.json / trial.log โ”œโ”€โ”€ agent/ โ”‚ โ”œโ”€โ”€ answer.txt # final answer (written by agent-1) โ”‚ โ”œโ”€โ”€ coral-server.log # threads and messages โ”‚ โ””โ”€โ”€ agent-{1..4}-claude-code.txt โ””โ”€โ”€ verifier/ โ”œโ”€โ”€ reward.txt โ””โ”€โ”€ evaluation_results.json ``` --- ## ๐Ÿ“Š Results Full results on SWE-Atlas QnA (124 tasks, 1,306 rubrics). Category rows give tasks resolved, with category sizes in parentheses. Within each model column every configuration uses the same harness and settings. `B0` = single Claude Code ยท `L1` = 4ร— Claude Code + division of labor ยท `L2` = L1 + negotiation ยท `L3` = L2 + passive awareness (AgentRadio). **Opus 4.6** | | B0 | L1 | L2 | L3 | |---|:---:|:---:|:---:|:---:| | Architecture and system design (44) | 15 | 13 | 24 | **30** | | Root-cause analysis (37) | 9 | 16 | 18 | **20** | | Code onboarding (28) | 11 | 12 | 14 | **18** | | Security (11) | 4 | **7** | **7** | **7** | | API and library integration (4) | 1 | 1 | 1 | **2** | | **All tasks resolved (124)** | 40 | 49 | 64 | **77** | | **Task accuracy (%)** | 32.3 | 39.5 | 51.6 | **62.1** | | **Rubric pass rate (%)** | 84.2 | 86.1 | 91.3 | **93.1** | **DeepSeek V4 Pro** | | B0 | L1 | L2 | L3 | |---|:---:|:---:|:---:|:---:| | Architecture and system design (44) | 14 | 13 | 17 | **24** | | Root-cause analysis (37) | 11 | 13 | 15 | **18** | | Code onboarding (28) | 7 | 8 | 10 | **13** | | Security (11) | 4 | 4 | 6 | **7** | | API and library integration (4) | 0 | 0 | 1 | **1** | | **All tasks resolved (124)** | 36 | 39 | 49 | **63** | | **Task accuracy (%)** | 29.0 | 31.4 | 39.5 | **50.8** | | **Rubric pass rate (%)** | 81.2 | 83.7 | 85.9 | **90.2** | **L3 vs. L2, exact McNemar on paired task outcomes** โ€” Opus 4.6: wins 15, loses 2, p = 0.0023. DeepSeek V4 Pro: wins 17, loses 3, p = 0.0026. Rubric-level analysis shows the passive-awareness gain growing with task difficulty, consistent with mid-course correction as the underlying mechanism. --- ## ๐Ÿ› ๏ธ Troubleshooting - **401 errors mid-run** โ€” the OAuth token snapshot went stale. Refresh (see above), then `harbor job resume -p results/qa/ -f NonZeroAgentExitCodeError`. - **`claude: not found` in coral-server.log** โ€” the startup scripts export `PATH="$HOME/.local/bin:$PATH"`; check that Claude Code installed inside the container. - **Alpine-based tasks** โ€” some tasks use Alpine images; the adapters auto-detect this and install an Alpine-compatible JDK. - **Inspecting communication** โ€” `grep "sent message\|created thread" /agent/coral-server.log | sed 's/\x1b\[[0-9;]*m//g'` --- ## ๐Ÿ™ Acknowledgements The task data is the [SWE-Atlas QnA](https://github.com/scaleapi/SWE-Atlas) benchmark (harbor dataset `scale-ai/swe-atlas-qna`) by Scale AI. Runs are orchestrated with [Harbor](https://github.com/laude-institute/harbor) on [Modal](https://modal.com). --- ## ๐Ÿ“š Citation ```bibtex @misc{ren2026agentradio, title = {AgentRadio: Passive Awareness for Long-Horizon Multi-Agent Collaboration}, author = {Xinxing Ren and Qianbo Zang and Ziyan Wang and Caelum Forder and Suman Deb and Peter Carroll and Zekun Guo}, year = {2026}, eprint = {2607.28430}, archivePrefix = {arXiv}, url = {https://arxiv.org/abs/2607.28430} } ``` --- ## ๐Ÿ“„ License Released under the [Apache License 2.0](LICENSE). --- Built at Coral AI Labs, SnT โ€” Universitรฉ du Luxembourg, King's College London, and the University of Hull.