colony exposes MCP tools over a stdio server. IDE installers register that server as colony, so agent tool calls appear under the colony namespace. The design goal is progressive disclosure: hits are compact until the agent asks for more.
For memory lookup, the recommended workflow is search first, hydrate later:
- Before implementation, call
searchwith query-rich terms from the task: feature name, package name, file path, task slug, or exact error message. - Review the compact IDs and snippets. Do not fetch full bodies for every hit.
- Call
get_observationsonly with the filtered IDs you actually need.
Use list_sessions -> timeline when you need to navigate a known session instead of searching memory globally.
Agent startup, resume, "what needs me?", and "what should I do next?" flows should call these first:
hivemind_contextto see active agents, owned branches, live lanes, compact memory hits, and relevant negative warnings.attention_inboxto see what needs your attention: handoffs, messages, wakes, stalled lanes, fresh claims, stale-claim cleanup signals, and decaying hot files.task_ready_for_agentto choose available work matched to the current agent.
Do not choose work before attention_inbox.
Codex-style MCP tool names include the server prefix:
mcp__colony__hivemind_context,
mcp__colony__attention_inbox, and
mcp__colony__task_ready_for_agent.
Use task_list for browsing/debugging recent task threads. Use task_ready_for_agent for choosing what to work on next.
Every live Colony MCP call has a matching top-level section in this file. Keep this index short; the sections below carry examples, return shape notes, and workflow guidance.
| Area | Tool | Use |
|---|---|---|
| Memory | search |
Find compact observation hits before hydrating bodies. |
| Memory | get_observations |
Fetch selected full observation bodies by ID. |
| Memory | timeline |
Navigate one session by compact observation IDs. |
| Memory | list_sessions |
Find recent sessions for recall or timeline lookup. |
| Memory | recall_session |
Audit a compact recall of another session into the current one. |
| Runtime | hivemind |
See compact live agent/session lanes. |
| Runtime | hivemind_context |
Combine live lanes, ownership, memory hits, and warnings before work. |
| Runtime | attention_inbox |
See pending handoffs, unread messages, blockers, stale lanes, and claim signals. |
| Runtime | startup_panel |
Build one compact startup card with active task, inbox, ready work, and next call. |
| Runtime | bridge_status |
Feed OMX HUD/status with compact Colony state. |
| Tasks | task_list |
Browse task threads; not the work picker. |
| Tasks | task_timeline |
Read compact activity IDs for a task. |
| Tasks | task_updates_since |
Check task changes since a timestamp, excluding your own posts. |
| Tasks | task_post |
Add shared questions, answers, decisions, blockers, notes, and warnings. |
| Tasks | task_note_working |
Save current working state when task resolution should be inferred. |
| Tasks | task_claim_file |
Claim one file before editing so overlap is visible. |
| Tasks | task_drift_check |
Compare recent edits against active claims for one task/session. |
| Tasks | task_link |
Link related task threads. |
| Tasks | task_links |
List related task-thread links. |
| Tasks | task_unlink |
Remove a task-thread link. |
| Handoff | task_hand_off |
Transfer work and optional file claims to another agent. |
| Handoff | task_accept_handoff |
Accept a pending handoff. |
| Handoff | task_decline_handoff |
Decline a pending handoff. |
| Handoff | task_relay |
Emit quota/rate-limit/turn-cap resume baton when the sender may be gone. |
| Handoff | task_accept_relay |
Accept a relay and inherit its resume recipe/claims. |
| Handoff | task_decline_relay |
Decline a relay so it can be rerouted. |
| Quota claims | task_claim_quota_accept |
Adopt quota-pending claim ownership from a handoff or relay. |
| Quota claims | task_claim_quota_decline |
Decline a quota-pending claim without cancelling the baton. |
| Quota claims | task_claim_quota_release_expired |
Weaken expired quota-pending claims and expire old batons. |
| Messages | task_message |
Send directed or broadcast agent-to-agent messages. |
| Messages | task_messages |
Read compact unread/direct message entries. |
| Messages | task_message_mark_read |
Mark one message read and write a receipt. |
| Messages | task_message_claim |
Claim a broadcast before replying. |
| Messages | task_message_retract |
Retract your unreplied sent message. |
| Proposals | task_propose |
Create weak future-work candidate for reinforcement. |
| Proposals | task_reinforce |
Reinforce or promote a proposal. |
| Proposals | task_foraging_report |
Browse pending/promoted proposals for a branch. |
| Profiles | agent_upsert_profile |
Set capability weights for an agent type. |
| Profiles | agent_get_profile |
Read capability weights for an agent type. |
| Planning | queen_plan_goal |
Decompose a high-level goal into a published claimable plan. |
| Planning | task_plan_validate |
Preflight a multi-agent plan for overlaps, claims, and wave errors. |
| Planning | task_plan_publish |
Publish a spec-backed plan with claimable sub-tasks. |
| Planning | task_plan_list |
List plans and next available sub-tasks. |
| Planning | task_ready_for_agent |
Pick or auto-claim the next available sub-task. |
| Planning | task_plan_claim_subtask |
Claim one plan sub-task. |
| Planning | task_plan_complete_subtask |
Complete one plan sub-task and release its claims. |
| Planning | task_plan_status_for_spec_row |
Check whether a spec row is already covered by a plan sub-task. |
| Planning | task_autopilot_tick |
Get one stateless next-action decision from inbox plus ready work. |
| OpenSpec | spec_read |
Read parsed SPEC.md plus root hash. |
| OpenSpec | openspec_sync_status |
Report drift between Colony task state and OpenSpec artifacts. |
| OpenSpec | spec_change_open |
Open a spec change and task thread. |
| OpenSpec | spec_change_add_delta |
Append one add/modify/remove delta to an open change. |
| OpenSpec | spec_build_context |
Fetch task-scoped spec context. |
| OpenSpec | spec_build_record_failure |
Record a build/test failure and maybe promote an invariant proposal. |
| OpenSpec | spec_archive |
Validate, merge, and archive a spec change. |
| Examples | examples_list |
List indexed food-source examples. |
| Examples | examples_query |
Search indexed example patterns. |
| Examples | examples_integrate_plan |
Build deterministic integration guidance for an example. |
| Suggestions | task_suggest_approach |
Get similarity-backed guidance from past tasks. |
| Rescue | rescue_stranded_scan |
Dry-run stranded lane/claim rescue candidates. |
| Rescue | rescue_stranded_run |
Emit rescue relays and release abandoned claims. |
| Metrics | savings_report |
Report live MCP token receipts and reference savings model. |
Ruflo integration should stay at the sidecar boundary. Do not vendor Ruflo, copy its swarm runtime, or import its browser/security tool trees into Colony. If Ruflo runs beside Colony, expose it through a separate MCP/runtime and let Colony observe compact events through a bridge.
The intended flow is
Ruflo tools/events -> Colony bridge -> compact observations -> suggestions/health/debrief.
Map those events into Colony records such as observations, task threads,
handoffs, claims, active-session state, learned patterns, and token receipts. See
Ruflo sidecar architecture.
Copy-paste startup:
{ "name": "hivemind_context", "input": { "repo_root": "/abs/repo", "query": "current task or branch", "memory_limit": 3, "limit": 20 } }{ "name": "attention_inbox", "input": { "session_id": "sess_abc", "agent": "codex", "repo_root": "/abs/repo" } }{ "name": "task_ready_for_agent", "input": { "session_id": "sess_abc", "agent": "codex", "repo_root": "/abs/repo", "limit": 5 } }When the selected task needs implementation context, call search with the task title, files, or error phrase, then hydrate only the needed IDs with get_observations. Claim files with task_claim_file or task_plan_claim_subtask before editing.
For multi-agent runtime awareness, call hivemind_context first when you need ownership plus likely memory hits, or hivemind when you only need the runtime map. Both return compact active worktrees, branches, agents, and task previews from .omx proxy-runtime state without fetching observation bodies.
After every hivemind_context, call attention_inbox before choosing work. hivemind_context.summary.next_action is intentionally explicit: Do not choose work yet. Call attention_inbox, then task_ready_for_agent. attention_inbox checks what needs you now: live pending handoffs, unread messages, blockers, stalled lanes, fresh claims, stale-claim cleanup signals, and decaying hot files. Review its compact IDs first; fetch full bodies with get_observations only after you pick the IDs worth reading.
Do not choose work before attention_inbox.
For choosing work to claim, the compact path is:
hivemind_context -> attention_inbox -> task_ready_for_agent -> task_plan_claim_subtask
Following the progressive-disclosure pattern saves ~10× tokens versus fetching full bodies upfront.
Invariant: compact MCP tools do not return full observation bodies by default. Default responses may include counts, IDs, snippets, previews, branch/task/file metadata, action hints, and suggested MCP calls. Full observation content and metadata belong behind get_observations(ids[]), after the caller has selected the compact IDs worth hydrating.
The expected compact startup and work-selection flow is:
hivemind_context -> attention_inbox -> task_ready_for_agent -> get_observations only after compact IDs are selected
Use hivemind_context for ownership, compact memory hits, negative warnings, and the attention summary. Use attention_inbox for compact attention buckets and message/action hints. Use task_ready_for_agent for the claimable-work picker and exact claim calls. Use get_observations only after a compact tool returned IDs that the caller deliberately selected.
Current payloads already expose this contract through fields such as summary, observation_ids, observation_ids_truncated, hydrate_with, next_action, compact message preview, and tool-specific action hints. A uniform budget object is planned/optional and is not required in current MCP payloads yet. When implemented, budget should be advisory and compact:
items_available: total items matching the request before compaction.items_returned: items included in the current response.collapsed_count: items intentionally omitted from the compact response.estimated_tokens_returned: rough token estimate for the compact payload.hydrate_with: next tool to use for expansion, usuallyget_observations; it may name another compact tool such asattention_inboxwhen that is the next disclosure step.why_collapsed: short reason the response stayed compact.
Example noisy inbox payload. The budget object is planned/optional; the compact IDs, previews, and action hints match the current behavior:
{
"summary": {
"unread_message_count": 12,
"pending_handoff_count": 1,
"stalled_lane_count": 2,
"blocked": true,
"next_action": "Reply to blocking messages before choosing work."
},
"unread_messages": [
{
"id": 401,
"task_id": 17,
"urgency": "blocking",
"preview": "Need PR merge evidence before cleanup.",
"reply_tool": "task_message",
"suggested_reply_args": {
"task_id": 17,
"reply_to": 401,
"urgency": "fyi",
"content": "..."
},
"mark_read_tool": "task_message_mark_read"
}
],
"pending_handoffs": [
{
"id": 402,
"task_id": 17,
"summary": "Take over cleanup evidence",
"next": "Accept or decline the handoff."
}
],
"budget": {
"items_available": 26,
"items_returned": 5,
"collapsed_count": 21,
"estimated_tokens_returned": 950,
"hydrate_with": "get_observations",
"why_collapsed": "Noisy inbox: returned top blocking/needs_reply items, compact counts, and action hints only."
}
}Example stalled-lane payload. Stalled lanes stay compact: owner, branch, task, activity, and worktree path are enough to decide whether to rescue, inspect, or ignore. If there is no observation ID, expand with the lane's task timeline or a targeted search rather than fetching unrelated bodies:
{
"summary": {
"stalled_lane_count": 1,
"next_action": "Review stalled lanes before treating the repo as idle."
},
"stalled_lanes": [
{
"repo_root": "/abs/repo",
"branch": "agent/codex/docs-budget-contract",
"task": "Tool: colony.examples_query",
"owner": "agent/unknown",
"activity": "dead",
"activity_summary": "Heartbeat stale for 7m 28s.",
"worktree_path": "/abs/repo/.omx/agent-worktrees/repo__codex__docs-budget-contract",
"next_action": "Inspect lane evidence, then take over or ignore if already cleaned up.",
"suggested_actions": [
{
"action": "inspect",
"reason": "Read branch/worktree/task evidence before taking ownership.",
"command": "git -C /abs/repo/.omx/agent-worktrees/repo__codex__docs-budget-contract status --short --branch"
},
{
"action": "takeover",
"reason": "Owner appears stalled or dead; explicit takeover is safer than waiting.",
"command": "colony lane takeover agent/unknown --reason 'stalled lane takeover'"
},
{
"action": "ignore",
"reason": "Use only after branch/PR/task evidence shows the lane is already closed."
}
]
}
],
"budget": {
"items_available": 9,
"items_returned": 1,
"collapsed_count": 8,
"estimated_tokens_returned": 420,
"hydrate_with": "attention_inbox",
"why_collapsed": "Only the top stalled lane is needed for the immediate startup decision."
}
}Example suggestion payload. task_suggest_approach and the SessionStart suggestion preface return derived guidance and task IDs, not full historical observation bodies:
{
"similar_tasks": [
{
"task_id": 31,
"similarity": 0.91,
"branch": "agent/codex/attention-budget",
"repo_root": "/abs/repo",
"status": "completed",
"observation_count": 42
}
],
"first_files_likely_claimed": [
{
"file_path": "apps/mcp-server/src/tools/attention.ts",
"appears_in_count": 4,
"confidence": 0.64
}
],
"patterns_to_watch": [
{
"description": "Expired handoff caused stale ownership",
"seen_in_task_id": 31,
"kind": "expired-handoff"
}
],
"resolution_hints": {
"median_elapsed_minutes": 38,
"median_handoff_count": 1,
"median_subtask_count": 2,
"completed_sample_size": 5
},
"insufficient_data_reason": null,
"budget": {
"items_available": 12,
"items_returned": 3,
"collapsed_count": 9,
"estimated_tokens_returned": 700,
"hydrate_with": "task_suggest_approach",
"why_collapsed": "Startup suggestion shows only top files and first pattern; run task_suggest_approach for the full derived guidance."
}
}The OMX-Colony bridge contract lives in openspec/specs/omx-colony-bridge/spec.md:
OMX runs agents, Colony coordinates agents, OMX displays Colony state, and
Colony consumes OMX telemetry. Use Colony first for coordination; use OMX state
or notepad only when Colony is unavailable or missing the required surface.
For current working state, call task_note_working before any OMX notepad
write. A successful Colony working note must not duplicate the full content into
.omx/notepad.md; only bridge.writeOmxNotepadPointer=true may append the tiny
pointer fields branch, task, blocker, next, evidence, and
colony_observation_id. If no active task matches, callers may opt into
allow_omx_notepad_fallback=true to write that same tiny pointer.
Working handoff notes use one compact field order:
branch=<branch> | task=<task> | blocker=<blocker> | next=<next> | evidence=<path|command|PR|spec>
Use task_note_working or the CLI helper when posting progress:
colony note working --session-id sess_abc --repo-root /abs/repo --next "run focused tests" --evidence "apps/mcp-server/test/task-threads.test.ts"branch and task are inferred from the active session/task binding when the
binding is unambiguous. next and evidence are required. Evidence must be a
compact pointer, not pasted logs; long proof text is compacted and returned with
a warning. Each successful auto note marks the prior live auto handoff note as
superseded so resume flows read one current state.
Find observations matching a natural-language query.
{
"name": "search",
"input": { "query": "auth middleware", "limit": 10 }
}Good planning queries include:
- Feature name:
queen plan publication - Package name:
@colony/mcp-server - File path:
apps/mcp-server/src/tools/search.ts - Task slug:
agent-agent5-mcp-search-first-docs - Error message:
cannot open '.git/FETCH_HEAD': Read-only file system
Then hydrate only selected hits:
{
"name": "search",
"input": {
"query": "@colony/mcp-server apps/mcp-server/src/tools/search.ts search description",
"limit": 5
}
}{
"name": "get_observations",
"input": { "ids": [6337, 8946], "expand": true }
}Returns: [ { id, session_id, snippet, score, ts } ] - compact hits only, never full observation bodies. Use get_observations for the few IDs worth reading.
Search hits include kind and task_id so agents can recognize advisory negative warnings such as failed_approach before hydrating the full body.
Scoring is hybrid: keyword (FTS5 BM25) blended with vector similarity via settings.search.alpha. Missing fields fall back gracefully.
Chronological observation identifiers for a given session.
{
"name": "timeline",
"input": { "session_id": "sess_abc", "around_id": 42, "limit": 50 }
}Returns: [ { id, kind, ts } ] — no body content. Use the IDs in get_observations.
Fetch full observation bodies by ID.
{
"name": "get_observations",
"input": { "ids": [12, 34], "expand": true }
}Returns: [ { id, session_id, kind, ts, content, metadata } ].
Content is expanded to human-readable form by default. Pass expand: false to request the compressed form (useful for audit or for agents that understand the caveman dialect directly).
List recent sessions in reverse chronological order.
{
"name": "list_sessions",
"input": { "limit": 20 }
}Returns: [ { id, ide, cwd, started_at, ended_at } ]. Use id with timeline to navigate within a session.
Summarize what active agent sessions are doing now.
{
"name": "hivemind",
"input": {
"repo_root": "/home/deadpool/Documents/recodee",
"include_stale": false,
"limit": 50
}
}Returns:
{
"generated_at": "2026-04-23T08:01:00.000Z",
"repo_roots": ["/home/deadpool/Documents/recodee"],
"session_count": 1,
"counts": { "working": 1, "thinking": 0, "idle": 0, "stalled": 0, "dead": 0, "unknown": 0 },
"sessions": [
{
"branch": "agent/codex/live-task",
"task": "Expose runtime tasks to Codex",
"agent": "codex",
"activity": "working",
"worktree_path": "/home/deadpool/Documents/recodee/.omx/agent-worktrees/live-task",
"source": "active-session"
}
]
}Inputs:
repo_root: one workspace root to inspect. Defaults to the MCP server process cwd.repo_roots: multiple workspace roots to inspect. Also configurable withCOLONY_HIVEMIND_REPO_ROOTSseparated by the platform path delimiter.include_stale: include dead active-session records. Defaults tofalse.limit: maximum sessions returned, capped at 100.
Sources:
.omx/state/active-sessions/*.jsonfrom the proxy runtime / Guardex active-agent producer..omx/agent-worktrees/*/AGENT.lockand.omc/agent-worktrees/*/AGENT.lockas a telemetry fallback for task previews.
Use this from a Codex skill as the first context step when the skill needs to know which session owns which task before reading memory timelines.
Build a compact startup/resume card for UIs, HUDs, or agents that need one
payload instead of manually composing hivemind_context, attention_inbox,
and task_ready_for_agent.
{
"name": "startup_panel",
"input": {
"session_id": "sess_abc",
"agent": "codex",
"repo_root": "/abs/repo",
"branch": "agent/codex/current-work",
"ready_limit": 3
}
}Returns { session_id, agent, repo_root, branch, active_task, ready_task, active_queen_plan, inbox_count, blocking_items, claimed_files, blocker, next, evidence, warnings, recommended_next_tool, recommended_next_args, copy_paste_next_mcp_calls }.
Use this for presentation and resume surfaces. Agents that need full
progressive-disclosure IDs should still call hivemind_context,
attention_inbox, and task_ready_for_agent directly.
Return live lane ownership plus compact relevant memory hits and negative warnings in one request. Before editing, inspect ownership, then claim touched files on the active task.
{
"name": "hivemind_context",
"input": {
"repo_root": "/home/deadpool/Documents/recodee",
"query": "session takeover stale source",
"memory_limit": 3,
"limit": 20
}
}Returns:
{
"generated_at": "2026-04-23T08:01:00.000Z",
"summary": {
"lane_count": 1,
"memory_hit_count": 3,
"negative_warning_count": 1,
"needs_attention_count": 0,
"next_action": "Do not choose work yet. Call attention_inbox, then task_ready_for_agent.",
"suggested_tools": ["attention_inbox", "task_ready_for_agent"],
"must_check_attention": true,
"attention_hint": "Call attention_inbox to review pending handoffs, unread messages, blockers, and stalled lanes before claiming work.",
"ready_work_hint": "Then call task_ready_for_agent to choose claimable work. Use task_list only for browsing/debugging.",
"unread_message_count": 0,
"pending_handoff_count": 0,
"blocking": false,
"ready_work_count": 0
},
"attention": {
"unread_messages": 0,
"pending_handoffs": 0,
"blocking": false,
"observation_ids": [],
"hydration": "Hydrate with attention_inbox; call get_observations with observation_ids only for bodies.",
"hydrate_with": "attention_inbox"
},
"lanes": [
{
"branch": "agent/codex/live-task",
"task": "Expose runtime tasks to Codex",
"owner": "codex/codex",
"activity": "working",
"needs_attention": false
}
],
"memory_hits": [
{
"id": 42,
"session_id": "sess_abc",
"kind": "decision",
"snippet": "compact hit",
"score": 1.2,
"ts": 1710000000000,
"task_id": 17
}
],
"negative_warnings": [
{
"id": 43,
"session_id": "sess_def",
"kind": "failed_approach",
"snippet": "do not repeat manual polling",
"ts": 1710000001000,
"task_id": 17
}
]
}Inputs:
repo_root,repo_roots,include_stale, andlimit: same ashivemind.query: optional memory query. If omitted, the server derives one from active task text.memory_limit: compact memory hits to return, capped at 10 and defaulting to 3.
Use this for takeover, review, or resume flows where the agent needs current ownership and a small memory index before deciding which full observations to fetch. The summary intentionally pushes the startup loop toward attention_inbox, then task_ready_for_agent; hivemind_context returns compact IDs and counts, not full observation bodies.
Return compact coordination state for OMX HUD/status displays without fetching full observation bodies. This composes the same hivemind, attention, and ready-work logic as the richer tools.
{
"name": "bridge_status",
"input": {
"session_id": "sess_abc",
"agent": "codex",
"repo_root": "/home/deadpool/Documents/recodee",
"branch": "agent/codex/live-task",
"query": "current task"
}
}Returns:
{
"schema": "colony.omx_hud_status.v1",
"generated_at": "2026-04-28T21:30:00.000Z",
"runtime_source": "omx",
"hivemind": {
"lane_count": 1,
"total_lane_count": 1,
"lanes_truncated": false,
"needs_attention_count": 0,
"counts": {
"working": 1,
"thinking": 0,
"idle": 0,
"stalled": 0,
"dead": 0,
"unknown": 0
},
"lane_preview": [
{
"branch": "agent/codex/live-task",
"task": "Ship bridge status",
"owner": "codex/codex",
"activity": "working",
"needs_attention": false,
"risk": "none",
"source": "active-session",
"locked_file_count": 1,
"locked_file_preview": ["apps/mcp-server/src/tools/bridge.ts"]
}
]
},
"branch": "agent/codex/live-task",
"task": "Ship bridge status",
"blocker": null,
"next_action": "Continue agent/codex/live-task.",
"next": "Continue agent/codex/live-task.",
"evidence": {
"task_id": 17,
"latest_working_note_id": 43,
"attention_observation_ids": [],
"attention_observation_ids_truncated": false,
"hydrate_with": "get_observations"
},
"attention": {
"unread_count": 0,
"blocking_count": 0,
"blocking": false,
"pending_handoff_count": 0,
"pending_wake_count": 0,
"stalled_lane_count": 0
},
"attention_counts": {
"lane_needs_attention_count": 0,
"pending_handoff_count": 0,
"pending_wake_count": 0,
"unread_message_count": 0,
"stalled_lane_count": 0,
"recent_other_claim_count": 0,
"blocked": false
},
"ready_work_count": 1,
"ready_work_preview": [
{
"title": "Implement bridge status tool",
"plan_slug": "bridge-ready-plan",
"subtask_index": 0,
"reason": "ready_high_score",
"fit_score": 0.8,
"capability_hint": "api_work",
"file_count": 2,
"file_scope_preview": ["apps/mcp-server/src/tools/bridge.ts"]
}
],
"claimed_file_count": 1,
"claimed_file_preview": [
{
"task_id": 17,
"file_path": "apps/mcp-server/src/tools/bridge.ts",
"by_session_id": "sess_abc",
"claimed_at": 1710000000000,
"yours": true
}
],
"claimed_files": [
{
"task_id": 17,
"file_path": "apps/mcp-server/src/tools/bridge.ts",
"by_session_id": "sess_abc",
"claimed_at": 1710000000000,
"yours": true
}
],
"latest_working_note": {
"id": 43,
"task_id": 17,
"session_id": "sess_abc",
"ts": 1710000001000,
"content": "branch=agent/codex/live-task; task=bridge status; blocker=none; next=run tests; evidence=bridge_status"
}
}Inputs:
session_id,agent, andrepo_root: required identity and workspace scope.branch: optional current branch hint used to pick the active lane.query: optional compact context query. No memory hits or full observation bodies are returned.
The payload is intentionally HUD-sized. hivemind.lane_preview,
ready_work_preview, and claimed_file_preview are capped previews. next is
a legacy alias for next_action. Hydrate evidence.attention_observation_ids
with get_observations only after the user expands the card or needs the full
body. Use hivemind_context, attention_inbox, or task_ready_for_agent
directly when the agent needs progressive-disclosure IDs or richer details.
Call hivemind_context before editing:
{
"name": "hivemind_context",
"input": {
"repo_root": "/home/deadpool/Documents/recodee",
"query": "files I expect to touch",
"memory_limit": 3,
"limit": 20
}
}Inspect active lanes for branches, owners, and file ownership:
{
"lanes": [
{
"branch": "agent/codex/live-task",
"owner": "codex/codex",
"locked_file_preview": ["apps/mcp-server/src/tools/task.ts"]
}
]
}Call task_claim_file once for each file you expect to edit:
{
"name": "task_claim_file",
"input": {
"task_id": 17,
"session_id": "sess_abc",
"file_path": "apps/mcp-server/src/tools/task.ts",
"note": "updating claim-before-edit wording"
}
}{
"name": "task_claim_file",
"input": {
"task_id": 17,
"session_id": "sess_abc",
"file_path": "docs/mcp.md",
"note": "documenting normal edit workflow"
}
}Then edit. Claims are warnings, not locks. They never block writes. They make overlap visible so agents can coordinate before a collision.
List indexed example projects (food sources) discovered under <repo_root>/examples/<name>/. Populated by the colony foraging scan command and by the SessionStart hook when settings.foraging.scanOnSessionStart is true.
{
"name": "examples_list",
"input": { "repo_root": "/abs/path/to/repo" }
}Returns: [ { example_name, manifest_kind, observation_count, last_scanned_at } ].
manifest_kind is one of npm, pypi, cargo, go, unknown, or null. observation_count is the cached number of foraged-pattern observations the indexer wrote for that example. Use this to choose a target for examples_query or examples_integrate_plan.
BM25-ranked search scoped to kind = 'foraged-pattern' observations, optionally narrowed to a single example.
{
"name": "examples_query",
"input": { "query": "webhook signature", "example_name": "stripe-webhook", "limit": 10 }
}Returns compact hits: [ { id, session_id, kind, snippet, score, ts, task_id } ]. Follow with get_observations(ids[]) for full bodies. Vector re-rank is intentionally skipped when a filter is present — the embedding index has no kind column.
Build a deterministic plan for integrating a food source into the target repo. No LLM in the loop — the plan is derived from the indexed manifest and entrypoints plus a fresh read of the target package.json.
{
"name": "examples_integrate_plan",
"input": {
"repo_root": "/abs/path/to/repo",
"example_name": "stripe-webhook",
"target_hint": "apps/api/package.json"
}
}Returns:
{
"example_name": "stripe-webhook",
"dependency_delta": { "add": { "stripe": "^14.0.0" }, "remove": ["lodash"] },
"files_to_copy": [
{ "from": "examples/stripe-webhook/src/index.ts", "to_suggestion": "src/index.ts", "rationale": "…" }
],
"config_steps": ["npm run build", "npm run test"],
"uncertainty_notes": ["…"]
}dependency_delta.add lists example deps missing from the target. dependency_delta.remove is informational — it is never a recommendation to delete. Only npm examples produce a real diff today; other manifest_kinds emit an uncertainty note and leave add empty. target_hint is optional: absolute paths are used as-is, relative paths are joined onto repo_root, and the default is <repo_root>/package.json.
Browse task threads; use task_ready_for_agent when choosing work to claim. Each task groups sessions collaborating on the same (repo_root, branch).
Use task_list when you need to inspect existing task threads by repo or branch for browsing/debugging. Do not use it as the main work picker; call task_ready_for_agent when the question is "what should I work on next?"
{ "name": "task_list", "input": { "limit": 50, "session_id": "sess_abc" } }Returns: { tasks, hint, coordination_warning, next_tool }. Before a session calls task_ready_for_agent, coordination_warning is task_list is inventory; use task_ready_for_agent to choose work. and next_tool is task_ready_for_agent. Repeated task_list calls without task_ready_for_agent return Stop browsing. Call task_ready_for_agent before selecting work. as the stronger warning. After task_ready_for_agent, coordination_warning is omitted and task_list stays a browsing/debugging surface. The legacy hint field remains for backward compatibility.
Compact observation index for a task thread.
{ "name": "task_timeline", "input": { "task_id": 17, "limit": 50 } }Returns: [ { id, kind, session_id, ts, reply_to } ]. Use the IDs with get_observations.
Task-thread observations after since_ts, with the caller's own posts filtered out — tailored for "what changed while I was away".
{
"name": "task_updates_since",
"input": { "task_id": 17, "session_id": "sess_abc", "since_ts": 1714000000000, "limit": 50 }
}Returns: [ { id, kind, session_id, ts } ].
Link two related task threads. Links are bidirectional and idempotent, so either side can discover the relationship without copying decisions between threads.
{
"name": "task_link",
"input": {
"task_id": 17,
"other_task_id": 42,
"session_id": "sess_abc",
"note": "frontend task depends on API contract"
}
}Returns { low_id, high_id, created_at, created_by, note }. Errors with
TASK_LINK_SELF when both IDs are the same.
List task links for one thread.
{ "name": "task_links", "input": { "task_id": 17 } }Returns each linked edge with the other task side, note, and link metadata.
Remove a task-thread link after the coordination relationship is no longer needed.
{
"name": "task_unlink",
"input": { "task_id": 17, "other_task_id": 42 }
}Returns { removed: true } when a link was deleted and { removed: false }
when there was no link to delete.
Post shared notes, decisions, blockers, questions, and answers on a task thread. Use task_message for directed agent-to-agent coordination. Use task_note_working as the first write path for current working state and when you do not know task_id. Use the dedicated tools (task_claim_file, task_hand_off, task_accept_handoff) for structured actions; task_post is for free-form shared thread state tagged with a kind.
Use kind: "note" when the caller already knows the task_id or needs a normal task-thread note. For current working state without a resolved task_id, call task_note_working first. The note lands on both the task thread and the posting session's memory through MemoryStore, so it stays compressed, timeline-visible, and searchable later.
Use failed_approach, blocked_path, conflict_warning, or reverted_solution when another agent should not repeat a concrete bad path. Keep these warnings explicit and evidence-based: failed paths, blocked approaches, reverted solutions, flaky routes, or do-not-touch notes. They show up compactly in search, hivemind_context, and task_ready_for_agent, but they do not lower ready-work ranking.
When a note or decision looks like future work, task_post returns a recommendation that points to task_propose. Use the proposal tool for weak candidates so foraging can reinforce, decay, and promote them instead of leaving them buried in a thread note.
{
"name": "task_post",
"input": {
"task_id": 17,
"session_id": "sess_abc",
"kind": "decision",
"content": "Using BM25 + cosine hybrid with alpha=0.5",
"reply_to": 123
}
}kind ∈ question | answer | decision | blocker | note | failed_approach | blocked_path | conflict_warning | reverted_solution. Returns { id, hint }, plus recommendation for future-work notes/decisions. The hint points unknown-task_id working-state writes to task_note_working, and also says For directed agent coordination, use task_message. when a post names an agent and asks for action or reply. Directed posts also return route_to_task_message: true, misrouted_directed_coordination: true, replacement_tool: "task_message", and a suggested_args.content value copied from the compacted post text so callers can reroute without inventing placeholder content.
Save current working state to the active Colony task. Use this to write working note, save current state, remember progress, log what I am doing, or as the notepad replacement when you do not know task_id. The note is still task/session scoped and persists through MemoryStore.
{
"name": "task_note_working",
"input": {
"session_id": "sess_abc",
"repo_root": "/abs/repo",
"branch": "agent/codex/current-work",
"content": "branch=...; task=...; blocker=none; next=run tests; evidence=...",
"pointer": {
"branch": "agent/codex/current-work",
"task": "bridge status",
"blocker": "none",
"next": "run tests",
"evidence": "bridge_status"
},
"allow_omx_notepad_fallback": true
}
}Minimal working note:
{
"name": "task_note_working",
"input": {
"session_id": "sess_abc",
"content": "branch=agent/codex/current-work; task=finish API slice; blocker=none; next=run typecheck; evidence=tests/api.test.ts"
}
}Filtered when one session participates in multiple active tasks:
{
"name": "task_note_working",
"input": {
"session_id": "sess_abc",
"repo_root": "/abs/repo",
"branch": "agent/codex/current-work",
"content": "branch=agent/codex/current-work; task=finish API slice; blocker=none; next=push PR; evidence=pnpm test"
}
}repo_root and branch are optional filters. The tool scans active task participation for the session, posts kind:"note" when exactly one task matches, and returns { observation_id, id, task_id }. If bridge.writeOmxNotepadPointer=true, a successful write appends only a tiny pointer to .omx/notepad.md: branch, task, blocker, next, evidence, colony_observation_id. The full content is never duplicated into OMX notepad after a Colony note succeeds. If multiple tasks match, it returns AMBIGUOUS_ACTIVE_TASK plus compact candidates (task_id, repo_root, branch, status, updated_at, agent) instead of guessing. If none match, it returns ACTIVE_TASK_NOT_FOUND; with allow_omx_notepad_fallback:true, it may write the same tiny pointer to OMX notepad so legacy resume still has a breadcrumb.
task_note_working is the first write path for working state. On success it
keeps the full note in Colony and skips .omx/notepad.md unless
bridge.writeOmxNotepadPointer=true. When the pointer bridge is enabled, OMX
receives only:
branch=<branch>; task=<task>; blocker=<blocker>; next=<next>; evidence=<path|command|PR|spec>; colony_observation_id=<id>
When no active Colony task matches, pass allow_omx_notepad_fallback=true only
if a transition-era OMX resume pointer is still needed. Ambiguous task
resolution never writes the fallback pointer; choose a task by repo_root and
branch first.
- Current working state starts with
task_note_working; usetask_post kind:'note'when the task id is already known and the note is not the current working-state handoff. - Routing note: use task_message for directed agent-to-agent coordination; keep task_post for shared kind:'note'|'blocker'|'question'|'answer'|'decision' thread state.
- Use specific tools for claim / hand_off / accept.
- Fallback when task_relay is unavailable in your client tool surface: post a note or blocker containing reason, one_line, base_branch, fetch_files_at if known, touched files, and whether the named source branch/worktree is missing.
- After that, use task_hand_off when another agent must resume the work.
Claim a file before editing so other agents see ownership and overlap warnings. Use this to avoid conflict and make file ownership visible before touching shared files.
Claims are warnings, not locks. They never block writes. They arm the conflict preface for the next turn.
Existing claims are age-classified before they are treated as ownership. Fresh claims can produce active overlap warnings; stale or expired/weak claims remain in audit history and may be returned as weak_stale details, but they are not active ownership and are not inherited by task_relay.
{
"name": "task_claim_file",
"input": {
"task_id": 17,
"session_id": "sess_abc",
"file_path": "packages/storage/src/storage.ts",
"note": "extending searchFts with a filter arg"
}
}Returns { observation_id }.
Accept quota-pending claim ownership from the linked quota handoff or relay. This transfers all pending claims on that baton to the replacement session, marks the baton accepted, and writes an audit note.
{
"name": "task_claim_quota_accept",
"input": {
"task_id": 17,
"session_id": "sess_replacement",
"agent": "codex",
"handoff_observation_id": 812
}
}Use handoff_observation_id when the inbox gives one. Use file_path when a
single quota-pending file identifies the baton. Returns the updated quota claim
result from TaskThread.
Decline a quota-pending claim without cancelling the linked relay. The baton is retargeted to any recipient so another agent can adopt it.
{
"name": "task_claim_quota_decline",
"input": {
"task_id": 17,
"session_id": "sess_abc",
"file_path": "apps/api/src/routes.ts",
"reason": "outside this worktree"
}
}Returns the quota-decline result from TaskThread.
Release expired quota-pending claims from active blocker status. Matching
handoff_pending claims are downgraded to weak_expired, and expired relays or
handoffs are marked expired while audit history stays intact.
{
"name": "task_claim_quota_release_expired",
"input": {
"task_id": 17,
"session_id": "sess_abc",
"handoff_observation_id": 812
}
}Omit handoff_observation_id and file_path to release all expired quota
claims on the task.
Hand off work to another agent on this task. Atomically transfers file claims from the sender to the receiver when combined with task_accept_handoff.
{
"name": "task_hand_off",
"input": {
"task_id": 17,
"session_id": "sess_abc",
"agent": "claude",
"to_agent": "codex",
"summary": "Implementation landed. Codex: run the publish e2e script.",
"next_steps": ["run scripts/e2e-publish.sh", "verify the packed CLI tarball includes staged assets"],
"blockers": [],
"transferred_files": ["apps/cli/scripts/prepack.mjs"],
"expires_in_minutes": 60
}
}to_agent ∈ claude | codex | any. Use any to broadcast; the router surfaces capability-ranked candidates in the recipient's SessionStart preface. Returns { handoff_observation_id, status: 'pending' }. The handoff is visible to the target at their next SessionStart with inlined accept with: / decline with: tool-call snippets. Handoffs expire after 120 minutes by default; use expires_in_minutes to shorten or extend the live recruitment window up to the tool limit. Expired handoffs stay in the audit trail but drop out of pending inbox/observe surfaces.
Accept a pending handoff addressed to you. Installs the transferred file claims under the accepting session.
{
"name": "task_accept_handoff",
"input": { "handoff_observation_id": 401, "session_id": "sess_xyz" }
}Returns { status: 'accepted' } on success. Errors include { code, error }, where code is stable for branching, for example HANDOFF_EXPIRED, NOT_PARTICIPANT, NOT_TARGET_AGENT, or ALREADY_ACCEPTED.
Decline a pending handoff. Records a reason so the sender can reissue, possibly targeting a different agent. Declining an expired handoff returns stable code HANDOFF_EXPIRED and marks the handoff expired instead of cancelling it.
{
"name": "task_decline_handoff",
"input": {
"handoff_observation_id": 401,
"session_id": "sess_xyz",
"reason": "out of scope for this branch"
}
}Returns { status: 'cancelled' } on success. Errors include { code, error }.
Pass unfinished work to another agent when quota, rate limits, turn caps, or a manual stop mean the sender may not be available for a normal handoff.
{
"name": "task_relay",
"input": {
"task_id": 17,
"session_id": "sess_sender",
"agent": "codex",
"reason": "quota",
"one_line": "Docs patch is half-written; finish missing relay sections.",
"base_branch": "main",
"to_agent": "any",
"fetch_files_at": "abc1234",
"expires_in_minutes": 60
}
}Relays differ from task_hand_off: they assume the sender is gone, weaken the
sender's claims to handoff_pending with a short TTL, and include a
worktree_recipe so the receiver can reproduce or inherit the work. If
fetch_files_at is omitted, the relay warns that dirty or untracked files may
need human coordination. Returns { relay_observation_id, status: 'pending' }.
Accept a pending relay and resume it in your session. This re-claims inherited
files under your session; inspect the relay's worktree_recipe before editing.
{
"name": "task_accept_relay",
"input": { "relay_observation_id": 901, "session_id": "sess_receiver" }
}Returns { status: 'accepted' }. Errors include task-thread lifecycle codes
such as OBSERVATION_NOT_ON_TASK.
Decline a relay you cannot take. The decline records a reason, cancels the pending relay, and leaves ownership available for rerouting.
{
"name": "task_decline_relay",
"input": {
"relay_observation_id": 901,
"session_id": "sess_receiver",
"reason": "branch already pruned"
}
}Returns { status: 'cancelled' }.
Send a message to another agent. Use for directed coordination that doesn't transfer file claims — for "hand off the work + files", use task_hand_off. Use task_post for generic thread notes, blockers, questions, answers, and decisions. A message is a task_post with kind message, explicit addressing, and a read/reply/expire/retract/claim lifecycle.
{
"name": "task_message",
"input": {
"task_id": 17,
"session_id": "sess_abc",
"agent": "claude",
"to_agent": "codex",
"to_session_id": "sess_xyz",
"content": "can you re-run the typecheck on your branch?",
"urgency": "needs_reply",
"reply_to": 401,
"expires_in_minutes": 60
}
}to_agent ∈ claude | codex | any. urgency ∈ fyi | needs_reply | blocking. Returns { message_observation_id, status: 'unread' }.
- Minimum call: task_message(task_id, session_id, agent, content); it broadcasts to_agent='any' with urgency='fyi'. Use to_agent / to_session_id for direct coordination that doesn't transfer file claims; for 'hand off the work + files', use task_hand_off instead.
- Urgency controls preface prominence: fyi (coalesced into a counter), needs_reply (rendered as a summary + expected action), blocking (top-of-preface, never coalesced).
- Pass reply_to to chain onto an earlier message; the parent's immediate status flips to "replied". Reply chains are 1-deep authoritative: replies-to-replies are allowed but only the immediate parent flips, never a transitively-referenced ancestor.
- expires_in_minutes is an optional TTL. Past-TTL unread messages drop out of default inbox/attention queries and any later mark_read returns stable MESSAGE_EXPIRED; their bodies stay in storage for audit and FTS.
- Replying to a still-unclaimed broadcast (to_agent=any) auto-claims it for you, hiding the broadcast from other recipients.
- Retract sent message. Recipients stop seeing it in inboxes; only the original sender can retract before it is answered, and audit storage keeps body text searchable for FTS and reply-chain history.
Directed-message workflow: task_message -> attention_inbox / task_messages -> get_observations -> task_message_mark_read -> reply.
- Sender calls
task_messagewithto_agent, optionalto_session_id,urgency, and optionalreply_to. - Recipient sees unread,
needs_reply, andblockingitems first inattention_inbox; usetask_messageswhen you need the message-only list. - Recipient hydrates message bodies with
get_observations(ids[]);task_messagesstays compact and does not return full bodies. - Recipient calls
task_message_mark_readafter reading when no reply is needed. - Recipient replies with
task_message(..., reply_to=<message id>, ...); replying to an unclaimed broadcast auto-claims it. Usetask_message_claimonly when taking a broadcast before you are ready to reply.
Read unread messages. Lists messages addressed to you across tasks you participate in (or scoped with task_ids). Compact shape includes reply_tool, suggested_reply_args, and mark_read_tool action hints; fetch full bodies via get_observations. Does not mark as read; call task_message_mark_read explicitly so an agent can peek at its inbox during planning without burning the "you have new mail" signal. Retracted messages and broadcasts already claimed by other agents are filtered out of every recipient's view.
{
"name": "task_messages",
"input": {
"session_id": "sess_abc",
"agent": "claude",
"since_ts": 1714000000000,
"unread_only": true,
"limit": 50
}
}Returns [ { id, task_id, ts, from_session_id, from_agent, to_agent, to_session_id, urgency, status, reply_to, preview, expires_at, is_claimable_broadcast, claimed_by_session_id, claimed_by_agent, reply_tool, suggested_reply_args, mark_read_tool } ], newest-first. unread_only: true is the default-inbox shape used by attention_inbox: expired unread rows are hidden there. With unread_only: false, status reflects the effective audit state: an unread row past its TTL surfaces as expired even if the on-disk status hasn't been rewritten yet.
Mark message read. Idempotent — re-marking a read or replied message is a no-op. Writes a sibling message_read observation so the original sender sees a read receipt in their attention_inbox. Returns the resulting status.
{
"name": "task_message_mark_read",
"input": { "message_observation_id": 512, "session_id": "sess_xyz" }
}Errors include { code, error } with stable codes: NOT_MESSAGE, TASK_MISMATCH, OBSERVATION_NOT_ON_TASK, NOT_PARTICIPANT, NOT_TARGET_SESSION, NOT_TARGET_AGENT, MESSAGE_EXPIRED (TTL elapsed before read; status flips to expired on the first call and later calls keep returning MESSAGE_EXPIRED), or ALREADY_RETRACTED (sender retracted the message).
Retract sent message. Sets the status to retracted and the body stops surfacing in any recipient's inbox; the body stays in storage (still searchable via FTS, still in the timeline) for audit. Cannot retract a message that has already been replied to — at that point the recipient has invested response work and silently rewriting the sender's intent would be deceptive.
{
"name": "task_message_retract",
"input": {
"message_observation_id": 512,
"session_id": "sess_abc",
"reason": "duplicate of #498"
}
}Errors: NOT_MESSAGE, TASK_MISMATCH, NOT_SENDER (only the original sender may retract), ALREADY_REPLIED, ALREADY_RETRACTED.
Claim broadcast. Once claimed, the to_agent='any' broadcast drops out of every other recipient's inbox; only the claimer keeps seeing it. Use when you want to silently take ownership of a broadcast before responding — replying via task_message already auto-claims, so this tool is for the "I'll handle it but not yet ready to reply" case.
{
"name": "task_message_claim",
"input": {
"message_observation_id": 730,
"session_id": "sess_xyz",
"agent": "codex"
}
}Returns { status: 'claimed', claimed_by_session_id, claimed_by_agent, claimed_at }. Errors: NOT_MESSAGE, NOT_BROADCAST (directed messages can't be claimed), NOT_PARTICIPANT, ALREADY_CLAIMED (someone else got there first — idempotent for the existing claimer), MESSAGE_EXPIRED, ALREADY_RETRACTED.
Pull a compact timeline of a past session (your own or another agent's) and audit the recall as a kind: 'recall' observation in the calling session. Use this when you need to stand on context from an earlier lane without pasting bodies into your current session.
{
"name": "recall_session",
"input": {
"target_session_id": "codex-abc-123",
"current_session_id": "claude-now-789",
"around_id": 4421,
"limit": 25
}
}target_session_id is the session whose memory you want to read. current_session_id is your session — it must already exist (the tool will not auto-create it). around_id centres the window on a specific observation id; limit caps the count (default 20, max 100).
Returns:
{
"recall_observation_id": 9012,
"session": { "id": "codex-abc-123", "ide": "codex", "cwd": "/repo", "started_at": 1714000000000, "ended_at": null },
"observations": [{ "id": 4418, "kind": "edit", "ts": 1714000000123 }, ...]
}Progressive disclosure: observations carries IDs only — fetch full bodies via get_observations(ids[]). The recall_observation_id is the audit row written into your current session, with metadata:
{
"recalled_session_id": "codex-abc-123",
"owner_ide": "codex",
"observation_ids": [4418, 4419, 4420, 4421, 4422],
"around_id": 4421,
"limit": 25
}Wire contract: kind: 'recall', plus metadata.recalled_session_id, metadata.owner_ide, and metadata.observation_ids. UI surfaces and search filters can key off these fields. owner_ide falls back to inferIdeFromSessionId(target_session_id) when the sessions row lists ide as unknown.
Errors include { "code": "SESSION_NOT_FOUND", "error": "..." } when either target_session_id or current_session_id is missing — the tool refuses to silently materialise a phantom session via MemoryStore.ensureSession.
Compact post-hivemind_context attention check for live pending handoffs, unread messages, blockers, stalled lanes, pending wakes, recent other-session file claims, stale claim cleanup signals, and decaying hot files. Expired handoffs are hidden from the pending bucket; the original observations remain available via timeline/search for audit. This is the main surface where task_message items show up: expired unread messages are hidden, read/replied messages stop triggering attention, and blocking messages remain prominent until read, replied, retracted, or expired. Use task_messages for a focused message-only inbox. Review compact IDs first, then fetch full bodies via get_observations only for the entries you need.
{
"name": "attention_inbox",
"input": {
"session_id": "sess_abc",
"agent": "claude",
"repo_roots": ["/abs/repo-a", "/abs/repo-b"],
"recent_claim_window_minutes": 30,
"recent_claim_limit": 20,
"file_heat_half_life_minutes": 30,
"file_heat_limit": 10
}
}Example workflow:
- Call
hivemind_contextfor active lanes plus compact memory hits. - Call
attention_inboxwith yoursession_id,agent, and repo scope. - Review compact item IDs for handoffs, unread messages, blockers, stalled lanes, fresh claims, stale-claim summary, and hot files.
- Call
get_observationsonly for the selected IDs that need full bodies.
Either repo_root or repo_roots scopes the inbox. task_ids can narrow further. recent_other_claims contains fresh active ownership only. Stale claims are summarized separately in stale_claim_signals with stale_claim_count, top stale branches, and a sweep suggestion so audit history stays separate from active ownership. file_heat is computed at read time from observations and active claims with fileHeatHalfLifeMinutes decay, so stale activity fades without a cleanup job. Returns a structured payload with attention buckets; each entry carries the IDs to hydrate on demand.
Unread task_message entries include compact action hints so recipients do not need to remember the lifecycle tools:
{
"id": 401,
"task_id": 17,
"urgency": "needs_reply",
"reply_tool": "task_message",
"suggested_reply_args": {
"task_id": 17,
"session_id": "sess_abc",
"agent": "claude",
"to_agent": "any",
"to_session_id": "sess_xyz",
"reply_to": 401,
"urgency": "fyi",
"content": "..."
},
"reply_args": {
"task_id": 17,
"session_id": "sess_abc",
"agent": "claude",
"to_agent": "any",
"to_session_id": "sess_xyz",
"reply_to": 401,
"urgency": "fyi",
"content": "..."
},
"reply_with_tool": "task_message",
"reply_with_args": {
"task_id": 17,
"session_id": "sess_abc",
"agent": "claude",
"to_agent": "any",
"to_session_id": "sess_xyz",
"reply_to": 401,
"urgency": "fyi",
"content": "..."
},
"mark_read_tool": "task_message_mark_read",
"mark_read_args": {
"message_observation_id": 401,
"session_id": "sess_abc"
},
"mark_read_with_tool": "task_message_mark_read",
"mark_read_with_args": {
"message_observation_id": 401,
"session_id": "sess_abc"
},
"next_action": "Reply with task_message using reply_to, or mark read after reading if no reply is needed."
}next_action is present on blocking and needs_reply message entries; FYI messages still include the reply and mark-read tool hints.
Find a proven approach from similar past tasks before planning or implementation. This uses embeddings when available and returns derived guidance instead of full historical bodies.
{
"name": "task_suggest_approach",
"input": {
"query": "quota relay stale claims cleanup",
"repo_root": "/abs/repo",
"current_task_id": 17,
"limit": 5
}
}Returns a suggestion payload with similar task IDs, likely files, patterns to
watch, resolution hints, and insufficient_data_reason when embeddings are
unavailable or no similar tasks clear the floor. Use returned IDs with
task_timeline or get_observations only when you need full history.
Propose a potential improvement scoped to (repo_root, branch). The proposal becomes a real task only after collective reinforcement crosses the promotion threshold.
{
"name": "task_propose",
"input": {
"repo_root": "/abs/repo",
"branch": "main",
"summary": "Extract a shared ExamplesIndex helper",
"rationale": "Three call sites reimplement the walk; diverging filter lists now.",
"touches_files": ["apps/cli/src/commands/foraging.ts", "apps/mcp-server/src/tools/foraging.ts"],
"session_id": "sess_abc"
}
}Returns { proposal_id, strength, promotion_threshold }.
Example weak candidate:
{
"name": "task_propose",
"input": {
"repo_root": "/repo",
"branch": "main",
"summary": "Show promoted proposals in colony health",
"rationale": "Agents keep leaving follow-up notes, but health reports show task_propose stayed at 0.",
"touches_files": ["apps/cli/src/commands/health.ts", "apps/cli/test/health.test.ts"],
"session_id": "sess_forager"
}
}Reinforce a pending proposal. kind='explicit' means direct support; 'rediscovered' means you arrived at the same idea independently and weighs more than explicit support; 'adjacent' is weak evidence from editing a touched file. Scoring is deterministic and source-diverse: repeated same-session reinforcement is collapsed, different sessions from the same agent type add moderate strength, and a different agent type/session adds stronger evidence. Existing rows keep their stored base weight, and session agent type is read from existing session metadata/IDE fields with conservative fallbacks.
{
"name": "task_reinforce",
"input": { "proposal_id": 42, "session_id": "sess_xyz", "kind": "rediscovered" }
}Returns { proposal_id, strength, promoted, task_id }. promoted flips true when the reinforcement crosses the threshold; task_id becomes non-null at the same moment.
Example rediscovered issue:
{
"name": "task_reinforce",
"input": { "proposal_id": 42, "session_id": "sess_second_agent", "kind": "rediscovered" }
}List pending and recently promoted proposals on a (repo_root, branch). Pending proposals whose strength has evaporated below the noise floor are omitted.
{
"name": "task_foraging_report",
"input": { "repo_root": "/abs/repo", "branch": "main" }
}Returns { pending: [ { id, strength, summary, ... } ], promoted: [ { id, task_id, summary, ... } ] }. Pending reinforcement_count counts unique reinforcing sessions, not duplicate rows.
Example pending/promoted report:
{
"name": "task_foraging_report",
"input": { "repo_root": "/repo", "branch": "main" }
}Use pending rows to decide whether to call task_reinforce; use promoted rows to find proposal-backed task threads that are ready to claim.
Set or update an agent's capability profile. Weights ∈ [0, 1]; missing weights keep their current value (or the 0.5 default for first-time profiles). Used by the handoff router to rank candidates for to_agent: 'any' broadcasts.
{
"name": "agent_upsert_profile",
"input": {
"agent": "claude",
"capabilities": { "ui_work": 0.8, "api_work": 0.7, "test_work": 0.6 }
}
}Returns the saved profile.
Read an agent's capability profile. Unknown agents return the default (0.5 across all dimensions).
{ "name": "agent_get_profile", "input": { "agent": "claude" } }Returns { agent, capabilities, defaults }.
Read the root SPEC.md for a repo. Returns parsed sections and the root hash — use the hash when opening a change to pin the base.
{ "name": "spec_read", "input": { "repo_root": "/abs/repo" } }Returns { rootHash, sections, alwaysInvariants }. Section bodies are raw; row counts are included where the section has tabular rows so callers can decide whether to hydrate.
Report drift between Colony task state and durable OpenSpec artifacts. Use this when task checkboxes, PR evidence, or cleanup records may be stale relative to the task database.
{
"name": "openspec_sync_status",
"input": {
"repo_root": "/abs/repo",
"stale_after_hours": 24,
"limit": 50
}
}Returns compact drift rows and exact repair actions, including stale checkboxes, missing PR evidence, and OpenSpec cleanup mismatches.
Open a new spec change. Creates openspec/changes/<slug>/CHANGE.md, opens a task-thread on spec/<slug>, and joins the caller as a participant.
{
"name": "spec_change_open",
"input": {
"repo_root": "/abs/repo",
"slug": "add-embedding-batch-size",
"session_id": "sess_abc",
"agent": "claude",
"proposal": "Wire the batchSize setting into createEmbedder."
}
}slug must be kebab-case. Returns { task_id, path, base_root_hash }.
Append a delta row to an in-flight change. op ∈ add | modify | remove; target is a root spec id like V.3 or T.12.
{
"name": "spec_change_add_delta",
"input": {
"repo_root": "/abs/repo",
"slug": "add-embedding-batch-size",
"session_id": "sess_abc",
"op": "modify",
"target": "V.3",
"row_cells": ["must", "embedding.batchSize passes through to createEmbedder"]
}
}Returns { delta_count } — the running total for the change.
Resolve cite-scoped context for a §T task id. Returns only the invariants and rows the task is obliged to respect, plus §V.always entries — not the whole spec.
{ "name": "spec_build_context", "input": { "repo_root": "/abs/repo", "task_id": "T5" } }Returns { cited_ids, always_invariants, rendered }. Errors with { error: 'no task <id>' } when the task is not present.
Record a test failure during /co:build. Hashes the signature, appends §B, and — if the promote_after threshold is reached — proposes a §V invariant via the colony ProposalSystem.
{
"name": "spec_build_record_failure",
"input": {
"repo_root": "/abs/repo",
"slug": "add-embedding-batch-size",
"session_id": "sess_abc",
"agent": "claude",
"test_id": "packages/embedding/test/batch.test.ts:14",
"error": "Expected 16 but got 1",
"stack": "…",
"error_summary": "batchSize ignored when provider=local",
"promote_after": 3
}
}Returns { action, signature_hash, match_count, proposal_id }. action describes whether the gate just logged, promoted to a proposal, or skipped as duplicate.
Validate, three-way-merge, and archive an in-flight change. Atomic: either the archive and root write both land, or neither does.
{
"name": "spec_archive",
"input": {
"repo_root": "/abs/repo",
"slug": "add-embedding-batch-size",
"session_id": "sess_abc",
"agent": "claude",
"strategy": "three_way"
}
}strategy ∈ three_way | refuse_on_conflict | last_writer_wins. Returns { status, archived_path, merged_root_hash, conflicts, applied }. On refuse_on_conflict with real conflicts, the call returns status: 'refused' and isError: true so the caller sees the conflict set without committing.
Decompose a high-level goal into a Colony plan and publish it as claimable sub-tasks. Use this when the goal is broad enough for multiple coordinated lanes but you do not want to hand-write every sub-task.
{
"name": "queen_plan_goal",
"input": {
"goal_title": "Document every MCP tool",
"problem": "Users cannot see the complete callable surface in one place.",
"acceptance_criteria": ["Each live tool has a docs section", "Docs coverage is tested"],
"repo_root": "/abs/repo",
"affected_files": ["docs/mcp.md"],
"ordering_hint": "wave",
"finalizer": "Verify docs coverage",
"session_id": "sess_abc",
"dry_run": true
}
}With dry_run: true, returns the normalized plan without writing. Without
dry_run, publishes a plan with auto_archive=true and returns { plan_slug, spec_task_id, mcp_capability_map, subtasks, plan_validation }.
Validate a hand-written multi-agent plan before publishing. It checks pairwise file-scope overlaps, strong live claim collisions, ordered-wave errors, module overlap warnings, and the richer plan-validation summary.
{
"name": "task_plan_validate",
"input": {
"repo_root": "/abs/repo",
"subtasks": [
{
"title": "API",
"description": "Build API route.",
"file_scope": ["apps/api/src/widgets.ts"],
"capability_hint": "api_work"
},
{
"title": "UI",
"description": "Render widget page.",
"file_scope": ["apps/frontend/src/widgets.tsx"],
"depends_on": [0],
"capability_hint": "ui_work"
}
]
}
}Returns { pairwise_overlaps, live_claim_collisions, module_warnings, ordered_wave_errors, summary, partition_clean }. A partition_clean value of
false means the plan needs sequencing, narrower file scopes, or claim
coordination before publishing.
Publish a multi-task plan as a spec change with one task thread per sub-task. Sub-tasks live on spec/<slug>/sub-N branches and link back via metadata.parent_plan_slug. The originating agent does not auto-join sub-tasks — publishing is advertising, not claiming.
{
"name": "task_plan_publish",
"input": {
"repo_root": "/abs/repo",
"slug": "add-widget-page",
"session_id": "sess_abc",
"agent": "claude",
"title": "Add widget page",
"problem": "No widget page exists yet; users have no entry point.",
"acceptance_criteria": ["Widget page renders", "Widget API returns rows"],
"subtasks": [
{
"title": "Build widget API",
"description": "Add GET /api/widgets that returns rows.",
"file_scope": ["apps/api/src/widgets.ts"],
"capability_hint": "api_work"
},
{
"title": "Build widget page",
"description": "Render the widget list with a card per row.",
"file_scope": ["apps/frontend/src/pages/widgets.tsx"],
"depends_on": [0],
"capability_hint": "ui_work"
}
],
"auto_archive": false
}
}Validation:
subtasksmust contain at least 2 entries; for a single task usetask_threaddirectly.depends_onindices are zero-based and must point to earlier indices; cycles are rejected withPLAN_INVALID_WAVE_DEPENDENCY.- Parallel sub-tasks in the same ordered wave cannot share
file_scopeentries; this is rejected withPLAN_WAVE_SCOPE_OVERLAP. - Finalizer tasks such as verification, release, targeted test, or final doc updates must run in the last wave and depend on all earlier non-finalizer work; violations return
PLAN_FINALIZER_NOT_LAST. - Independent sub-tasks (no
depends_onchain between them) still cannot sharefile_scopeentries. To overlap files, sequence the work viadepends_on.
Optional inputs:
auto_archive(defaultfalse): whentrue, the parent spec change three-way-merges and archives automatically after the last sub-task completes. Conflicts block the auto-archive (recorded as aplan-archive-blockedobservation on the parent spec task) instead of forcing — the change stays open so the merge can be resolved by hand. Leaveauto_archiveoff until you trust the lane to land cleanly; opt in per plan.
Returns { plan_slug, spec_task_id, spec_change_path, subtasks: [{ subtask_index, branch, task_id, title }] }. Errors: PLAN_INVALID_WAVE_DEPENDENCY, PLAN_WAVE_SCOPE_OVERLAP, PLAN_FINALIZER_NOT_LAST, PLAN_SCOPE_OVERLAP.
List published plans with a sub-task rollup.
{
"name": "task_plan_list",
"input": {
"repo_root": "/abs/repo",
"only_with_available_subtasks": true,
"capability_match": "ui_work",
"limit": 25
}
}Returns [{ plan_slug, repo_root, spec_task_id, registry_status, title, created_at, subtask_counts: { available, claimed, completed, blocked }, subtasks: [...], next_available: [...] }]. registry_status is registered when the plan root task exists and subtask-only when the rollup was recovered from live sub-task rows after the root registry row went missing. next_available is the list of sub-tasks whose status is available and whose depends_on chain is fully completed. capability_match filters plans where at least one sub-task in next_available has the matching capability_hint.
Find the next task to claim for this agent. Use this when deciding what to work on.
{
"name": "task_ready_for_agent",
"input": {
"session_id": "sess_def",
"agent": "codex",
"repo_root": "/abs/repo",
"limit": 5,
"auto_claim": true
}
}Returns { ready, total_available, next_action }. Each ready entry includes priority, plan_slug, subtask_index, wave_index, wave_name, blocked_by_count, title, capability_hint, file_scope, fit_score, compact reason, and reasoning. Claimable ready entries also include next_tool: "task_plan_claim_subtask", exact copy-paste claim_args, codex_mcp_call, and next_action_reason so agents can claim instead of stopping at discovery. reason is one of continue_current_task, urgent_override, or ready_high_score. Blocked work is filtered out, and conflicting active file claims lower the score. When ready work exists, next_action points at task_plan_claim_subtask with the top ready entry's plan_slug and subtask_index; if the top reason is continue_current_task, keep working the already-claimed sub-task.
auto_claim defaults to true. When set, the server claims the unambiguous ready sub-task in the same MCP call and reports the outcome in auto_claimed: { ok, plan_slug, subtask_index, task_id, branch, file_scope }, plus a next_action of Auto-claimed <slug>/sub-<n>: claim files before edits with task_claim_file, then post task_note_working. The auto-claim only fires when next_tool would be task_plan_claim_subtask and assigned_agent matches the caller — cross-agent picks and ambiguous routings still defer to an explicit claim call. Pass auto_claim: false for browse-only callers that should not change ownership state. Because the loop closes inside one MCP call, the dashboard's task_ready_for_agent -> task_plan_claim_subtask conversion metric reads near-zero in normal operation; colony health suppresses the false-positive nag when claims are happening via this path (signature: from_calls > 0, to_calls === 0, claimed > 0).
When claimable work exists, the response also includes exact routing fields:
{
"next_tool": "task_plan_claim_subtask",
"plan_slug": "example-plan",
"subtask_index": 0,
"reason": "ready_high_score",
"next_action_reason": "Claim example-plan/sub-0: it is unclaimed, dependencies are met, and it is the highest-ranked claimable ready item.",
"claim_args": {
"repo_root": "/abs/repo",
"plan_slug": "example-plan",
"subtask_index": 0,
"session_id": "sess_def",
"agent": "codex",
"file_scope": ["apps/api/example.ts"]
},
"codex_mcp_call": "mcp__colony__task_plan_claim_subtask({ agent: \"codex\", session_id: \"sess_def\", repo_root: \"/abs/repo\", plan_slug: \"example-plan\", subtask_index: 0, file_scope: [\"apps/api/example.ts\"] })"
}When no plan exists, the response includes empty_state: "No claimable plan subtasks. Publish a Queen/task plan for multi-agent work, reinforce a proposal with task_propose/task_reinforce, or use task_list only for browsing." and next_action: "Publish a Queen/task plan or promote a proposal into claimable work." When a plan exists but later waves are blocked, it keeps the same empty_state and points next_action at completing dependencies instead of fabricating a claim.
The same picker is available in the CLI:
colony task ready --session sess_def --agent codex --repo-root /abs/repoUse --json for the raw task_ready_for_agent payload.
Find stranded sessions or abandoned file claims without changing state.
{
"name": "rescue_stranded_scan",
"input": { "stranded_after_minutes": 10 }
}Returns { dry_run: true, stranded, rescued }. rescued is ordered by blocking urgency, stale age, downstream blocked count, then pending message state. Plan sub-task entries may include plan_slug, wave_index, blocked_downstream_count, blocking_urgency, stale_age_minutes, message_attention_state, and suggested_action. blocked_downstream_count ignores downstream sub-tasks that are already completed.
rescue_stranded_scan is read-only at the MCP boundary: it rolls back the core dry-run transaction, so it does not emit relays, observer notes, or release claims.
Rescue stranded sessions after explicit confirmation. This mutates state by emitting rescue relays and releasing the stranded session's claims; it does not auto-reassign to a specific agent.
{
"name": "rescue_stranded_run",
"input": {
"stranded_after_minutes": 10,
"confirm": true
}
}Without confirm: true, returns RESCUE_CONFIRM_REQUIRED.
Claim an available sub-task. The handler runs scan-before-stamp inside a SQLite transaction so two concurrent claims serialize through the write lock; the first commit wins, the second sees the prior claim observation and rejects.
{
"name": "task_plan_claim_subtask",
"input": {
"plan_slug": "add-widget-page",
"subtask_index": 0,
"session_id": "sess_def",
"agent": "codex"
}
}On success: joins the caller to the sub-task thread and activates file claims for every entry in the sub-task file_scope. Returns { task_id, branch, file_scope }. Errors: PLAN_SUBTASK_NOT_FOUND, PLAN_SUBTASK_DEPS_UNMET, PLAN_SUBTASK_NOT_AVAILABLE.
Mark your claimed sub-task complete. Releases the sub-task file claims and stamps a plan-subtask-claim observation with status: 'completed'. Downstream sub-tasks (those whose depends_on includes this one) become available automatically — task_plan_list will surface them in next_available on the next read.
{
"name": "task_plan_complete_subtask",
"input": {
"plan_slug": "add-widget-page",
"subtask_index": 0,
"session_id": "sess_def",
"summary": "Widget API landed: GET /api/widgets serving rows."
}
}Returns { status: 'completed', auto_archive: { status, reason?, archived_path?, merged_root_hash?, applied?, conflicts? } }. The auto_archive field is always present and reports what happened on this completion:
status: 'skipped'— auto-archive disabled, sub-tasks still outstanding, or no parent linkage.reasoncarries the specific cause.status: 'archived'— the merge was clean and the change is now underopenspec/archive/<date>-<slug>/.archived_pathandmerged_root_hashdescribe the result.status: 'blocked'— auto-archive opted in and the plan is fully completed, but the three-way merge has conflicts. The change stays open; resolve by hand and callspec_archivedirectly.status: 'error'— auto-archive opted in but the archive flow threw (for example a missingCHANGE.md). The completion still succeeded; the failure is recorded as aplan-archive-errorobservation on the parent spec task.
Errors on task_plan_complete_subtask itself: PLAN_SUBTASK_NOT_FOUND, PLAN_SUBTASK_NOT_CLAIMED, PLAN_SUBTASK_NOT_YOURS.
Check whether a root spec row is already bound to a published plan sub-task.
This prevents duplicate sub-task publication for the same §T or other
spec-row work item.
{
"name": "task_plan_status_for_spec_row",
"input": { "repo_root": "/abs/repo", "spec_row_id": "T5" }
}When covered, returns { plan_slug, subtask_index, task_id, branch, spec_row_id, status, claimed_by_session_id, claimed_by_agent, binding }. When
not covered, returns { spec_row_id, binding: null, status: null }.
Stateless one-shot advisor that collapses attention_inbox + task_ready_for_agent into a single decision. Returns the next tool, the args to call it with, and a sleep hint. The loop itself lives in the caller (Claude Code's ScheduleWakeup, the /loop skill, cron, or any other scheduler) — this MCP call is stateless and never sleeps.
{
"name": "task_autopilot_tick",
"input": { "session_id": "sess_abc", "agent": "claude-code", "repo_root": "/abs/repo" }
}Decision priority (first match wins):
accept_handoff— a pending handoff is addressed to this session/agent. Returnstask_accept_handoffargs withobservation_id.accept_quota_relay— a quota-pending claim is ready for adoption. Returnstask_claim_quota_acceptargs lifted from the inbox'ssuggested_actions.accept.reply_blocking_message— at least one unread message hasurgency='blocking'. Returnstask_message_mark_readargs; the caller is expected to read the body before claiming new work.claim_ready—task_ready_for_agentreturned a claimable subtask. Returnstask_plan_claim_subtaskargs (ortask_claim_quota_acceptfor a quota-relay ready entry).continue_current— the caller already holds an open subtask claim. Returnstask_plan_complete_subtaskargs; the caller should finish or hand off before switching.no_op— no actionable signal.next_toolandnext_argsarenull;suggested_wake_secondsis conservative (1200s by default).
Returned shape:
{
"generated_at": 1700000000000,
"decision": "claim_ready",
"reason": "Claim foo/sub-0: it is unclaimed, dependencies are met, and it is the highest-ranked claimable ready item.",
"next_tool": "task_plan_claim_subtask",
"next_args": { "plan_slug": "foo", "subtask_index": 0, "session_id": "sess_abc", "agent": "claude-code", "repo_root": "/abs/repo", "file_scope": ["src/x.ts"] },
"next_action": "Call task_plan_claim_subtask with plan_slug=\"foo\", subtask_index=0, ...",
"suggested_wake_seconds": 60,
"signals": {
"pending_handoff_count": 0,
"quota_pending_claim_count": 0,
"unread_message_count": 0,
"blocking_message_count": 0,
"ready_subtask_count": 1,
"stalled_lane_count": 8,
"dead_heartbeat_lane_count": 6,
"actionable_stalled_lane_count": 2
}
}Stalled lanes whose surface activity is just session-start noise — title beginning with Session start, No active swarm, or Heartbeat, plus dead-activity lanes with no title — are classified as dead heartbeats and excluded from actionable_stalled_lane_count. Callers should drive escalation off actionable_stalled_lane_count, not the raw stalled_lane_count, to avoid noisy takeover signals.
Compare a session's active claims for one task against its recent edit-tool observations within a configurable window. File-scope drift only — does not analyse semantic drift from the task description.
{
"name": "task_drift_check",
"input": { "session_id": "sess_abc", "task_id": 42, "window_minutes": 60 }
}Inputs:
session_id— the agent's session.task_id— the task whose claims and edits are compared.window_minutes— lookback for edit observations. Default 60, max 1440. Claims have no time bound; only theirstate='active'rows count.
Returns:
{
"generated_at": 1700000000000,
"task_id": 42,
"session_id": "sess_abc",
"window_minutes": 60,
"claimed_files": ["src/keeper.ts", "src/idle-claim.ts"],
"edited_files": ["src/keeper.ts", "src/uncovered.ts"],
"edits_without_claim": ["src/uncovered.ts"],
"claims_without_edits": ["src/idle-claim.ts"],
"drift_score": 0.5,
"recommendation": "Claim 1 file(s) edited without an active claim: src/uncovered.ts. Release or revisit 1 claim(s) with no recent edits: src/idle-claim.ts.",
"next_tool": "task_claim_file",
"next_args": [{ "session_id": "sess_abc", "task_id": 42, "file_path": "src/uncovered.ts" }]
}drift_score is edits_without_claim.length / max(1, edited_files.length) — the share of recent edits that fell outside the claim manifest. next_tool / next_args carry concrete task_claim_file payloads when drift exists, otherwise null. Edit-tool detection uses the canonical FILE_EDIT_TOOLS set from @colony/storage.
Reports colony token savings: live per-operation usage from the mcp_metrics table plus reference rows for common coordination loops.
Args:
since_ms?— absolute epoch-ms cutoff for the live window. Takes precedence overhours.hours?— relative live window in hours. Defaults to 24, max 720 (30d).operation?— filter live rows to one tool name (e.g."search").input_usd_per_1m?— USD price per 1M input tokens. Falls back toCOLONY_MCP_INPUT_USD_PER_1M.output_usd_per_1m?— USD price per 1M output tokens. Falls back toCOLONY_MCP_OUTPUT_USD_PER_1M.
Response shape:
{
"live": {
"note": "Recorded mcp_metrics receipts for the requested window.",
"window": { "since": 1730000000000, "until": 1730086400000, "hours": 24 },
"cost_basis": { "input_usd_per_1m_tokens": 1.25, "output_usd_per_1m_tokens": 10, "configured": true },
"totals": { "operation": "__total__", "calls": 1284, "ok_count": 1280, "error_count": 4, "error_reasons": [{ "error_code": "TASK_NOT_FOUND", "error_message": "task 6 not found", "count": 2, "last_ts": 1730086391120 }], "input_tokens": 153000, "output_tokens": 482000, "total_tokens": 635000, "total_cost_usd": 5.01125, "avg_cost_usd": 0.003903, "avg_input_tokens": 119, "avg_output_tokens": 376, "total_duration_ms": 4310, "avg_duration_ms": 3, "last_ts": 1730086391120 },
"operations": [{ "operation": "search", "calls": 412, "ok_count": 411, "error_count": 1, "error_reasons": [], "...": "..." }]
},
"reference": {
"kind": "static_per_session_model",
"note": "Static estimated per-session token cost for common coordination loops, with vs. without colony. This total is not derived from the live mcp_metrics window.",
"rows": [{ "operation": "...", "frequency_per_session": 5, "baseline_tokens": 8000, "colony_tokens": 1500, "savings_pct": 81, "rationale": "..." }],
"totals": { "baseline_tokens": 802000, "colony_tokens": 83900, "savings_pct": 90 }
}
}Live tokens are counted with @colony/compress#countTokens — the same primitive that produces observation token receipts, so values line up across surfaces. Estimated USD cost is computed at report time from the live token totals and caller-provided USD-per-1M rates; unset rates keep cost_basis.configured=false and report zero cost fields. New failure rows record error_code / error_message; older failure rows may have unknown reason fields. The reference table is static and sourced from packages/core/src/savings-reference.ts; the CLI command colony gain and the worker's /savings page render the same payload.
The lane introduces several observation kinds on the parent spec task and on the sub-task threads. They are written through MemoryStore.addObservation, so content is compressed and metadata carries the structured payload.
plan-subtask— the initial advertisement, one per sub-task at publish time.metadatacarriesparent_plan_slug,parent_plan_title,parent_spec_task_id,subtask_index,file_scope,depends_on,capability_hint, and an initialstatus: 'available'.plan-subtask-claim— every lifecycle transition (claim, complete).metadata.statusis the new state;metadata.session_idandmetadata.agentidentify the actor. The latestplan-subtask-claimobservation by timestamp is authoritative.plan-config— written on the parent spec task at publish time. Carries plan-level lifecycle policy. Today:metadata.auto_archive.plan-archived— written on the parent spec task when auto-archive succeeds. Carriesarchived_path,merged_root_hash,applied.plan-archive-blocked— written when auto-archive is ready but the three-way merge has conflicts. Carriesconflicts(the conflict set) andapplied(the deltas that did merge cleanly).plan-archive-error— written when auto-archive throws. Carries the error message inmetadata.error. The sub-task completion still succeeded; auto-archive errors never tear down completion.reflexion— reserved for one-line lessons from failure, expiry, rollback, or success outcomes. Carries the sharedReflexionMetadatapayload from@colony/core; writers store the summary/reflection throughMemoryStore.addObservation, so the body is compressed.
Fields may be added. Existing fields will not be removed or renamed within a minor version.