Repository navigation
feat: tasks between bots through MCP tools (M3, part 2) - #4
Merged
Merged
Conversation
The message line of the Claude Code inbox is not documented, so it was tested with Claude Code 2.1.283 before the courier depends on it: the line in 9.2 is delivered and opens a turn, a missing or wrong auth line closes the connection, and Claude Code never replies. The same run confirmed --continue resuming a real conversation. Also settles what the courier does: in order and one at a time per bot, a 10 s send timeout, deterministic retry backoff, archived bots' queues dropped, and an English envelope with a relative deadline.
Protocol types for spec 9 and 11 (Message, Delivery, Task, their enums and the messages.*/deliveries.* params), exported to TypeScript, plus the envelope a bot reads when a message arrives and validation for message bodies.
Migration 0002 creates the three tables of spec 12. A message is saved with its delivery and the task it creates in one transaction. Delivery transitions are single conditional UPDATEs; due_deliveries hands out only each bot's oldest pending delivery, and only while none of that bot's deliveries is being sent, so messages arrive in order.
Opens the bot's named pipe as a client, retries for up to 2 s while it is busy, writes and closes. The address comes from a bot's hook, so only plain names under \\.\pipe\ are accepted: a ".." segment could make CreateFile open a real file.
The courier moves pending deliveries into the bots' inboxes: it waits without counting attempts while a bot is not ready, retries failures with backoff until max_attempts, recovers expired leases, drops the queue of archived bots and does not blame a delivery when the bot restarted during the send. Times come from an injectable clock, so the tests drive retries with a manual clock and a fake inbox. New RPC methods messages.send, messages.list, deliveries.list and deliveries.retry, the message.created and delivery.changed notifications, and the delivery backlog in system.status. Also fixes the test daemon's botloftd path, which had backspace characters in it.
Settles how a task chain is found (the sender's deepest open task),
deadlines, late results and the expiry notice, and what each tool
returns. The MCP server speaks both MCP eras: Claude Code 2.1.284
sends server/discover (2026-07-28) first and falls back to initialize
(2025-11-25), as seen with a headless run that fails on an unknown
model before spending tokens. The same run confirmed the
${BOTLOFT_BOT_TOKEN} expansion in mcp.json headers.
Generated settings now allow mcp__botloft, so a bot on its own can use
the crew tools without a permission prompt.
Tasks can be listed by crew, assignee, requester and status, and open tasks past their deadline found. settle_task moves a task to its new status and saves the message that reports it in one transaction, and does nothing when the task is no longer in an expected status.
Params and method name for listing tasks, exported to TypeScript, and the relative deadline text made public for the tools to reuse.
A bot can send a note or a task to another bot of its crew. A task continues the chain the sender is working on and is refused past max_hops. Only the assignee completes a task, also after the deadline, and the requester gets the result as a message. The courier expires overdue tasks each cycle and tells the requester. tasks.list lists them for the app.
POST /mcp gives each bot crew_roster, send_message, complete_task and my_tasks, authenticated with the bot token of a live generation. It answers MCP 2026-07-28 (server/discover, header checks, caching hints, which Claude Code needs to accept the tool list) and the initialize flow of earlier revisions. Mistakes a model can fix come back as tool errors it can read. Generated settings allow mcp__botloft and the rules tell bots to close every task they receive with complete_task. Tested with Claude Code 2.1.284: one bot delegated a task to another, which completed it, and the result came back, with nobody stepping in.
httpsphl
enabled auto-merge
September 28, 2026 19:24
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Second and last slice of M3 (spec 17): bots message each other and hand off tasks through MCP tools. This PR is built on #3. Merge #3 first (merge commit); this diff then shrinks to the five commits below.
With this PR, M3's acceptance test passes with real Claude Code: two bots exchange a task and its result without anyone stepping in.
What changes
POST /mcpgives each bot four tools:crew_roster,send_message,complete_taskandmy_tasks. It is authenticated with the bot token of a live generation.server/discover(MCP 2026-07-28, no handshake). If that fails, it falls back toinitialize(2025-11-25). The server answers both:-32020), unsupported versions (-32022), 404 for unknown methods, and the caching hints (ttlMs,cacheScope). Without those hints, Claude Code rejects the tool list.initializeside: version negotiation, notifications get 202, and GET/DELETE get 405.max_hopswith an explanation.isErrorresults with a sentence it can act on.mcp__botloft, so a bot on its own is never stuck at a permission prompt. The trust dialog shows this rule. The bot rules now ask bots to close every task withcomplete_task.tasks.listis available to the app.Tests
tests/mcp.rs:initializepath;Mcp-Nameform;tests/tasks.rs, bot to bot through the tools withFakeRuntimeandFakeInbox:my_tasks;pnpm check.Real Claude Code checks (done, 2.1.284)
claude -p --mcp-config ... --model <unknown>connects its MCP servers before failing on the model. A logging server showedserver/discoverwith the 2026-07-28 headers, theninitializewith 2025-11-25, and theAuthorizationheader with${VAR}expanded./mcpfirst showed "botloft · tools fetch failed". The cause was the missing caching hints. After the fix it shows "botloft · 4 tools", with a singletools/listper bot.@probeand@helperin one crew, folders trusted):@probeviamessages.sendto send@helpera task: the sum of 17 and 25.@probecalledsend_message.@helpergot[botloft] from @probe · crew Real Test · task tsk_... · due in 2 hand calledcomplete_taskwith "17 + 25 = 42".@probegot the result and answeredRESULTADO 42.donewithhops: 1, and all 5 deliveries aresentwith 0 failed attempts. The daemon log has no message bodies or tokens.Notes