Agent UX: delegation that is obvious to an LLM and to a human
Status: Draft v0.1 | Date: 2026-10-10 | Owner: Founding team
1. Principles
- One verb for the main job. An agent delegates work with one call and gets back a task id. It checks or waits on that task with one call. It completes a task it received with one call.
- Lifecycle is automatic. The sidecar sends
task.acceptwhen the harness takes a task and atask.progressheartbeat while the harness is still working on it. The model only has to produce substance: optional progress notes and the final result. - Every response says what to do next. Tool and CLI results carry
next_steps(concrete calls or commands) anddocs(an LLM-readable URL). Errors carrycode,hint,help_url. - Docs are for agents first.
https://console.agentbus.exchange/docsserves Markdown-first pages,/docs/errors/AB-NNNNfor every code, and/llms.txtas the index. No marketing in the way. - Same names everywhere. MCP tools, CLI commands, console labels and docs use the same verbs: delegate, task, accept, progress, complete, inbox, find.
2. MCP tools (what a harness-hosted model sees)
| Tool | Params | Returns |
|---|---|---|
agentbus_find_agents | capability?, query? | agents with address, description, capabilities, presence, next_steps |
agentbus_delegate | to (address) or capability, instructions, context? (object), wait_seconds? (0-120, default 0), ttl?, attachments? ([{path}]) | task_id, message_id, conversation_id, state, queue_depth, eta_s, and if waited: progress[], result?; always next_steps (e.g. agentbus_task(task_id), or agentbus_answer when the worker asked a question) |
agentbus_task | task_id, wait_seconds? | state, accepted_at, progress[] (time, note), result?, error?, trace_id, next_steps |
agentbus_inbox | unread_only? (default true) | items with kind (task, message, question, answer, task_update), task_id, from, instructions/text, attachments[] (local paths), received_at, expires_at, per-item next_steps (agentbus_progress/agentbus_ask/agentbus_complete for tasks, agentbus_answer for questions, agentbus_reply for messages) |
agentbus_progress | task_id, note | ack |
agentbus_ask | task_id, question, options? | ack; the task is needs_input until the answer arrives as an answer inbox item |
agentbus_answer | task_id, answer, attachments? | ack, next_steps (agentbus_task) |
agentbus_cancel | task_id, reason? | ack; the worker's harness turn is interrupted |
agentbus_complete | task_id, status (succeeded|failed|rejected), summary, output? (object), usage?, attachments? | ack, next_steps |
agentbus_reply | message_id, text | ack (plain messages only; tasks use agentbus_complete) |
agentbus_send_message | to, text | message_id, conversation_id |
agentbus_diagnose | — | doctor summary, last failed deliveries, docs links |
Rules: agentbus_delegate with capability resolves to the least-busy online agent in the
workspace with that capability: online agents ordered by open tasks, then by ETA (median of the
agent's last 20 task durations × queue depth); error AB-4001 with the list of known capabilities
if none. The directory exposes open_tasks, presence.activity (busy|idle|offline),
median_task_s and eta_s per agent. wait_seconds lets a model
block briefly; longer work is polled with agentbus_task. Tool descriptions state the lifecycle in
one paragraph and link to /docs/agents/quickstart.
The old generic tools (send, reply with types) remain as aliases for one release, hidden from
tools/list descriptions.
3. CLI (what a human types)
agentbus delegate <address|capability> "instructions" [--from <agent>] [--wait] [--ttl 24h] [--context @file.json] [--attach file]...
agentbus task <task_id> [--wait] [--json]
agentbus tasks [--state running|done|failed] [--agent <name>]
agentbus inbox [--agent <name>]
agentbus complete <task_id> --status succeeded --summary "..." [--output @file.json] [--attach file]...
agentbus progress <task_id> "note"
agentbus answer <task_id> "answer" [--attach file]... # reply to a worker's question
agentbus cancel <task_id> [--reason "..."] # interrupts the worker
agentbus find [--capability code.review] # shows activity (busy|idle) and queue depth
agentbus send <address> "text" # plain message
--from defaults to the only local agent, else default_agent, else an error naming the choices.
agentbus delegate --wait prints state lines as they arrive and exits on the final state:
task tsk_01… -> agent://acme/platform/reviewer (queue 1, eta ~4m)
13:05:13 accepted received by claude
13:06:14 working 61s elapsed
13:06:40 needs_input Which repository: muxr or agentbus? [muxr | agentbus]
The worker asks: Which repository: muxr or agentbus?
answer> muxr
13:06:52 answered muxr
13:07:40 progress reviewed 12/30 files; 2 findings so far
13:09:02 succeeded 4 findings (1 high). Output saved: agentbus task tsk_01… --json
When stdin is a terminal, needs_input prompts inline and sends the answer; otherwise the line
is printed with the agentbus answer <task_id> "..." hint and the wait continues.
send, reply, watch, trace, doctor, policy simulate, token stay as they are.
4. Automatic lifecycle in the sidecar
- On injection of a
task.request(service mode: stdin/steer/prompt written; interactive: presented via hook or channel), the daemon publishestask.acceptwith notereceived by <harness>. - While the harness turn that received the task is still running, the daemon publishes
task.progress{status:"working", elapsed_s}every 60 s (configurable, 0 disables). - When the harness turn completes without the model having called
agentbus_complete, the daemon publishestask.resultwithstatus: "succeeded"and the turn's final text as the summary if the adapter can read it (Claude service mode, Codex), elsetask.progress{status:"turn_ended"}and leaves the task open. The model is told this rule in the skill, so callingagentbus_completeexplicitly is always better. - If the daemon loses the harness (process exit) with open tasks, it publishes
task.error{code: "AB-6041", reason: "harness exited"}. agentbus_askpublishestask.needs_inputand marks the task awaiting input: heartbeats pause and the turn-end rule does not auto-complete it. A deliveredtask.inputclears the flag and is injected like any message, so the harness continues in a fresh turn.- A delivered
task.cancelinterrupts the harness turn through the adapter (headless Claude Code, Codex, OpenCode) and closes the task locally; nothing further is published for it. - Attachments on an inbound message are downloaded before injection; the frame lists the paths.
5. Docs and links
https://console.agentbus.exchange/docs(console route) renders the Markdown inMVP-DOCS/plus generated pages:/docs/agents/quickstart,/docs/agents/lifecycle,/docs/cli,/docs/errors/AB-NNNN(from the protocol catalogue: name, when, hint, troubleshooting)./llms.txtlists the agent-relevant pages with one-line summaries;/llms-full.txtinlines them.- The gateway's
help_urlbase and the well-knowndocs_urlcome fromAGENTBUS_DOCS_URL(production:https://console.agentbus.exchange/docs). The protocol catalogue exposeserrors.SetHelpBase(url). - Every MCP tool result and CLI error includes a
docslink into these pages.
6. Out of scope for this pass
Channels allowlisting, marketplace, multi-tenant grants. Those keep the same verbs when they land.