20 KiB
State Hub MCP — Tool Reference Card
Quick reference for all tools and resources.
Design Boundary
The State Hub is a read model. It observes and visualises cross-domain state that originates in the projects themselves.
Two write operations are permanently sanctioned:
| Use Case | Tools |
|---|---|
| Resolving Decisions | resolve_decision() — decisions are cross-cutting; resolution must propagate across all domains |
| Suggesting Next Steps | get_next_steps() (v0.2) — surface what is unblocked; the domain does the work |
All other mutate tools are bootstrap-only: use them during First Session Protocol to give a freshly-registered project its initial workstream structure. Do not use them as a substitute for formal work definition inside the domain repo.
Workplan terminology (STATE-WP-0065)
Preferred terms: workplan, workplan_id, /workplans/…
Legacy compatibility: workstream, workstream_id, /workstreams/…, and
create_workstream / update_workstream MCP tools remain available as aliases.
They call the same implementation as the workplan-named tools and endpoints.
| Preferred (workplan) | Legacy alias (workstream) |
|---|---|
create_workplan(repo_id, …) |
create_workstream(repo_id, …) |
update_workplan / update_workplan_status |
update_workstream / update_workstream_status |
list_workplans |
list_workstreams |
create_workplan_dependency |
create_dependency |
POST /workplans/ |
POST /workstreams/ (deprecated headers) |
workplan_id query/body field |
workstream_id (accepted alias) |
Repo classification filters: list_repos_by_classification(category?, domain?, capability_tag?, business_stake?) and extended list_domain_repos(...) query
params use GET /repos/ classification spine fields.
MCP/REST Parity and Failure Handling
The MCP server is a thin stateless HTTP client over the FastAPI service. On successful writes, MCP tools return the same JSON object shape as the REST endpoint they wrap:
| MCP tool | REST endpoint |
|---|---|
create_workplan(...) |
POST /workplans/ |
list_workplans(...) |
GET /workplans/ |
update_workplan_status(...) |
PATCH /workplans/{workplan_id} |
list_repos_by_classification(...) |
GET /repos/?category=… |
create_workstream(...) |
POST /workstreams/ |
create_task(...) |
POST /tasks/ |
update_task_status(...) |
PATCH /tasks/{task_id} |
bulk_update_task_statuses(...) |
POST /tasks/bulk-status-sync |
record_decision(...) |
POST /decisions/ |
add_progress_event(...) |
POST /progress/ |
For write tools that emit automatic progress events, the progress event is only sent after the primary REST write returns a valid object. If the API is unreachable, returns an HTTP error, or returns a malformed object, the MCP tool returns a JSON error payload instead:
{
"error": "API 404: ...",
"tool": "update_task_status",
"response": {"error": "API 404: ..."}
}
That error is intentional and actionable: do not treat it as success. Fall back
to the corresponding REST curl call from the repo instructions, then record a
normal progress event once the REST write succeeds. If the primary write
succeeds but its automatic progress event fails, the tool returns an error with
the successful write_result included so the caller can avoid duplicating the
entity while recording the missing progress event.
When API_BASE points at the optional State Hub edge relay and the central API is unreachable, queueable write tools may return a queued receipt instead of the normal REST shape. The receipt means the local outbox accepted the write; it is not yet a central commit. Automatic progress-event side effects are skipped for queued primary writes so replay does not duplicate records. Operators can inspect and replay with statehub outbox status and statehub outbox replay.
Query Tools (read-only, use freely)
| Tool | Key Args | When to use |
|---|---|---|
get_domain_summary(domain_slug) |
domain_slug: e.g. "railiance" |
Domain session start. Scoped snapshot: active workstreams, blocking decisions, last 5 events, repo SBOM status, compact capabilities list — ~10% of get_state_summary() token cost. |
get_state_summary() |
— | Cross-domain work / custodian sessions. Full snapshot: totals, all blocking decisions, waiting tasks, all open workstreams, last 20 events. Large (~10k tokens). API revision-caches unchanged snapshots (X-StateHub-Cache: hit-revision); use REST ?refresh=true only when you need a forced rebuild. |
get_topic(slug) |
slug: e.g. "markitect" |
Deep-dive on one topic + its workstreams + recent events. |
list_tasks(workstream_id, status?) |
workstream_id: UUID (required); status?: wait/todo/progress/done/cancel |
List all tasks in a workstream. Use this to look up task UUIDs before calling update_task_status, or to verify which workplan tasks are already synced to the DB. |
list_blocked_tasks(workstream_id?) |
optional filter | Legacy name: surfaces wait tasks, optionally scoped to one workstream. |
list_pending_decisions(topic_id?) |
optional filter | Decisions holding up work, sorted by deadline. |
get_recent_progress(limit, since?) |
limit default 20; since ISO datetime |
Reconstruct recent session history. |
get_capability_profile(domain_slug?) |
domain_slug: optional domain slug |
Capability deep-dive. Returns repos → capabilities tree for one domain or all active domains. Includes descriptions and keywords. For cross-domain architectural discussion or when a worker needs to understand what a domain provides without checking out its repos. |
list_capabilities(domain?, capability_type?) |
optional filters | Browse the capability catalog entries. Returns full records including keywords. |
Sanctioned Write Tools
| Tool | Key Args | Notes |
|---|---|---|
record_decision(title, ...) |
decision_type: made/pending; topic_id?; workstream_id?; deadline? |
Financial/legal + pending → auto-escalated per constitution §4. At least one of topic_id/workstream_id required. |
resolve_decision(decision_id, rationale, decided_by) |
all required | Marks decision resolved, emits progress event, writes DECISIONS.md to project directory. |
add_progress_event(summary, ...) |
event_type: note/milestone/blocker/insight; topic_id?; workstream_id?; task_id?; detail? |
Append-only log entry. Use at session end. |
Bootstrap-Only Tools
Use during First Session Protocol to give a freshly-registered project its initial workstream structure. Do not use for ongoing project management — formal work structure belongs in the domain repo (workplans, requirements, milestones).
| Tool | Key Args | Notes |
|---|---|---|
create_workstream(topic_id, title, ...) |
slug?; owner?; description?; due_date? |
Creates workstream under a topic. Use get_state_summary() to find topic IDs. |
create_task(workstream_id, title, ...) |
priority: low/medium/high/critical; assignee?; due_date? |
Creates task under a workstream. |
update_task_status(task_id, status, ...) |
status: wait/todo/progress/done/cancel; blocking_reason? describes wait conditions |
Legacy aliases blocked, in_progress, cancelled, and canceled are accepted during migration. |
bulk_update_task_statuses(updates, author?, session_id?) |
updates: list of {task_id, status, blocking_reason?} |
Updates many task statuses in one REST call and emits one task_status_changed progress event per task. Prefer this at session checkpoints instead of many single-task calls. |
update_workstream_status(workstream_id, status) |
status: proposed/ready/active/blocked/backlog/finished/archived |
Thin shortcut — use update_workstream for full field control. |
update_workstream(workstream_id, ...) |
title?; description?; owner?; due_date?; repo_goal_id?; status? |
Patch any subset of workstream fields. Pass empty string for repo_goal_id to clear the link. |
Human Interventions
Tasks that agents cannot complete themselves are flagged with needs_human=True.
Use list_human_interventions() at session start to see Bernd's action items.
| Tool | Key Args | Notes |
|---|---|---|
flag_for_human(task_id, note) |
task_id: UUID; note: action description (required) |
Sets needs_human=True + intervention_note. Emits progress event. |
clear_human_flag(task_id) |
task_id: UUID |
Clears flag after human completes the action. Emits progress event. |
list_human_interventions(workstream_id?) |
optional workstream filter | Returns all tasks with needs_human=True. |
Token Consumption Tools
Record and query AI token usage at task/workstream/repo/commit/release granularity.
Agents should call record_token_event (or pass tokens_in/tokens_out via
update_task_status) at task completion.
| Tool | Key Args | Notes |
|---|---|---|
record_token_event(tokens_in, tokens_out, ...) |
task_id?, workstream_id?, repo_id?, model?, agent?, ref_type?, ref_id?, note?, session_id? |
POSTs to /token-events/. workstream_id auto-filled from task. Returns event id + running total. |
get_token_summary(scope, id) |
scope: task|workstream|repo|commit|release|session; id: UUID or ref string |
Returns formatted table of tokens_in/out/total, event_count, by_model, by_agent. |
record_adhoc_task(title, repo_slug, ...) |
tokens_in?, tokens_out?, note?, model?, agent?, description?, session_id? |
Find-or-create today's file-backed ADHOC-YYYY-MM-DD workplan/workstream, append task block, mark done, record token event. |
record_interactive_task(title, repo_slug, ...) |
same as record_adhoc_task |
Deprecated compatibility alias; use record_adhoc_task. |
Token note taxonomy:
| note | meaning |
|---|---|
"measured" |
Exact counts read from Claude Code status bar — default when tokens_in/tokens_out provided |
"userbased" |
Counts provided by a human (pass note="userbased" explicitly) |
"workplan" |
Prorated from workplan total across task count |
"heuristic" |
Server fallback — 1 000 in / 500 out, no agent input |
Governance Tools
| Tool | Key Args | When to use |
|---|---|---|
validate_repo_adr(repo_slug, domain_slug?) |
repo_slug: registered repo slug (e.g. "the-custodian"); domain_slug?: for orphan detection |
Check a repo against ADR-001. Resolves the local path from the DB (uses this host's registered path). Detects missing workplans/ dir, invalid frontmatter, stale workstream ID references, and DB-only orphan workstreams. Always runs against the MCP server's copy — see Multi-Host section below. |
Resources (URI-addressable, read-only)
| URI | Returns |
|---|---|
state://summary |
Full StateSummary JSON |
state://topics |
Active topics list |
state://workstreams/{topic_slug} |
Workstreams for a topic (by slug) |
state://decisions/blocking |
All pending decisions |
state://tasks/blocked |
Legacy resource name; returns all wait tasks |
Domain Management Tools (v0.5)
Domains are now first-class DB entities. Use list_domains() to discover available slugs.
| Tool | Key Args | Notes |
|---|---|---|
list_domains(status?) |
status: active/archived/all (default: active) |
Discover all registered domains. |
create_domain(slug, name, description?) |
slug: lowercase_underscored; name: display name |
Register a new project domain. |
rename_domain(slug, new_slug, new_name) |
all required | Renames domain and cascades to EP/TD string columns. |
archive_domain(slug) |
slug |
Soft-delete; fails if active topics exist. |
list_domain_repos(domain_slug) |
domain_slug |
List repos registered under a domain. |
register_repo(domain_slug, name, ...) |
slug?; local_path?; remote_url? |
Register a git repo under a domain. |
update_repo_path(repo_slug, path, host?) |
repo_slug: e.g. "marki-docx"; path: absolute local path; host: defaults to current hostname |
Register this machine's local path for a repo. Use when the same repo lives at different paths on different machines (e.g. /home/worsch/… vs /home/tegwick/…). The consistency checker prefers this over local_path. |
SCOPE.md Health Contract
Repo dispatch includes scope_needs_review and scope_issue_details.
scope_issue_details reports C5a/C5b/C5c with machine-readable
missing_sections, invalid_capability_blocks, and needs_refresh_sections.
For ecosystem refresh, call:
curl "http://127.0.0.1:8000/repos/scope-health?needs_review=true&reachable_only=true"
The list response returns active repos with repo_slug, domain_slug,
local_path, path_available, scope_needs_review, and the same
scope_issue_details shape. Repo-scoping should use needs_refresh_sections
to update only the affected SCOPE.md sections.
Agent Inbox Tools
Inter-agent coordination via shared message board. Check inbox at session start; send messages to coordinate across Claude instances.
Agent names: use the repo slug (e.g. "marki-docx", "railiance") or "hub" for the custodian agent.
Use "broadcast" as to_agent to send to all agents.
| Tool | Key Args | When to use |
|---|---|---|
get_messages(to_agent?, from_agent?, unread_only?, limit?) |
to_agent: your agent name; unread_only: True recommended at session start |
Check for pending coordination messages. |
send_message(from_agent, to_agent, subject, body, thread_id?) |
all except thread_id required |
Send a coordination message to another agent (or broadcast). |
mark_message_read(message_id) |
message_id: UUID |
Mark a message as read after acting on it. |
reply_to_message(message_id, from_agent, body) |
all required | Reply in-thread; marks original as read. |
Dashboard: http://localhost:3000/inbox
Kaizen Agents
Specialized agent personas from kaizen-agentic/agents/. Each agent is a markdown
instruction set — load it and follow the instructions it contains.
| Tool | Key Args | When to use |
|---|---|---|
list_kaizen_agents(category?) |
category: optional filter (testing/quality/process/infrastructure) |
Discover all 17 available agent personas with name, description, category. |
get_kaizen_agent(name) |
name: e.g. "tdd-workflow", "code-refactoring" |
Load full agent instructions. Read and follow them. |
Common agents:
| Agent | Category | When to use |
|---|---|---|
tdd-workflow |
testing | Step-by-step TDD8 workflow for any feature |
code-refactoring |
quality | Code quality analysis and safe refactoring |
test-maintenance |
testing | Diagnose and fix failing tests |
requirements-engineering |
process | Prevent interface/mock mismatches upfront |
keepaTodofile |
process | Maintain TODO.md during work |
project-management |
process | Track status, determine next steps |
scope-analyst |
project-management | Analyze a repo and produce/improve SCOPE.md |
datamodel-optimization |
quality | Optimize dataclasses and data structures |
Multi-Host & Remote Agent Usage
Three tools access the local filesystem on the MCP server machine:
| Tool | File-sys operation |
|---|---|
validate_repo_adr |
Runs validate_repo_adr.py against the server's repo checkout |
check_repo_consistency |
Runs consistency_check.py against the server's repo checkout |
ingest_sbom_tool |
Runs ingest_sbom.py against the server's lockfiles |
Design boundary: these tools always execute on the machine where the MCP server
runs (bnt-lap001), against the path registered for that host. A remote agent
calling them gets results from the server's checkout — not from its own working copy.
Implications for remote agents (e.g. workers on COULOMBCORE)
- Ahead of server on a branch? Results will be based on the server's (older) copy. Sync first: push your branch and pull it on the server, or accept the gap.
- Pure-API tools (
get_state_summary,create_task,add_progress_event, etc.) work correctly from any host — they query the DB, not the filesystem.
Running file-sys scripts locally from a remote host
# From COULOMBCORE (tunnel maps remote :18000 → bnt-lap001 :8000):
python scripts/consistency_check.py --repo the-custodian --api-base http://127.0.0.1:18000
python scripts/validate_repo_adr.py /home/tegwick/the-custodian --api-base http://127.0.0.1:18000
Registering a new host path
# Via MCP tool:
update_repo_path("marki-docx", "/home/tegwick/marki-docx") # defaults to current hostname
# Via Makefile (on the machine where the path lives):
make register-path REPO=marki-docx PATH=/home/tegwick/marki-docx
# Via API directly:
curl -X POST http://127.0.0.1:8000/repos/marki-docx/paths/ \
-H "Content-Type: application/json" \
-d '{"host": "your-hostname", "path": "/home/you/marki-docx"}'
Capability Catalog & Requests
Capabilities describe what each domain/repo can provide. Use the catalog for routing; use requests for cross-domain work coordination.
Catalog tools
| Tool | Key Args | Notes |
|---|---|---|
register_capability(domain, capability_type, title, ...) |
domain: slug; capability_type: infrastructure/api/data/security/governance/documentation; keywords?; description?; repo_slug? |
Add a capability to the catalog. Provide repo_slug to attribute it to a specific repo within the domain. |
list_capabilities(domain?, capability_type?) |
optional filters | Browse active catalog entries with full detail (description + keywords). |
get_capability_profile(domain_slug?) |
optional domain slug | Deep-dive. Returns domain → repos → capabilities tree with descriptions and keywords. Single domain or all active domains. Use when a worker needs to understand what a domain provides without checking out its repos. |
Request tools
| Tool | Key Args | When to use |
|---|---|---|
request_capability(title, capability_type, requesting_domain, requesting_agent, ...) |
priority?; description?; requesting_workstream_id?; blocking_task_id? |
Ask another domain to provide a capability. Auto-routes to best matching catalog entry. |
list_capability_requests(domain?, status?, capability_type?) |
optional filters | List open requests — filter by your domain to see what you must fulfill. |
get_capability_request(request_id) |
request_id: UUID |
Full detail on a single request. |
accept_capability_request(request_id, fulfilling_agent, ...) |
fulfilling_workstream_id? |
Accept a request routed to your domain. Notifies requester. |
update_capability_request_status(request_id, status, note?) |
status: in_progress/ready_for_review/completed/rejected/withdrawn |
Advance request lifecycle. completed auto-unblocks the linked task. |
dispute_capability_routing(request_id, reason, disputed_by, suggested_domain?) |
all required except suggested_domain |
Flag incorrect routing. Notifies custodian for re-routing. |
reroute_capability_request(request_id, rerouted_by, note, domain?, catalog_entry_id?) |
one of domain/catalog_entry_id required |
Re-route a disputed request to the correct domain. |
patch_capability_request(request_id, ...) |
catalog_entry_id?; priority?; blocking_task_id?; fulfilling_workstream_id? |
Correct mutable metadata on a request. |
Request status flow: requested → accepted → in_progress → ready_for_review → completed
Dispute path: requested → routing_disputed → requested (after re-route)
Domain Slugs
Run list_domains() to get the live list. Default 6: custodian · railiance · markitect · coulomb_social · personhood · foerster_capabilities
Common Patterns
# Session start:
get_state_summary()
# Decision resolved in the hub UI or via tool:
resolve_decision(decision_id="<uuid>", rationale="...", decided_by="Bernd")
# Session end:
add_progress_event(
summary="...",
event_type="note", # or milestone / insight / blocker
topic_id="<uuid>",
workstream_id="<uuid>", # optional
detail={"key": "value"}, # optional
)
# First Session Protocol only — bootstrap a new project:
create_workstream(topic_id="<uuid>", title="My Workstream", owner="me")
create_task(workstream_id="<uuid>", title="Do the thing", priority="high")