Swarm coordination MCP: file claims, agent presence, postboard intentions — the shared brain for teams of coding agents.
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Documented (README)
git clone https://github.com/spuentesp/zoanthrope{
"mcpServers": {
"zoanthrope": {
"command": "zoanthrope"
}
}
}MCP Servers overview
# zoanthrope
> The Tyranid creature that relays the Hive Mind's will to the swarm —
> zoanthrope is the coordination relay: who works where, what was
> promised, what happened.
**A swarm coordination MCP server.**
zoanthrope answers one question — *who is working on what?* — for a
workspace of collaborating agents. File claims with read/edit intents,
agent presence, a public postboard of intentions, per-path filesystem
leases against clobbering, a rejoin path for agents that went away and
came back, and a capped audit ring. It keeps a team of agents out of
each other's way and leaves a trail of who promised what.
## What it is
- a small MCP server (`zoanthrope mcp`) over stdio JSON-RPC
- a hook-facing CLI (`zoanthrope claim` / `release` / `rejoin` / `status`)
- a state registry at `.zoanthrope/state.json` plus filesystem leases at
`.zoanthrope/locks/` — zero daemons, nothing to install and keep alive
## Tool surface
All tools take and return JSON objects. Success bodies carry
`"ok": true`; a refused claim is a *successful* call whose body has
`"ok": false` plus the conflict shape.
| Tool | Arguments | Returns |
|---|---|---|
| `claim_files` | `agent_id`, `mode` (`claim` \| `release` \| `list`, default `claim`), `files` (paths or `{path, purpose?}`), `purpose?`, `intent?` (`edit` default \| `read`) | claim: `{ok, granted: [{path, claimed_at, purpose, intent}]}` or the conflict shape; release: `{ok, released: [path]}`; list: `{ok, claims}` |
| `list_claims` | `agent_id?` | `{ok, claims: [{path, agent, intent, claimed_at, purpose, held_by_stale}]}` |
| `who_am_i` | `agent_id` | `{ok, agent_id, name, kind, last_seen, stale, claims, posts}` |
| `list_active_agents` | `include_stale?` | `{ok, agents: [{agent_id, name, kind, last_seen, stale, claims_count}]}` |
| `register_agent` | `name`, `kind?` | `{ok, agent_id, name, kind, last_seen}` |
| `post_intention` | `agent_id`, `title`, `note`, `files?` | `{ok, post_id, post: {post_id, agent_id, title, files, note, status, created_at, updated_at}}` |
| `list_posts` | `agent_id?`, `status?` | `{ok, posts: [...]}` newest-updated first |
| `update_post` | `agent_id`, `post_id`, `status?` (`open`\|`taken`\|`done`\|`dropped`), `title?`, `note?`, `files?` | `{ok, post_id, post}` |
| `remove_post` | `agent_id`, `post_id` | `{ok, post_id, removed: true}` |
| `rejoin_agent` | `agent_id`, `files?` | `{ok, agent_id, claims_kept, claims_at_risk, view_epoch, board}` |
| `get_audit_log` | `limit?` (default 200), `since_unix?` | `{ok, events: [{ts, agent, action, path?, purpose?}]}` |
### The conflict shape
The heart of the product: a claim that clashes with another agent's
recorded intent is refused *all-or-nothing* and says exactly who is in
the way:
```json
{"ok": false, "holder": "beta", "path": "a.rs", "claimed_at": 1791780567.1, "purpose": "fix the parser", "holder_stale": false, "intent": "edit"}
```
### Claim semantics
A claim carries an intent (`read` or `edit`):
- an **edit** claim conflicts with anything another agent holds on the
path — exactly one writer at a time;
- a **read** claim conflicts with another agent's **edit**, but readers
co-hold happily with each other;
- an agent's recorded intent on a path is the **strongest** it holds —
a later weaker claim never hides a stronger one. Only release (then
re-claim) downgrades.
Claims are all-or-nothing per call: one conflict in a batch means
nothing is granted. A holder silent past the presence TTL is `stale`,
its claims are `held_by_stale`, and they still **block** — claims are
never auto-released; forcing one open is a policy this product did not
make.
A claim also binds the file's **content**: at claim (or re-claim) time
it records a content fingerprint — `mtime+size` always, plus `sha256`
for files ≤ 256 KiB, so same-size rewrites on coarse filesystems are
still caught. Every guarded write (the hook family) checks the file
against the claim's fingerprint first: if the file changed under the
claim — an out-of-band append, a generator run — the write is refused
with a `stale-claim` denial (holder is self) telling the agent to
re-read and re-claim. Re-claiming re-binds the fingerprint to the
current content; `release` drops it. No deliberate takeover exists: a
claim lock is a content promise, not just a writer lock.
### Filesystem leases (anti-clobbering)
A granted **edit** claim also takes a filesystem lease under
`.zoanthrope/locks/`: a nonce-named sentinel file per path, acquired
under a short `O_EXCL` guard (so concurrent acquirers cannot both pass
the holder scan), released by move-aside-and-verify (so a delayed
release can never delete a replacement holder's file). A live foreign
lease refuses a claim even when the registry is free — a lease-only
writer (an editor's save, a stray process) still gets the file to
itself. Read claims take no lease.
Leases carry a heartbeat mtime; one older than 60s
(`ZOANTHROPE_LEASE_TTL_SECS` overrides) is stale and may be taken
over, again move-aside-and-verify. `status` prints the lease layer so
orphaned sentinels are easy to spot.
### Postboard
Posts are the agents' public intentions — one line a human can read
while debugging a swarm. `post_intention` opens one (`status: open`);
`update_post` moves it through `taken` → `done`, or `dropped` if the
plan changed. Posts do not replace each other; an agent may carry
several. Only the posting agent may edit or remove its post.
### Rejoin
An agent that went away and came back (restart, sleep, disconnect)
calls `rejoin_agent`. It refreshes presence, re-asserts the agent's own
claims (filesystem lease refreshed or re-taken), republishes the board,
and reports — never rewrites. A claim the registry still credits to the
caller but where another agent now holds a live lease comes back as
`claims_at_risk`: reported, not stolen back, not released. Rejoin never
breaks claims, own or foreign.
## Quickstart
```console
$ cargo build --release
$ ./target/release/zoanthrope mcp
```
Then, over stdio (one JSON-RPC message per line):
```json
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"demo","version":"0"}}}
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"claim_files","arguments":{"agent_id":"alpha","files":[{"path":"src/a.rs","purpose":"fix the parser"}]}}}
```
Point another agent at the same file and its call returns the conflict
shape above with `"holder": "alpha"`.
Pre-edit hooks use the CLI mirror instead of MCP (see `hooks/`):
```console
$ zoanthrope claim --files a.rs,b.rs --agent alpha --purpose "fix bug" --intent edit
$ zoanthrope release --files a.rs,b.rs --agent alpha
$ zoanthrope rejoin --agent alpha
$ zoanthrope status [--workspace DIR]
```
Exit codes: `0` granted/ok, `1` conflict (or `ok: false`), `2` usage or
IO error. `--workspace` is optional everywhere; without it the root is
found by walking up from the current directory for `.git`.
### Wire the hooks (Claude Code)
The guard family claims every file a tool call would mutate and, in
blocking mode, turns conflicts into tool-call denials. This is the
exact wiring that ran the recorded collision experiments — copy it
into your workspace's `.claude/settings.json` (adjust the paths to
where you keep the repo):
```json
{
"hooks": {
"PreToolUse": [
{ "matcher": "Edit|Write|MultiEdit|Bash",
"hooks": [{ "type": "command", "command": "/path/to/zoanthrope/hooks/claude-code/claim-guard.sh" }] }
],
"PostToolUse": [
{ "matcher": "Edit|Write|MultiEdit|Bash",
"hooks": [{ "type": "command", "command": "/path/to/zoanthrope/hooks/claude-code/release-guard.sh" }] },
{ "matcher": ".*",
"hooks": [{ "type": "command", "command": "/path/to/zoanthrope/hooks/claude-code/watch.sh" }] }
]
}
}
```
Each agent needs its identity in the environment (`ZOANTHROPE_AGENT=alpha`,
…) — see `hooks/README.md` for the identity resolution order and how
to port the hooks to other agent frameworks.
**One wiring, both modes.** Advisory vs blocking is a runtime mode,
not a different hook: this wiring serves both. `claim-guard.sh`
resolves the mode per tool call, highest priority wins:
1. `ZOANTHROPE_MODE` env var (`advisory` | `blocking`) — the
per-agent override, so a swarm can block its bots and leave one
advisory actor;
2. `.zoanthrope/config.json` at the workspace root (found by walking
up to the git toplevel, like the CLI; the file is optional):
```json
{"mode": "advisory"}
```
3. default: `blocking` (the experiment-proven behavior).
In `advisory` mode the guard claims the file, prints the
claim/conflict JSON to stderr, and always exits 0 — it never emits a
`permissionDecision: deny`. In `blocking` mode a conflict denies the
tool call: exit 2, reason naming the holder (unchanged). An invalid
mode value falls back to `blocking` with one warning line on stderr —
a hook never crashes. `pre-edit.sh` remains as the legacy advisory
alias; `release-guard.sh` and `watch.sh` never deny, so the mode does
not apply to them.
## Instructions for agents
Paste this into your swarm's prompt or `AGENTS.md` — it is the protocol
the collision experiments validated:
```text
A coordination service (zoanthrope) is active in this workspace.
- Before touching shared files, post your intention (`post_intention` /
`zoanthrope claim --files … --agent <you> --purpose "…"`).
- An edit may be DENIED with a reason naming the holder. That means
another agent owns the file right now: wait briefly, then retry
(up to 3 times). If still denied, work on something else and record
it — never work around the lock (no out-of-band writes).
- Prefer append/insert on shared files; if you must rewrite a file
whole, read it back after writing and merge anything that appeared.
- Post what you plan to do on the postboard before you start, and
update the post when done (`update_post`).
- If you return after being away, call `zoanthrope rWhat people ask about zoanthrope
What is spuentesp/zoanthrope?
+
spuentesp/zoanthrope is mcp servers for the Claude AI ecosystem. Swarm coordination MCP: file claims, agent presence, postboard intentions — the shared brain for teams of coding agents. It has 0 GitHub stars and its last recorded update is dated 2026-10-12.
How do I install zoanthrope?
+
You can install zoanthrope by cloning the repository (https://github.com/spuentesp/zoanthrope) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is spuentesp/zoanthrope safe to use?
+
Our security agent has analyzed spuentesp/zoanthrope and assigned a Trust Score of 87/100 (tier: Trusted). See the full breakdown of passed checks and flags on this page.
Who maintains spuentesp/zoanthrope?
+
spuentesp/zoanthrope is maintained by spuentesp. The last recorded GitHub activity is dated 2026-10-12, with 0 open issues.
Are there alternatives to zoanthrope?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy zoanthrope to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/spuentesp-zoanthrope)<a href="https://claudewave.com/repo/spuentesp-zoanthrope"><img src="https://claudewave.com/api/badge/spuentesp-zoanthrope" alt="Featured on ClaudeWave: spuentesp/zoanthrope" width="320" height="64" /></a>More MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
Reverse engineer anything with agents, from app behavior down to native binaries.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev