Board-mediated multi-agent coordination in ~500 lines of Python
Project description
Board-mediated multi-agent coordination in ~500 lines of Python.
Multiple AI agents work in parallel on a shared task board.
They never talk to each other — they coordinate exclusively through SQLite.
Quickstart · Commands · How it works · Marcus
What it looks like
$ mini build "a snake game in Python"
Decomposing goal → 8 tasks
Spawning 3 agents (DAG recommends 3) in tmux session 'marcus-snake-game-1146'
Spawned agent-1 (pane 0)
Spawned agent-2 (pane 1)
Spawned agent-3 (pane 2)
✓ 3 agents running. mini watch to follow along.
mini dag shows the decomposed work as it's running:
╭────────────────────╮
│ project structure │
╰────────────────────╯
│
┌─────────┴─────────────┐
▼ ▼
╭────────────────────╮ ╭────────────────────╮
│ game state model │ │ render engine │
╰────────────────────╯ ╰────────────────────╯
│ │
└────────┬──────────────┘
▼
╭────────────────────╮
│ collision logic │
╰────────────────────╯
│
▼
╭────────────────────╮
│ game loop │
╰────────────────────╯
mini bench measures coordination overhead after the run completes:
Bench — snake-game-1146
─────────────────────────────────────
Wall time 8m 34s
Agent work 18m 12s
Utilization 70.8%
Coordination tax 29.2%
Tasks 8 (8 done)
The idea
Most multi-agent frameworks let agents talk to each other directly. marcus-mini
does the opposite: agents are blind to each other and coordinate only through
a shared board.
Three invariants hold in every run:
- Agents self-select work. The board assigns nothing — agents pull the next available task whose dependencies are all complete.
- Agents make all implementation decisions. The board says what to build, never how.
- Agents communicate only through the board. Artifacts and decisions logged to a task become context for downstream agents. No direct messages, no shared memory outside the board.
This mirrors how distributed teams actually work: a shared backlog, async handoffs, no mandatory standups.
Quickstart
Requirements: Python 3.11+, Claude Code CLI, tmux
pip install marcus-mini
export MINI_API_KEY=sk-ant-... # your Anthropic key — for decomposition only
mini build "a snake game in Python"
Why
MINI_API_KEYand notANTHROPIC_API_KEY? Claude Code agents inherit your shell environment. IfANTHROPIC_API_KEYis set, agents use it for every API call — even if you have a Claude subscription — and you get charged.MINI_API_KEYis only read by the decomposer (one call permini build). Agents run under your subscription key, not this one.
mini build will:
- Call Claude to decompose the goal into a parallel task DAG
- Persist all tasks to a local SQLite board
- Spawn N agents in a tmux session (N = DAG width)
- Each agent loops: claim task → implement → log artifacts → mark done
Watch the board live:
mini watch # live-refreshing kanban
mini status # per-agent activity
mini bench # coordination metrics after completion
Install
pip install marcus-mini
Or from source:
git clone https://github.com/lwgray/marcus-mini
cd marcus-mini
pip install -e .
Commands
Build & monitor
| Command | Description |
|---|---|
mini build "goal" |
Decompose goal, spawn agents |
mini watch |
Live kanban board (auto-exits on completion) |
mini board |
Static kanban snapshot |
mini status |
Per-agent activity with staleness warnings |
mini dag |
ASCII dependency graph |
mini tasks |
Task list with dependency info |
mini progress |
Completion percentage |
mini time |
Project elapsed time |
mini logs |
Tail agent log files |
mini wait |
Block until all tasks reach DONE/FAILED (scripting-friendly) |
Measure
| Command | Description |
|---|---|
mini bench |
Wall time, utilization, coordination tax |
Manage projects
| Command | Description |
|---|---|
mini projects |
Running projects (--all to see completed too) |
mini load |
Total live agents across all running projects |
mini open |
Print output directory (cd $(mini open)) |
mini stop |
Kill the current project's agents (DB + tmux) |
mini stop --all |
Stop every running project (type STOP to confirm) |
mini purge |
Wipe every project from the DB (type DELETE to confirm) |
mini config |
View/set API key env var |
Common flags
mini build "goal" --agents 4 # override agent count
mini build "goal" --output-dir ~/myproject
mini watch --interval 5 # refresh every 5s
mini bench --project my-project-1200
mini wait --interval 30 --timeout 5400 # 90-min ceiling
How it works
mini build "snake game"
│
▼
┌─────────────┐
│ decomposer │ Claude call → flat task list + dependency DAG
└──────┬──────┘
│
▼
┌─────────────┐
│ board │ SQLite (WAL mode) — the shared environment
└──────┬──────┘
│ MCP server exposes 5 tools to each agent
│
┌────┴────┐
│ │
agent-1 agent-2 ... agent-N (tmux panes)
│ │
└─────────┘
read/write the same board, never each other
Board MCP tools (what agents see)
| Tool | Purpose |
|---|---|
request_next_task |
Claim next task whose deps are all DONE |
log_artifact |
Store output (API spec, schema, file path) |
log_decision |
Record an architectural choice |
get_task_context |
Read artifacts from dependency tasks |
report_done |
Mark task complete, unblock dependents |
Task assignment (atomic SQL)
A task is claimable when status = 'TODO' and every dependency has
status = 'DONE'. The claim runs inside BEGIN EXCLUSIVE with a
json_each() dependency check — no race conditions, no external lock manager.
Coordination tax
mini bench measures the gap between theoretical and actual parallelism:
agent utilization = total task work / (n_agents × wall_time)
coordination tax = 1 − utilization
A tax of 0 % means every agent was always working. Typical software projects land at 30–60 % because of the critical path.
Project structure
marcus-mini/
├── marcus_mini/
│ ├── board.py # SQLite board + async API
│ ├── board_server.py # MCP server (5 tools)
│ ├── cli.py # mini CLI (Click)
│ ├── decomposer.py # Claude → task DAG
│ ├── models.py # Task dataclass
│ ├── monitor.py # tmux monitor pane
│ └── spawn.py # tmux agent spawner
├── prompts/
│ └── agent_prompt.md # agent loop instructions
├── tests/
└── pyproject.toml
Design discipline: the Mini Red Line
marcus-mini is intentionally small. Every proposed feature has to pass one test:
"Does coordination break without this?" Yes → allowed. No → it doesn't belong in mini.
What's ruled out, even if it would be useful:
- Observability beyond
mini status(no dashboards, metrics pipelines) - Resilience infrastructure (no retry, circuit breakers, fallbacks)
- Rich configuration (one flat JSON file, period)
- External integrations (no Slack, GitHub, webhooks)
- Agent capability management (no skills, tools, specializations)
- Scheduling (no cron, recurring tasks)
What stays, even if it adds lines of code:
- Correctness fixes (stall detection, accurate liveness checks)
- Coordination primitives (task claiming, dependency resolution, spawning)
- Measurement (
mini bench, timing, coordination tax)
If a feature would be at home in Marcus, it doesn't belong in mini.
The evolution: Marcus
marcus-mini proves the concept on one stack: SQLite, Claude, tmux. Three
moving parts, ~500 lines of coordination, intentionally crippled where Marcus
shines.
Marcus takes the same board-mediated primitives and turns them into a production platform. Here is what Marcus does that mini cannot:
| Capability | mini | Marcus |
|---|---|---|
| Contract-first decomposition — agents agree on APIs/schemas before any code is written, so coordination works in domains without code (legal, scientific, design) | flat task DAG only | full contract synthesis pre-fork |
| Observability — structured run logs, experiment tracking, cross-run comparison, dashboards | mini status + mini bench |
full telemetry pipeline + Cato dashboard |
| Resilience — agent retry, circuit breakers, error taxonomy, automatic stall recovery, lease-based work claiming | none (fails loud) | error framework + lease/recovery layer |
| Provider abstraction — board protocol independent of which LLM or which agent runtime | Claude + Claude Code only | multi-provider board protocol |
| Domain extensibility — coordinate non-software work via contract templates | software builds only | research, ops, content, analysis |
| Multi-team / multi-project — concurrent boards, RBAC, shared artifact registry | single user, single board | team and tenant isolation |
| Configuration — environments, profiles, per-agent tuning | one flat JSON | hierarchical config + per-environment overrides |
| Scheduling — recurring tasks, cron, triggered runs | one build at a time | full scheduler |
In short: mini is the experiment. Marcus is the platform. If you find yourself wanting any row in the right column, you have already outgrown mini — graduate to Marcus.
Known scope limitations of mini
- Claude-only. The decomposer uses the Anthropic SDK directly, and agents are Claude Code processes. There is no provider abstraction. This is a deliberate scope choice for a research instrument — Marcus handles multi-provider.
- Single user, single key. No multi-tenancy, no RBAC, no team workflows.
- Local only. SQLite + tmux on one machine. No remote agents, no cluster.
- Best effort failure handling. If an agent dies or the API quota runs out, mini stops loud — there is no auto-recovery. By design.
Why not CrewAI / AutoGen / LangGraph?
Those frameworks route messages between agents. marcus-mini does not. Agents
in this system are genuinely autonomous — they pull work, they decide how to do
it, they post results. The board is the only channel.
This means: parallelism is structural (DAG-derived), not programmed. You don't write agent communication logic. You write a goal, and the board handles the rest.
Contributing
See CONTRIBUTING.md. Bug reports and PRs welcome — but new features must pass the Red Line test above.
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 marcus_mini-0.1.1.tar.gz.
File metadata
- Download URL: marcus_mini-0.1.1.tar.gz
- Upload date:
- Size: 51.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c36594ce301da49f209668366846811f24f9bb67e0c989aa1307bb1b1e9f4543
|
|
| MD5 |
f1ecae6275cef5da55cafd2215c32fa1
|
|
| BLAKE2b-256 |
a4fce077a878989cc8ebbfaab76a9aa681ae949eb81c8ad169c978458c9f0a36
|
Provenance
The following attestation bundles were made for marcus_mini-0.1.1.tar.gz:
Publisher:
publish.yml on lwgray/marcus-mini
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
marcus_mini-0.1.1.tar.gz -
Subject digest:
c36594ce301da49f209668366846811f24f9bb67e0c989aa1307bb1b1e9f4543 - Sigstore transparency entry: 1418993623
- Sigstore integration time:
-
Permalink:
lwgray/marcus-mini@cd1f5fd510342437d290f2fa48ff02868a177e29 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/lwgray
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@cd1f5fd510342437d290f2fa48ff02868a177e29 -
Trigger Event:
push
-
Statement type:
File details
Details for the file marcus_mini-0.1.1-py3-none-any.whl.
File metadata
- Download URL: marcus_mini-0.1.1-py3-none-any.whl
- Upload date:
- Size: 44.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 |
702d53956a972d0beab871f6beb6aa2d3b6f268755e4c40785f5cf442a3e7e1d
|
|
| MD5 |
25b5008575a1150d5972b9fd452b590d
|
|
| BLAKE2b-256 |
0785f3ac62a062cc6a18bfd3760fa2361ece35c7e1b1e9cabf7cdf6f94011e78
|
Provenance
The following attestation bundles were made for marcus_mini-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on lwgray/marcus-mini
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
marcus_mini-0.1.1-py3-none-any.whl -
Subject digest:
702d53956a972d0beab871f6beb6aa2d3b6f268755e4c40785f5cf442a3e7e1d - Sigstore transparency entry: 1418993708
- Sigstore integration time:
-
Permalink:
lwgray/marcus-mini@cd1f5fd510342437d290f2fa48ff02868a177e29 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/lwgray
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@cd1f5fd510342437d290f2fa48ff02868a177e29 -
Trigger Event:
push
-
Statement type: