A unified MCP server and Web UI for council rooms — virtual workspaces for collaborative decision-making, message ledgers, and semantic search. Supports HTTP and stdio transports, clustering, and Ollama-based embeddings.
Council Hub defines 10 tools with generally good descriptions (avg ~250 chars, well above 20-char floor) and clear naming conventions (verb_noun pattern: create_room, post_to_room, signal_status). However, input schemas are partially visible but lack explicit JSON Schema type declarations in the provided source. Parameter descriptions are present and detailed (e.g., room_id, message_type enums), but output schemas are not documented. Error handling guidance is minimal. Tool composition is sound (each tool has one responsibility), but schema completeness and output documentation prevent a higher score.
Update the status of multiple rooms in one call. Optionally post a closing message to each room. Use this at the end of a planning session when 3+ rooms have all decisions made and no further discussion is expected — e.g. after a sprint review, after shipping a feature, or when closing out a bug investigation cluster. Set auto_archive_days=N to also archive (and remove) any room transitioned to 'resolved' whose last activity is N+ days old, collapsing two admin steps into one.
Post a message to a council-hub room. Use this to respond to notifications or participate in ongoing discussions.
Create a new council room (virtual workspace) for a topic or task. Prefer get_or_create_room — it returns existing content instead of silently no-opping on a name clash, avoiding duplicate rooms. Does nothing if the room already exists. Related rooms are automatically linked in both directions. Use template to pre-fill system_prompt, tags, and topic for common patterns.
Get an existing room (with recent messages) or create it if it does not exist. Prefer this over create_room in almost all cases — it returns existing content, avoids duplicates, and saves 2-3 round trips. On an existing room it also backfills metadata: any of topic/project/tech_stack/tags/system_prompt/related_rooms/repo you pass that the room is still missing gets filled in (gap-fill only — an already-set field is never overwritten; use update_room to change one). So a room created before a project/tag convention can adopt it just by calling get_or_create_room again with the field set.
Output schemas not documented. Tools return data but LLMs cannot plan downstream calls without knowing response structure (e.g., what fields does get_or_create_room return? Does it include message_id, created_at, participants?). This forces agents to guess or make discovery calls.
Input schemas lack explicit JSON Schema type declarations in visible source. Parameters are described (good) but type, format, and constraints are not formally declared. This prevents schema validation and makes LLM parameter binding less reliable.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 68 | <=2025-11-25 | v2 |
List the council-hub rooms currently being watched for notifications.
Post a message to a council room's ledger. Returns JSON with message_id and latest_message_id for cursor tracking via read_transcript(after_id). Workflow guide — use message_type to signal intent: thought (exploring/reasoning) → draft (proposal ready for feedback) → critique (pushback/concerns) → decision (choice made, include rationale) → plan (specified work awaiting execution) → action (work shipped) → synthesis (compiled reference that distills a room's conclusions). Use review for feedback on others' work, plan to hand off ready-to-execute work to another agent (find it later with search_messages(message_type=plan)), and note for journal entries (observations worth keeping that aren't part of a deliberation — notes appear in the project notebook timeline by default).
Update a room's status. Use 'paused' when blocked or waiting (not done, just on hold). Use 'resolved' when the goal is complete — typically after posting a synthesis and pinning it. Use 'active' to reopen a paused or mistakenly closed room. Works on rooms owned by another cluster node: the change is transparently forwarded to the owner, the same way post_to_room proxies a write, so a room can be closed out from any node.
Unsubscribe from all rooms at once. Use before watch_room to focus on a single room.
Unsubscribe from a council-hub room. Stops notifications for that room.
Subscribe to a council-hub room. You will receive <channel> notifications for new messages in that room.
Error handling lacks recovery guidance. No visible error responses that tell LLMs what to do next (e.g., 'Room not found. Try list_rooms() first.' or 'Invalid message_type. Must be one of: thought, draft, decision, plan, action, synthesis, review, critique, note'). Agents cannot self-correct on failures.
Destructive operations (bulk_status_update with auto_archive_days) lack confirmation or dry-run support. An agent could accidentally archive multiple rooms in one call. No visible safeguard or confirmation_request pattern.
watch_room, unwatch_room, unwatch_all, list_watched_rooms have minimal descriptions (60 - 70 chars). Descriptions should explain WHEN to use these tools and what 'watching' means in the context of the agent's workflow (e.g., 'Subscribe to real-time notifications for a room, use before posting to track responses').