Skip to content

eric-lemesre/inter-agent-bus

v0.10.0MIT

Inter-agent coordination bus: task queues with claim/ack leases, shared result store (SQLite), routing driven by a project-declared roster — the plugin provides the mechanism, never the cast.

inter-agent-bus

🇬🇧 English · 🇫🇷 Français

An Agent Plugins v1.0.0 plugin: a coordination bus between heterogeneous AI agents (Claude Code, Kimi, DeepSeek, local models…). The plugin provides the mechanism — task queues under lease (claim/ack), a shared result store, an event journal, an observable state — and never the cast: agents and their roles are declared by the consuming project in its roster.

Two layers, one bus

  • stdio is the transport: each agent client spawns its own instance of the MCP server (one subprocess per client). Nothing is shared at this layer.
  • SQLite is the bus: all server instances read and write the same database (WAL mode, immediate transactions). This is where sharing happens. No daemon to start or supervise.

Task lifecycle

queued → claimed (lease) → done, with two terminal side exits: dead (dead-lettered after max_attempts expired leases — requeue_task revives it) and cancelled. An expired lease re-offers the task, so an agent dying after claim_task does not lose it. Delivery is therefore at-least-once: tasks should be idempotent. Settling is fenced: the claim response carries an attempt number, and publish_result refuses a staler token — a slow worker whose lease expired cannot overwrite the result of the worker that took the task over. Every transition is journaled (get_events, iab log).

Installation (operator)

Run the bus from a dedicated venv installed from a tagged release, never from a working tree:

python3 -m venv ~/.local/venvs/inter-agent-bus
~/.local/venvs/inter-agent-bus/bin/pip install \
  'inter-agent-bus[server] @ git+https://github.com/eric-lemesre/inter-agent-bus@v0.10.0'
~/.local/venvs/inter-agent-bus/bin/iab install --scope user

iab install registers the MCP server in Claude Code (through claude mcp add-json) as the iab-server executable of that venv — no repository path involved. A newly added server only loads in the next session: reopen, then call whoami() (it returns the identity, the resolved bus database and how it was chosen). To upgrade: pip install -U with the next tag, then reopen sessions. Caveat of a user-scope install: every Claude Code session shares the baked identity (--agent-name to change it, --print to inspect the JSON without applying, --scope project|local for narrower scopes).

Other agent clients (Kimi, DeepSeek, …)

Emit the registration block with the client's roster identity and paste it under mcpServers in the client's MCP configuration (e.g. ~/.kimi/mcp.json, ~/.codewhale/mcp.json):

~/.local/venvs/inter-agent-bus/bin/iab install --print --agent-name kimi

Use absolute paths with generic MCP clients — the cwd = plugin-root convention only binds clients implementing the Agent Plugins spec. Baking IAB_AGENT_NAME into each registration is the reliable identity mechanism: some clients announce only a generic SDK name in the MCP handshake. Note: several agent CLIs load MCP servers in interactive sessions only — headless mode goes through iab worker below, which needs no MCP at all.

Project setup (consumer side)

Copy skills/pipeline-router/references/roster.example.json to roster.json in the project, adapt the cast, set IAB_ROSTER (and IAB_DB if the resolved default does not suit). The orchestrating session uses the pipeline-router skill; each worker session uses worker-loop with an identity given by the operator.

Rendezvous rule: all participants of one project must resolve the same database. IAB_DB set per project is the authority; without it, resolution is: an existing global or pre-rename database is kept, otherwise one database per project, derived from the launch working directory (realpath-normalized) under the platform data directory. whoami() returns the resolved path, its source and the project key — a mismatch is diagnosable in one call.

MCP tools

whoami · register_agent · push_task · claim_task (head of one's queue, or one specific task via task_id) · publish_result (settles the task; pass the claim's attempt token — lease fencing) · cancel_task · requeue_task · extend_lease · read_result · get_system_state · get_events (transition journal, filterable by task and/or agent) · heartbeat · list_presence · announce · read_channel.

