You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Tau's extension architecture has a clean contract: standalone binaries, CBOR over stdio, declared via harness.json5, no recompilation needed. Extensions are first-class participants in the system.
Except for one thing: slash commands are hardcoded in tau-cli.
This proposes a minimal primitive (one optional handshake field, one generic dispatch event) that lets extensions register and handle /-prefixed commands dynamically. No CLI changes per extension, no new protocol variants per feature.
The Problem
Every slash command today is hardcoded in the CLI, has a dedicated Event::UiXxx variant in tau-proto, and a hardcoded dispatch arm to match. Extensions can register tools (things the agent calls on their behalf) but they cannot offer user-initiated commands. There's no way for an extension to put a picker in front of the user, drive an OAuth flow, or surface an inline status summary.
The wall between "core" and "extension" holds everywhere in Tau's design except here.
Concrete Motivation: MCP Server Management
We're building out tau-ext-mcp and the natural UX involves a family of user-initiated commands:
/mcp — open an interactive server picker
/mcp auth github — trigger browser OAuth for a configured server
/mcp status — inline summary of all server states
/mcp enable/disable <server> — toggle a server on or off
The options for implementing this today are all unsatisfying:
Option
Problem
Hardcode /mcp into tau-cli
Breaks the "extensions are standalone" principle; every new extension needs a CLI release
Expose as a proxy tool
Requires LLM mediation for a flow the user is initiating — wrong abstraction, poor UX
Add Event::UiMcpXxx variants
Doesn't scale; every interactive extension needs new protocol types indefinitely
None of these feel right. They all feel like working around a missing primitive rather than having one.
Proposed Design
The idea is two small additions to the existing protocol: an optional declaration during the handshake, and one new generic event for dispatch.
Registration: During the Hello → Subscribe → Ready sequence, an extension optionally declares the command prefix it wants to own, a description, and the subcommands it supports (including argument hints for completion). The harness collects these declarations across all extensions and broadcasts the full set to the CLI as a harness.slash_commands_available event.
Dispatch:The CLI subscribes to that event and merges the registered prefixes into its completion registry. When a user types a command matching a registered prefix, instead of hitting a hardcoded match arm, the CLI emits a single generic ui.slash_command event carrying the prefix, the full input text, and the parsed arguments.
Handling: The harness routes that event to the owning extension. The extension handles it however it needs to and responds using the event types that already exist — HarnessInfo, ExtensionEvent, and so on. No new response types needed; the CLI already knows how to render them.
Tau's core idea is a component is just an executable that speaks the protocol. Tool registration already works this way: extensions advertise capabilities at startup, the harness routes at runtime. This proposal applies the exact same pattern to slash commands — nothing architecturally new, just the missing application of an existing idea.
Dynamic command registration would:
Keep tau-cli generic: no per-extension logic, no recompilation required for new commands
Give extensions the UX surface they need for user-initiated flows (auth, pickers, status)
Open the door to a real extension ecosystem where installing a binary gives you new / commands automatically
Open Questions
These aren't blockers, but worth settling before anything is prototyped:
Question
Strawman
Completion data for dynamic args?
Extensions push updates via ExtensionEvent; CLI caches latest
Reply rendering?
Extensions use existing event types — already rendered inline, no new plumbing
Interactive pickers?
Extension emits structured ExtensionEvent; CLI enters a generic picker mode
Harness re-broadcasts on restart; CLI refreshes its registry
Request
Would love your read on whether this belongs in the protocol, and if so, how minimal the first cut should be. The immediate need is unblocking the /mcp command family for MCP server management, but the primitive feels like it unlocks a whole class of interactive extensions — so it's worth getting the shape right rather than solving it one-off.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji