Skip to main content
Glama

CPG-Radio

A fork of the CPG server that adds non-blocking peer messaging and a durable task-lease layer on top of the Cognitive Planning Graph.

The base server is memory with no bus: it models a completed fan-out run (WORKFLOW → WORKER → STRUCTURED_RESULT) but gives no agent a way to tell another anything while work is in flight. AgentRadio-style message buses are the converse — a bus with no memory, whose threads evaporate at the end of a run.

CPG-Radio adds the bus, and every message is also a typed, provenance-linked, FTS + embedding-searchable graph node. Passive awareness that stays queryable after the run and across sessions.

Section references below (DESIGN §x, SPEC §y) point at internal design documents that are not published; they are kept as provenance markers on the code comments that cite them.


What's new

Messaging (DESIGN §6.1)

Tool

What it does

create_thread

Open a THREAD node — a named channel for one topic or handoff. Validates any workflow_id / task_ids it links.

send_message

Post a MESSAGE to a thread as the calling agent. Creates the node, posted_in / replies_to / refers_to edges, and the ordering index row. Never waits for a reader.

poll_messages

Read messages newer than a cursor, oldest first, excluding your own. Read-only — it does not advance any cursor.

ack_messages

The only writer of the caller's cursor. Idempotent and forward-only; a replayed or stale ack cannot re-deliver processed messages.

wait_for_mention

Block up to 30 s for a message mentioning you (or broadcasting to *). Returns immediately if one is already pending; expiry is an empty success with timed_out: true, never an error.

Session identity (§6.2)

Tool

What it does

join_session

Bind this connection to an existing active session and declare your agent id. Returns a binding_token that preserves this logical identity when several agents share one MCP transport. Archives nothing.

Task leases (§6.3)

Tool

What it does

claim_task

Atomically take the lease on a TASK. Succeeds when it is unowned, expired, or already yours. Losing the race returns claimed: false with the real owner — losing is normal, not an exception.

renew_lease

Extend your lease. renewed: false means the task was reaped and reassigned, and you must stop working on it.

release_task

Give the lease up with a terminal status (or planned, a voluntary hand-back). Requires the lease_generation you hold.

worker_heartbeat

Stamp heartbeat_at on your own WORKER node so the reaper does not treat it as stale. Refused for another agent's worker.

complete_worker

Close your own WORKER as completed or failed; idempotent for an already-terminal worker and refused for another agent's worker.

Tips

Tool

What it does

drop_tip

Store a short project TIP (command, check-first, or craft) as the bound agent. Normalized-text duplicates return the existing id; supersedes_id retires an older tip.

tips

List tips by usefulness and recency, or search them through the existing hybrid FTS + embedding path with a usefulness boost. Superseded tips are hidden by default.

tip_useful

Give one idempotent usefulness vote per agent.

join_session and plan_session surface up to five top project tips on arrival. Pass the returned binding_token on later identity-bearing calls. A connection that has carried more than one agent identity rejects tokenless identity-bearing calls, preventing a sibling join from redirecting messages, acknowledgements, leases, worker completion, or result authorship. Ordinary cpg_query calls exclude TIP nodes unless node_types explicitly includes TIP, keeping operational advice separate from normal graph recall.

Swarm coordination plane

Area

Tools and guarantees

Authenticated campaigns

create_campaign, invite_member, join_campaign, revoke_member. Tokens are generated once, stored only as SHA-256 digests, bound to the connection, role-scoped, and rechecked against active membership on every protected operation.

Information barriers

Campaign threads enforce open, campaign, or exact participants access. Workflows, workers, structured results, spawned-worker views, and tips carry server-stamped campaign provenance. Messages carry trust, non-executable authority, visibility, sharing policy, priority, deadline, acknowledgement, supersession, and resolution metadata. cpg_query applies access policy before FTS/vector ranking.

Synchronization

publish_signal is a versioned CAS register with TTL and evidence refs. create_barrier / arrive_barrier provide explicit participant, quorum, phase, deadline, and CAS semantics.

Resource coordination

claim_resource, renew_resource, and release_resource manage shared/exclusive leases for names such as gpu:0, path:/repo, or server:8773, with TTLs and generations.

Reliable delivery

subscribe_thread, poll_thread, and ack_thread give each thread an independent durable cursor. A requires_ack message atomically creates one delivered receipt per authorized recipient; ack_delivery transitions only that recipient's obligation. Each thread is capped at 1,000 outstanding obligations, and protocol_health separates pending, overdue, and legacy orphaned requirements.

Atomic lifecycle

post_progress and complete_assignment combine lease, heartbeat/result, worker, and message mutations in one idempotent transaction. Self-managed workers close there; live spawned workers return worker_completion="supervisor_owned" and remain under the supervisor's single-writer lifecycle.

Independent work

commit_result / reveal_result seal outputs before reveal. Bound workers cannot attribute structured results to another worker.

Governance and health

Campaign command tips are quarantined until moderate_tip approves them with evidence. protocol_health reports coordination failures without returning message bodies.

Staleness

stale_report (read-only) lists running workers past the heartbeat threshold, leased tasks whose claimant's worker is terminal or missing, a gpu.lock owner.json that disagrees with the lease claimant, and watchers of finished jobs. register_watch / close_watch let a watcher declare the job (worker id, label, or done-file) it waits on so the report can see it. Added 2026-09-05 after seven of nine local log watchers were found tailing jobs that had ended hours earlier.

Legacy session threads remain open. Migrate a crew by creating a campaign, issuing each stable agent a membership token through a trusted channel, having each call join_campaign, then creating campaign or participant threads. Planning or joining another session clears the connection's old campaign grant. Message and TIP text are always data; no body invokes a tool or changes control state, regardless of its authority label.

Reaper (§6.4) — a background task, not a tool. Every 60 s it returns expired task leases to planned (bumping the generation and telling the linked thread), CAS-expires overdue barriers and shared/exclusive resource leases with dedicated audit events, fails WORKERs with no heartbeat for an hour, and marks a WORKFLOW whose workers have all terminated as blocked. Expired coordination records are retained, and resource fencing generations remain monotonic when reclaimed. It never auto-completed anything: completion is a claim about results, and only an agent may make it. A coordinator can explicitly reconcile blocked to completed after it has collected the terminal results.

Everything else from the base server — cpg_think, record_fact, record_belief, plan_session, update_task, replan, start_workflow, update_workflow, register_worker, record_structured_result, import_fable_trace, record_execution, reflect, resolve_contradiction, and the three cpg://session/* resources — keeps its existing contract. cpg_query, get_nodes, and record_structured_result now receive caller context so access and authorship can be enforced.


The agent protocol

A crew is not a new entity: it is one session_id that several agents joined. Because nodes stay session-scoped, cpg_query's existing session_scope: current | project | all gives crew-scoped and cross-crew recall for free.

join_session  →  claim_task  →  work  →  poll / ack  →  release_task
  1. join_session(session_id, agent_id) — or plan_session(..., agent_id=..., archive_previous=False) if you are the one opening the session. Identity is bound here. Keep the returned binding_token and pass it to later identity-bearing tools. No later tool takes an agent_id argument.

  2. claim_task(task_id) — take the lease before touching the work. Keep the returned lease_generation; every later mutation needs it. claimed: false just means someone else got there first — pick another task.

  3. Work. Call renew_lease if you will exceed the lease (default 900 s, clamped to [60, 7200]), and worker_heartbeat if you registered a worker.

  4. poll_messages / ack_messages between work steps. Poll is read-only, so ack only what you have actually processed; a crash between the two re-delivers rather than loses. Post your own findings with send_message, mentioning the agents who need them.

  5. release_task(task_id, lease_generation, status) — done, done_pending_verification, failed, blocked, or planned to hand it back.

If you crash instead, the reaper does step 5 for you within a minute.

Parameter names are singular by design: after_seq, max_results, lease_seconds, lease_generation. There are no aliases.


Running it

CPG-Radio runs on port 8773 with its own DB and project id, deliberately distinct from the live CPG server on 8766:

scripts/run-cpg-radio-http

That script pins CPG_PORT=8773, CPG_PROJECT_ID=cpg-radio, and CPG_DB_PATH=~/.cpg-radio/radio.db. Health check:

curl -s http://127.0.0.1:8773/          # {"service": "cpg-radio", ...}

MCP requests go to http://127.0.0.1:8773/mcp.

A development checkout refuses to start on the reserved legacy endpoint. Port 8766, or a db_path under ~/.cpg/ or ~/.local/state/codex-mcp/, is rejected at startup with LiveDeploymentError — the guard exists so a working copy can never attach to an already-installed server's database. An installed deployment that genuinely owns that endpoint may set CPG_ALLOW_LEGACY_ENDPOINT=1; the spawn gate then requires the complete canonical identity (loopback bind, the canonical project id, SQLite, and the canonical DB path) and refuses mixtures of development and canonical settings. Installed launchers should also set CPG_SPAWN_TOKEN_PATH, CPG_WORKER_LOG_DIR, and CPG_SUBAGENT_MCP_CONFIG to their own state paths.

