
zoanthrope
io.github.spuentesp由 GitHub 帳號 spuentesp 發布v0.1.6更新於 Oct 24, 2026
Coordination relay for agent swarms: file claims, presence, postboard intentions, leases, audit.
概覽
一個本機協調中繼,讓多個編碼代理認領檔案、公布意圖,並查看誰在處理什麼。
- 可以做什麼
- 認領、釋放與列出檔案認領,帶讀取或編輯意圖;衝突時整批拒絕並指出持有者,同時加檔案系統租約防止覆寫。列出認領與作用中的代理,註冊代理,並查詢自身的身分、認領與公告。發布、列出、更新與刪除公開公告板意圖,狀態為 open、taken、done 或 dropped。重新啟動後重新加入,重申在線狀態與自身認領,並查看變化。讀取有上限的協調事件稽核記錄。
- 適用情境
- 當多個代理或工作階段編輯同一工作區、需要避免重疊寫入時使用,或需要一份可讀的「誰承諾了什麼」紀錄時使用。它面向多代理編碼情境,而非單一代理使用。
- 執行需求
- 以本機 stdio 程序執行,透過 npx 從 npm 套件啟動;README 也說明可用 Cargo 從原始碼建置。狀態保存在工作區根目錄的 .zoanthrope 目錄中,未指定工作區時會向上尋找 git 頂層目錄。清單未宣告驗證或環境變數;README 提到掛鉤接線時可選用 ZOANTHROPE_AGENT 等設定。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 zoanthrope,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
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.jsonplus 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.
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:
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.
A claim can also carry caller stamps: opaque {name, value} pairs
you computed yourself — a symbol fingerprint, a hash, anything —
attached with stamps on claim_files or --stamp name=value on the
CLI (repeatable). zoanthrope stores caller stamps and re-checks only
its own file stamp; verifying caller stamps is the caller's business.
They come back on grants, in conflicts (a waiting agent sees what the
holder pinned), in list_claims, and in who_am_i. A re-claim that
passes stamps replaces the stored set outright; one without keeps the
pins already set; release drops them with the claim.
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
Then, over stdio (one JSON-RPC message per line):
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/):
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):
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:
-
ZOANTHROPE_MODEenv var (advisory|blocking) — the per-agent override, so a swarm can block its bots and leave one advisory actor; -
.zoanthrope/config.jsonat the workspace root (found by walking up to the git toplevel, like the CLI; the file is optional): -
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:
For consultation and debugging (who holds what, stale agents, orphaned
claims), give your agents skills/zoanthrope/SKILL.md.
State
Everything lives in .zoanthrope/state.json at the workspace root:
claims, agents, posts, the published board (who holds what, stamped
with a generation epoch), and an append-only audit ring capped at
1000 events. Writes are atomic (temp file + rename — the rename is the
generation publish) and serialized by a lock file. A state file from a
different format version is refused with instructions; move
.zoanthrope/ aside to start fresh.
Presence TTL defaults to 15 minutes; ZOANTHROPE_TTL_SECS overrides.
Performance
Decide in nanoseconds, persist in microseconds, scale to 128
concurrent agents without losing a write. The guarantee covers write
paths that go through the guarded hooks (Edit/Write/MultiEdit
and recognized Bash mutations); unparseable commands are audited as
unclaimed-mutation rather than blocked, and generator scripts
(node script.js) are not automatically covered unless they write
through recognized idioms — the audit trail remains the safety net.
All numbers measured on this machine; each family reproduces with the
command named.
Latency — cargo run --release --bin zoo-bench:
Persistence is the cost, the decision is not. The contended-8 p95 is 7.3 ms; under the earlier fixed 20 ms poll the same tail reached 101 ms, and lock acquisition now backs off exponentially to bring it down. Postboard creation runs at 614 posts/s.
Clobber chaos — cargo test --release --test clobber_chaos -- --ignored (scale with ZOO_CHAOS_WORKERS):
Prevention holds as the swarm grows. One documented limit, plainly: the post-hoc stomp detector samples faster than it can observe when writes exceed ~10⁵/s — prevention (the lock) is the guarantee; the audit trail is best-effort at machine-gun rates.
The A/B with real agents — 3 concurrent agents on shared files,
locked arm vs an unguarded control (full protocol and per-run data in
experiments/zoo-ab-2026-10-12.md): the locked arm finished with
0 lost work, 3 denials that named the holder, all recovered on
retry, at equal wall time (53.1 s vs 52.9 s). Scope, framed as
coverage: tool-mediated edits (Edit/Write) ride the host harness's
own CAS/OCC — verified 0 lost work in 24 agent runs — so the lock
is engineered for the vector that escapes those tools: Bash
mutations, codemods, generators, scripts. On that vector the
round-3 table reads 0 vs 1 lost, with +6 in-flight clobbers
self-healed in the control.
Formal guarantees
The coordination core is checked against TLA+ models in formal/:
PresenceClaims— claim arbitration: no conflicting holders, read co-holding, and strongest-intent recording;FsLease/FsLeaseGuard— filesystem lease exclusion, the anti-clobbering core (move-aside-and-verify release,O_EXCLacquire guard);RejoinProtocol— returning agents re-assert without breaking claims, own or foreign.
Verified with TLC via formal/check.sh: 11/11 configurations — 4
invariant configurations green, and 7 negative-control configurations
reproduce their counterexamples (the specs demonstrably catch the
failure modes they claim to: broken arbitration, unguarded leases,
leaky rejoin). One command to re-verify:
(TLA2TOOLS_JAR points at a tla2tools.jar, TLA+ tools v1.8.0; the
spec→code mapping lives in formal/README.md.)
Development
tests/mcp_smoke.rs spawns zoanthrope mcp and runs the full
initialize → tools/list → claim → conflict → postboard round trip →
rejoin → release over stdio. npm-shim/ is the @spuentesp/zoanthrope
node launcher (thin, no download machinery — it forwards to a binary on
PATH or ZOANTHROPE_BIN).
License
MIT — see LICENSE.
來源:README.md,提交 ef15afc
工具
0版本歷史
2- v0.1.6最新Oct 14, 2026
- v0.1.2Oct 13, 2026
評分
已滿足適用檢查項的 50%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分