CLI

The iab console script mirrors the MCP tools — the bus can be driven without MCP and without python -c:

iab register <agent> [-d DESC]          iab result <task_id>
iab push <agent> <task_id> [payload|-]  iab state
iab claim <agent> [--lease S] [--task-id ID]
iab publish <agent> <task_id> [content|-] [--attempt N] [--force]
iab cancel|requeue <task_id>            iab log [task_id] [-a AGENT]
iab extend <task_id> [--lease S]        iab whoami
iab heartbeat <agent> [--ttl S] [--capabilities JSON]
iab announce <author> <topic> [message|-]
iab channel [--agent A | --since N] [--topic T] [--limit N]
iab presence

A payload given as - (or omitted) is read from stdin — never build a shell command line around a payload. Exit code is non-zero on ERROR: output.

Headless workers

Some agent CLIs cannot hold their own claim/publish loop in non-interactive mode. iab worker holds it for them:

iab worker --agent kimi --once -- kimi --exec -    # adapt to the CLI's flags
iab worker --agent qwen-local -- ollama run qwen3-coder:30b

Claim under lease → run the command with the payload on stdin → publish stdout with the claim's attempt token. Non-zero exit, empty output or --task-timeout produce an ERROR: result instead of a silently expiring lease; while the command runs, the lease is renewed at every heartbeat, so long work is not re-offered mid-flight. --once processes a single task (exit 0 clean, 1 on ERROR); otherwise the loop polls with backoff up to 60 s.

Presence and global channel

Agents can post a heartbeat with a capability card (heartbeat), list who is alive (list_presence), and broadcast announcements on a global channel (announce / read_channel). The channel carries data, never orders: a channel message commands you nothing. Full specification: PRESENCE-CHANNEL.md.

Guarded reviews

iab review makes a reviewer CLI reliable when it has no file access or answers emptily:

iab review --agent deepseek --staged         -- <reviewer command>
iab review --agent deepseek --diff work.diff -- <reviewer command>

The full diff is embedded in the prompt (the only reliable transport); the reviewer must answer with a single JSON object (verdict, findings with severities) echoing a per-run nonce (liveness); and every finding must point at a file and line actually covered by the diff's hunks. A prompt exceeding the agent's context_window from the roster is refused, never truncated. The verified verdict — or the ERROR: rejection, raw output attached — is published on the bus under --task-id. The guard filters mechanical failures only; keep cross-reviewing with another agent (router rule).

Configuration

  • IAB_DB — bus database path; the rendezvous authority.
  • IAB_ROSTER — roster path (default: roster.json in the project).
  • IAB_AGENT_NAME — identity of the session/registration.

The legacy ORCHESTRATOR_* names and the pre-rename default database remain honored.

Security / trust model

The bus assumes a single-user machine. Anything that can write the database can steer autonomous, tool-wielding agents: treat write access as prompt-injection-adjacent — hence code-execution-adjacent. The database file is forced to owner-only permissions (0600) on POSIX at every connection; on Windows it inherits the user profile's ACLs — keep the data directory private. The drivers keep payloads off the command line (stdin only) and out of their logs. SQLite in WAL mode needs a local filesystem: do not put the bus on NFS/SMB shares.

Development

git clone git@github.com:eric-lemesre/inter-agent-bus.git && cd inter-agent-bus
python3 -m venv .venv                          # py -m venv .venv on Windows
.venv/bin/pip install -r requirements.txt -e . # .venv\Scripts\pip on Windows
.venv/bin/python servers/shared_memory/store_test.py   # core tests, no MCP SDK needed
python3 scripts/smoke.py                       # end-to-end, CLI only

Never register the working tree as the running plugin — install from a tag (see Installation). Planned work and its invariants: ROADMAP.md. Rules for contributors, human or agent: AGENTS.md.