Configuration

Variable

Meaning

Default

CPG_DB_BACKEND

sqlite or postgres

inferred

CPG_DATABASE_URL

PostgreSQL connection string

—

CPG_DB_PATH

SQLite path

~/.cpg-radio/radio.db

CPG_PROJECT_ID

project / session namespace

cpg-radio

CPG_TRANSPORT

stdio or streamable_http

stdio

CPG_BIND_HOST / CPG_PORT

HTTP bind

127.0.0.1 / 8773

CPG_STREAMABLE_HTTP_PATH

HTTP MCP path

/mcp

CPG_REAPER_INTERVAL_S

reaper tick; 0 disables it

60

CPG_WORKER_STALE_S

heartbeat age that fails a WORKER

3600

Schema version is 3. create_schema upgrades a v2 DB in place (the new tables are IF NOT EXISTS and the new payload fields are all optional, so there is no data migration) and refuses to start against a DB recording a newer version than the binary.


Development

.venv/bin/python -m pytest -q

# Optional: only against an isolated disposable PostgreSQL database
CPG_TEST_POSTGRES_URL=postgresql://... \
  .venv/bin/python -m pytest tests/integration/test_coordination_postgres.py -q

End-to-end smoke test — in-process, no network, no server, throwaway DB:

.venv/bin/python scripts/smoke-radio.py

It walks the full protocol (two agents join one session, one claims a task and posts a finding mentioning the other, the other polls and acks, the lease expires, the reaper hands the task back) and prints PASS/FAIL per step, exiting nonzero on the first failure.


Notes

  • Single process owns the DB. The reaper assumes it. Multi-process deployment still needs leader election, TLS/service identity, and Postgres notification ownership. Coordination objects are backend-neutral; this does not pretend a multi-host control plane is safe yet.

  • wait_for_mention is poll-backed at 500 ms on both backends. There is no LISTEN/NOTIFY: get_db() opens and closes a connection per call, so a LISTEN would never become active before the wait begins. Cursor polling is the primary path regardless; wait_for_mention is latency sugar.

  • Message bodies are capped at 16 KiB and rejected, never truncated. Larger findings go through record_structured_result with the message carrying a refs pointer.

  • kind="status" and kind="system" messages skip embedding, so a chatty bus does not run the model on every ping. finding, question, answer, claim, and handoff are embedded — those are the ones worth recalling later.

  • kind="system" is server-only and rejected from send_message.

  • Embedding search degrades gracefully when the model or vector backend is unavailable; SQLite uses sqlite-vec, PostgreSQL uses pgvector.

Available Tools

59 tools
ack_deliveryC

Record an idempotent required-delivery acknowledgement.

Inputs: message_id (required), binding_token.

ack_messagesA

Advance the calling agent's cursor to ack_seq. Forward-only: a lower value is ignored, so a replayed ack cannot re-deliver processed messages.

Inputs: ack_seq (required), binding_token.

ack_threadB

Advance a per-thread subscription cursor without hiding other threads.

Inputs: ack_seq (required), thread_id (required), binding_token.

arrive_barrierB

Atomically arrive at a barrier using its observed version.

Inputs: barrier_id (required), expected_version (required), binding_token.

cancel_workerB

Cancel a spawned worker. Idempotent. Authorised for the root spawn_token, or a child_token belonging to one of the target's ancestors.

Inputs: worker_id (required), reason, child_token, spawn_token, +1 more.

claim_resourceC

Claim a shared or exclusive named resource lease.

Inputs: campaign_id (required), resource_key (required), mode, binding_token, +2 more.

claim_taskA

Atomically take the lease on a TASK. Succeeds only if the task is unowned, its lease expired, or the caller already owns it. Pass the lease_generation you observed; a stale one loses the race.

Inputs: task_id (required), binding_token, lease_seconds, lease_generation.

close_threadA

Close a thread under opener or campaign-coordinator authority.

Inputs: thread_id (required), binding_token.

close_watchB

Close the caller's own watch registration (idempotent).

Inputs: watch_id (required), binding_token.

commit_resultA

Commit a SHA-256 digest before independent workers reveal results.

Inputs: commitment (required), campaign_id (required), workflow_id (required), binding_token, +1 more.

complete_assignmentA

Atomically record a result, release the task, close the worker, and post a handoff.

Inputs: summary (required), task_id (required), thread_id (required), idempotency_key (required), +6 more.

complete_workerA

Close the calling agent's own WORKER node with a terminal status. Call this when your delegated work is finished — otherwise the reaper stamps the worker 'failed' once it has been silent for the stale window. Identity-bound: you may only complete a worker you own. Never overwrites an existing terminal status, and refuses a live spawn-managed worker.

Inputs: note, status, worker_id, binding_token.

cpg_queryA

Hybrid FTS + embedding retrieval over the CPG graph. Use for structured lookups (node_type/domain filters) or open-ended recall (natural language questions). A complete 32-hex node id is resolved directly. Returns ranked node dicts.

Inputs: question (required), domain, node_types, max_results, +3 more.

cpg_thinkA

Ephemeral reasoning scratchpad. Optionally promote to an OBSERVATION node when the thought captures directly perceived data (tool output, file read, etc). Use promote_to='observation' with obs_type to persist. Predictions and hypotheses go through record_belief, not here.

Inputs: thought (required), obs_type, promote_to, source_tool.

create_barrierC

Create a quorum barrier for an explicit campaign phase.

Inputs: name (required), campaign_id (required), phase, quorum, +3 more.

create_campaignC

Create a durable coordination campaign and owner membership capability.

Inputs: name (required), description, binding_token, default_sharing_policy.

create_threadB

Open a THREAD node: a named channel other agents in this session can post to. Use one thread per topic or handoff, not one per message.

Inputs: topic (required), purpose, task_ids, visibility, +6 more.

drop_tipA

Drop a short practical TIP for other agents. TIPs are project-scoped, deduplicated by normalized text, and remain separate from FACT/BELIEF governance.

Inputs: text (required), kind, tags, binding_token, +2 more. Returns: tip_id, deduped

get_nodesA

