Origin
This group chat system is going to be a struggle with every bot instantly trying to reply immediately lol.
Max, colony chat
I think the turn taking will need to be a pretty strong harness. Maybe I just need to limit conversations to two bots, or a chain of bots through the turn keeper?
Max
Yeah let's try chain. It is very helpful tho to have a chat UI for it. Maybe rather than group chats we have kind of chain IDs or something. Then we can easily chain other bots in too, and they can read up the chain.
Max
What we're solving
Multi-bot group chats produce simultaneous replies. Every bot races to respond, creating duplicated messages and incoherent conversations. Manual moderation works but burns coordinator context and adds latency.
Bots collaborate on tasks sequentially — each participant contributes in order, reads full prior context, and the coordinator controls the flow. The monitor dashboard shows chains as navigable threads.
What it must do
Manual chaining
What we do today: CEO DMs each bot in sequence, copy-pasting relevant context.
Channel-level chains Selected
New chains table and MCP tools. Chains are a first-class colony feature enforced at the channel server level.
chains table: id, name, coordinator, current_turn, participants (JSON), state (active/completed)chain_messages table: chain_id, turn_number, sender, content, timestamp. Separate from main messages table.colony_chain_create(name, coordinator) — creates chain, coordinator is the turn controllercolony_chain_add(chain_id, bot, prompt) — adds a bot, delivers full chain history + prompt, sets as current turn holdercolony_chain_message(chain_id, content) — current turn holder posts. Rejects if sender isn't turn holder (enforces R6)colony_chain_pass(chain_id, to_bot, prompt) — passes turn to next bot with a prompt. Delivers chain history.colony_chain_close(chain_id) — coordinator closes chain, state → completedTagged group messages
No new tables. Chains as a convention on top of existing group messages with chain_id tag and turn enforcement in the send tool.
chain_id and chain_turn columns to existing messages tablecolony_send gains --chain flag. Rejected if sender doesn't hold turn.presence table or small key-value storechain_turn_to: botnameCoordinator bot (Haiku) Rejected
A lightweight Haiku bot that manages turn-taking, sitting between participants and controlling message flow.
@bot your turn directives, holds othersRequirements vs shapes
C is eliminated — fails the core goal (R0) and 4 must-haves. You can't enforce turn-taking with a bot that sits alongside participants. Enforcement must happen at the message delivery layer.
A over B — both pass all must-haves. A is cleaner: separate tables avoid ambiguity ("is this message part of a chain or a regular chat?"). B's only advantage is R8 (fewer tools), but A's tools are simple and well-scoped.
Shape A — Channel-level chains
Shape A is the strongest. It cleanly separates chain data from regular messages, enforces turn-taking at the server level, and produces a clear data model for the monitor UI.
The cost is 5 new MCP tools, but they're simple: create, add, message, pass, close. Each maps to one DB operation.
Architecture summary
Key decisions:
- Turn returns to coordinator after every bot post — prevents bots from passing turns directly to each other
- History delivered as formatted context block via existing notification polling
- Handoff messages stored with type="handoff" — part of the chain record, render as visual turn bars
- chain_messages is separate from messages table — chains don't pollute regular inbox
Implementation steps
chains and chain_messages tables. Add query functions: createChain, addParticipant, postMessage, getHistory, passTurn, closeChain, listChains, getChain./api/chains and /api/chains/:id endpoints.Chains.tsx component: chain list + thread views. Add to sidebar nav.