AI Agent Coordination

Every amux agent gets a REST API at startup. They coordinate in HTTP — no framework, no shared filesystem, no race conditions.

// quick answer

How do amux agents coordinate without race conditions? amux injects $AMUX_URL and $AMUX_SESSION into every session at startup, plus the full REST API contract in global memory. Agents POST tasks to the board, claim them via SQLite compare-and-swap (POST /api/board/:id/claim — 200 if won, 409 if taken), peek at each other's output, and send mid-run messages. No framework, no file locks, no races.

The coordination primitives

amux exposes five primitives that any agent session can call via curl or requests. These are documented in the global memory that every session reads at startup — agents don't need to be told how to coordinate; they already know.

1. Atomic task claiming — the core primitive

The shared board (GET/POST /api/board) is a SQLite-backed kanban accessible to all agents. The claim endpoint is the key to race-free parallel work:

# Create a task (orchestrator agent)
curl -s -X POST -H 'Content-Type: application/json' \
  -d '{"title":"Migrate users table","status":"todo"}' \
  $AMUX_URL/api/board

# Claim it atomically (worker agent)
# Returns 200 if won, 409 if another agent already claimed it
curl -s -X POST -H 'Content-Type: application/json' \
  -d '{"session":"'$AMUX_SESSION'"}' \
  $AMUX_URL/api/board/TASK-5/claim

# Mark done with result
curl -s -X PATCH -H 'Content-Type: application/json' \
  -d '{"status":"done","desc":"Migrated 1.2M rows in 4m32s"}' \
  $AMUX_URL/api/board/TASK-5

The claim is atomic at the SQLite transaction level. Two agents can POST /claim simultaneously — exactly one gets 200, the other gets 409. Safe at 50+ concurrency with zero coordination overhead.

2. Inter-agent messaging

Send text to another agent's steering queue — delivered at its next turn boundary:

# Agent A redirects agent B mid-run
curl -s -X POST -H 'Content-Type: application/json' \
  -d '{"text":"Focus on the auth module first, skip payments for now"}' \
  $AMUX_URL/api/sessions/worker-b/send

This works during active agent turns (it queues and delivers at the next natural pause) and between turns. Useful for orchestrators redirecting workers based on new information, or for human-in-the-loop steering without interrupting the agent's flow.

3. Peer output inspection

Read another agent's recent terminal output — the last N lines of its tmux pane:

# Check if agent B has finished its current task
curl -s "$AMUX_URL/api/sessions/worker-b/peek?lines=20" | \
  python3 -c "import json,sys; print(json.load(sys.stdin).get('output',''))"

Use this for lightweight polling ("is agent B done yet?"), debugging ("what is agent B actually doing?"), or for orchestrators that want to consume an agent's output programmatically.

4. Shared global memory

A CLAUDE.md-style scratchpad that all sessions can read and write. Every session reads this at startup — it's how agents know about the API contract, the project context, and the coordination rules without being explicitly told:

curl -s $AMUX_URL/api/memory/global       # read
curl -s -X POST -H 'Content-Type: application/json' \
  -d '{"content":"# Updated project context\n..."}' \
  $AMUX_URL/api/memory/global              # write

5. Agent discovery

List all registered sessions and their current status:

curl -s $AMUX_URL/api/sessions | python3 -c "
import json, sys
for s in json.load(sys.stdin):
    print(s['name'], s.get('status','unknown'), '-', s.get('desc',''))
"

amux injects $AMUX_URL and $AMUX_SESSION into every session at startup. Every agent knows its own identity and can reach all peers via these two env vars — no hardcoded hostnames or session lists.

Common coordination patterns

Producer-consumer (most common)

One orchestrator agent creates tasks on the board; N worker agents race to claim and execute them. The SQLite CAS claim is the only synchronization primitive needed — no message queue, no lock files, no Redis.

# Orchestrator: create 10 tasks
for i in $(seq 1 10); do
  curl -s -X POST -H 'Content-Type: application/json' \
    -d "{\"title\":\"Process batch $i\",\"status\":\"todo\"}" \
    $AMUX_URL/api/board
done

# Worker (runs in each of N agents in a loop):
# 1. List todo tasks
# 2. Try to claim the first unclaimed one (POST /api/board/:id/claim)
# 3. Execute the task
# 4. Mark done
# 5. Repeat until no tasks remain

Pipeline (agent A → agent B → agent C)

Agent A creates a draft PR. Agent B reviews it and posts comments via the board. Agent C runs tests and reports results. Each stage creates a board task for the next stage to claim — the board is the handoff mechanism.

Role-based routing

Tag tasks with role annotations ([security], [docs], [backend]). Each specialized agent filters the board for tasks matching its role before claiming. The orchestrator doesn't need to know which agent handles which role — agents self-select.

Agent coordination approaches compared

ApproachSetup overheadAtomic tasksInter-agent messagingObservability
amux board + REST APIZero — built in✓ SQLite CAS✓ send / peekDashboard + board view
Custom orchestrator (LangGraph)Build & maintainCustomCustomCustom
File-based coordinationLow✗ race conditions
Claude Code Agent Teams (experimental)Feature flagPartialLimitedLimited
Separate message queue (Redis, SQS)Infra to provision + runSeparate tooling
Shared SQLite (direct DB access)Schema to design

Frequently asked questions

How do amux agents avoid working on the same task?

Atomic SQLite compare-and-swap claim: POST /api/board/:id/claim. Returns HTTP 200 if the agent won the claim, HTTP 409 if another agent already claimed it. The claim is atomic at the database level — no two agents can win the same task even when dozens call simultaneously.

Can agents send instructions to each other?

Yes. POST /api/sessions/:name/send delivers text to another session's steering queue, delivered at the next turn boundary. This works mid-run — agent A can redirect agent B while B is still actively working.

How does an agent know about other agents in the fleet?

amux injects $AMUX_URL and $AMUX_SESSION into every session environment at startup. The global memory contains the full REST API reference. Agents call GET /api/sessions to list all registered peers and their status.

Does agent coordination require a custom framework?

No. All coordination is plain HTTP — standard curl commands or Python requests calls inside any Claude Code session. No SDK, no framework, no custom protocol. The full API contract is in the global memory that every session reads at startup.

What is the amux producer-consumer pattern?

One orchestrator agent creates tasks on the board; N worker agents each loop POST /api/board/:id/claim until they win a task, execute it, mark it done, and repeat. The SQLite CAS claim ensures only one agent wins each task even at 50+ concurrency. No race conditions, no shared filesystem state.

See also: Kanban board for AI agents · Running 10+ agents in parallel · Web dashboard

Coordinate dozens of Claude Code agents without a framework

amux is an open-source control plane for running an AI engineering team from a single dashboard or your phone. MIT licensed, single Python file.

git clone https://github.com/mixpeek/amux && cd amux && ./install.sh
amux register myproject --dir ~/Dev/myproject --yolo
amux start myproject
amux serve  # → https://localhost:8822
⭐ Star on GitHub Get started