Fetch whole nodes by id — the by-id counterpart to cpg_query's ranked search. Returns each node's full payload (e.g. a STRUCTURED_RESULT's complete data), not a truncated match. Use when you hold specific ids — such as the result ids a crew posted to a thread — and need the recorded detail, not a summary. Scoped to your session by default; session_scope='project' reads across the project.

Inputs: node_ids (required), binding_token, session_scope.

import_fable_traceA

Read-only importer for Claude/Fable JSONL traces or workflow result JSON. Use when analyzing prior Fable sessions or preserving an external multi-agent workflow in CPG. It creates a WORKFLOW, WORKER nodes, trace events, and when present aggregate coverage/surviving/refuted STRUCTURED_RESULT nodes. It never executes commands from the trace. By default it filters JSONL imports to claude-fable rows when present and skips Opus/Sonnet rows.

Inputs: trace_path (required), max_events, workflow_name, include_non_fable.

invite_memberC

Issue a revocable, role-scoped campaign membership capability.

Inputs: agent_id (required), campaign_id (required), role, expires_at, +2 more.

join_campaignC

Authenticate this connection into a campaign using its membership token.

Inputs: campaign_id (required), membership_token (required), binding_token.

join_sessionA

Bind this connection to an existing active session and declare the calling agent's id. Does not archive anything. Required before any other radio tool when the agent did not itself call plan_session.

Inputs: agent_id (required), session_id (required), child_token. Returns: tips, bound, agent_id, worker_id, +5 more

list_spawnedA

Read-only table of spawned workers in this session: provider, spawn_state, depth, parentage, and uptime. No token required.

Inputs: workflow_id, spawn_states, binding_token.

moderate_tipC

Approve or reject a quarantined campaign tip with evidence.

Inputs: tip_id (required), review_state (required), binding_token, evidence_refs.

plan_sessionB

Initialise a planning session. Creates a GOAL node, registers the full task graph, resolves dependency indices, creates IMPACT predictions, and converts constraints to confirmed FACT nodes. Call once per session before executing tasks.

Inputs: goal (required), tasks (required), risks, budget, +8 more. Returns: tips, task_ids, session_id, binding_token, +3 more

poll_messagesA

Read messages in this session newer than a sequence number. Read-only: it does not advance the caller's cursor — call ack_messages for that.

Inputs: after_seq, thread_id, max_results, binding_token, +1 more. Returns: has_more, messages, next_cursor

poll_threadC

Poll a thread from its independent subscription cursor.

Inputs: thread_id (required), max_results, binding_token.

post_progressB

Atomically renew a task lease, heartbeat the worker, and post progress.

Inputs: body (required), task_id (required), thread_id (required), idempotency_key (required), +3 more.

protocol_healthC

Report coordination health without returning restricted message bodies.

Inputs: campaign_id, binding_token.

publish_signalC

Create or compare-and-swap a typed, versioned coordination signal.

Inputs: name (required), campaign_id (required), value, audience, +5 more.

record_beliefA

Record an uncertain BELIEF (inference, hypothesis, assumption). Must cite supporting FACT or OBSERVATION ids. When belief_kind='assumption', also creates a linked ASSUMPTION control-plane node.

Inputs: content (required), confidence (required), domain, risk_id, +4 more.

record_executionB

Episodic log of a significant tool call. Creates an EXECUTION node + auto-observation, processes actual_impacts (lazy ARTIFACT creation + staleness), and stores objective_signals for reflect().

Inputs: success (required), task_id (required), tool_name (required), input_summary (required), +9 more.

record_factA

Record a grounded FACT. Must cite source_observation_id (from a prior cpg_think promote) or a raw source string. Facts start as 'provisional' and are upgraded by evidence. Use supersedes_id to chain replacements.

Inputs: domain (required), content (required), source, symbol_id, +4 more.

record_structured_resultB

Store schema-bound worker output in a WORKFLOW. Use for findings, verifier verdicts, coverage notes, and final reports. For a verifier verdict, set result_kind='verdict', status to confirmed/plausible/refuted, and verifies_result_id to the finding/result being checked. The response returns an aggregate count by result kind and status.

Inputs: data (required), result_kind (required), workflow_id (required), title, +10 more.

reflectC

Core pedagogical loop. Provide deviation_type and optionally objective_signals; server computes ReflectiveSignals and a dual-signal SCORE. Closes the loop on patterns, beliefs, and v1.4 control-plane nodes.

Inputs: task_id (required), actual_outcome (required), deviation_type (required), expected_outcome (required), +10 more.

register_watchC

Record which job (worker id, label, or done-file) this agent is waiting on.

Inputs: note, done_file, job_label, binding_token, +1 more.

register_workerB

Register one delegated worker/agent inside a WORKFLOW. Use one worker per finder/verifier/synthesizer/executor. Include the model, agent_id, prompt, dimension, and role whenever known so later agents can audit who did what.

Inputs: label (required), workflow_id (required), role, model, +7 more.

release_resourceB

Release the caller from a generation-checked resource lease.

Inputs: lease_id (required), generation (required), binding_token.

release_taskA

Give up the caller's lease on a TASK. lease_generation is required so a reaped-and-reassigned task cannot be released out from under its new owner.

Inputs: task_id (required), lease_generation (required), note, status, +1 more.

renew_leaseB

Extend the caller's lease on a TASK it already owns. Fails if the lease was reaped or reassigned.

Inputs: task_id (required), lease_generation (required), binding_token, lease_seconds.

renew_resourceC

Renew a resource lease held by the caller.

Inputs: lease_id (required), generation (required), binding_token, lease_seconds.

replanB

Formal replanning event. Cancels specified tasks (preserved in history), optionally adds new tasks at an incremented plan_version. Does not delete any nodes or edges.

Inputs: reason (required), new_tasks, drop_task_ids.

resolve_contradictionB

Resolve a queued FACT conflict from the contradictions table. Applies one of: a_supersedes_b, b_supersedes_a, both_provisional, dismissed.

Inputs: resolution (required), contradiction_id (required), notes.

resolve_messageB

Mark a question or request resolved by a message in the same thread.

Inputs: message_id (required), resolution_message_id (required), binding_token.

reveal_resultC

Reveal data matching a prior commitment and record the result.

Inputs: data (required), nonce (required), commitment_id (required), title, +1 more.

revoke_memberC

Revoke a campaign membership capability.

Inputs: membership_id (required), binding_token.

send_messageA

Post a MESSAGE to a THREAD as the calling agent. Body is capped at 16 KiB; larger findings go through record_structured_result with the message carrying a refs pointer. kind='system' is server-only.

Inputs: body (required), thread_id (required), kind, refs, +12 more.

spawn_workersA

Fan out to configured local providers. Creates WORKER nodes in spawn_state='requested' and returns immediately — a background supervisor performs the calls and records each answer as a STRUCTURED_RESULT. Requires exactly one of spawn_token or child_token. Caps and unknown providers come back in 'refused', never as an error.

Inputs: workers (required), workflow_id (required), wait, child_token, +2 more.

stale_reportA

List stale running workers, leases whose claimant is gone, a gpu.lock that disagrees with the lease, and watchers of finished jobs. Read-only.

Inputs: scope, gpu_lock_dir, gpu_task_ids, binding_token, +1 more.

start_workflowA

Create a first-class fan-out/fan-in WORKFLOW run. Use this when a task will delegate to multiple agents, run phases such as find→verify→synthesize, or needs schema-bound aggregation. After calling it, register each worker with register_worker and store each worker output or verifier verdict with record_structured_result. Do not use for ordinary single-thread task lists; use plan_session/update_task for those.

Inputs: name (required), phases, metadata, task_ids, +2 more.

subscribe_threadB

Create a durable per-thread subscription cursor.

Inputs: thread_id (required), binding_token.

tipsB

Read ranked practical TIPs. With query, reuses hybrid FTS+embedding retrieval and boosts useful tips; otherwise ranks by votes then recency.

Inputs: kind, tags, query, scope, +3 more. Returns: tips

tip_usefulA

Mark a TIP useful as the calling agent. One vote per agent per TIP; repeated calls are idempotent.

Inputs: tip_id (required), binding_token. Returns: useful_count, already_voted

update_taskA

Update a TASK node lifecycle status. Valid transitions: planned→in_progress, in_progress→done/failed/blocked/cancelled/done_pending_verification/verified.

Inputs: status (required), task_id (required), notes.

update_workflowA

Update a WORKFLOW status and optional summary. Use when all workers finish, a workflow blocks, or final aggregation is complete. Terminal states are completed, failed, and cancelled.

Inputs: status (required), workflow_id (required), summary, binding_token.

wait_for_mentionA

Block until a message mentioning the calling agent (or broadcasting to '*') arrives, or the timeout elapses. Returns immediately if one is already pending.

Inputs: after_seq, thread_id, timeout_s, max_results, +2 more. Returns: has_more, messages, timed_out, next_cursor

wait_for_signalC

Read a signal only when its version advanced; expired signals are absent.

Inputs: name (required), campaign_id (required), after_version, binding_token.

worker_heartbeatA

Stamp heartbeat_at on the calling agent's WORKER node so the reaper does not treat it as stale.

Inputs: worker_id, binding_token.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    C2.7/5.0

    Scored across 59 tools

    Disambiguation2/5

    Several tool families—poll_messages/poll_thread, ack_messages/ack_thread/ack_delivery, record_structured_result/reveal_result/complete_assignment, renew_lease/renew_resource, complete_worker/complete_assignment—have nuanced but near-overlapping purposes, so an agent can easily select the wrong one. The descriptions are detailed, but at 59 tools the set lacks clear semantic separation.

    Naming Consistency2/5

    Most tools use snake_case verb_noun, but there are many inconsistent outliers: cpg_think, cpg_query, replan, reflect, tips, protocol_health, stale_report, post_progress, complete_assignment. Verbs are not normalized across categories (create/start/spawn, poll/subscribe, ack/acknowledge, close/complete/cancel), so the pattern is only loosely predictable.

    Tool Count1/5

    59 tools is an extreme size for an MCP server; even though the platform covers many subdomains, it is far beyond a well-scoped tool set and will overwhelm agents with selection overhead. It would benefit from consolidated compound tools or splitting into focused servers.

    Completeness4/5

    The server covers the core lifecycle well: planning, task leasing, workflow fan-out/fan-in, worker heartbeats/completion, threaded messaging with cursors/acks, campaign and barrier coordination, facts/beliefs/tips, and result commitments. Minor gaps like explicit campaign dissolution or direct fact/belief deletion are workaroundable through supersede/cancel/query tools.

    Maintenance

    ActivityStale
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      B
      maintenance
      Local OS for your AI Agents fleets. ——————- Enables AI agents to coordinate through a durable local board with shared state, ticket lifecycle, evidence-based approvals, and journal-woken handoffs.
      2
      Apache 2.0
    • A
      license
      Not graded
      quality
      B
      maintenance
      Provides AI agents with shared communication and persistent state over HTTP and MCP, letting an agent save its progress, search and reuse other agents' prior work, coordinate tasks in shared spaces, exchange direct messages, and hand its role to a successor when a session ends. State is kept on PostgreSQL with signed, append-only records that anyone can verify.
      Business Source 1.1