Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

RFC: Dynamic Slash-Command Registration (Let Extensions Own / Prefixes) #2

daemonp started this conversation in Ideas
Discussion options

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.

sequenceDiagram
 participant Ext as Extension (tau-ext-mcp)
 participant Harness
 participant CLI
 
 Note over Ext,CLI: Registration phase (startup)
 Ext->>Harness: Hello (advertises /mcp prefix + subcommands)
 Harness->>CLI: slash_commands_available
 CLI->>CLI: merge into completion registry
 
 Note over Ext,CLI: Dispatch phase (user types /mcp auth github)
 CLI->>Harness: UiSlashCommand { prefix: mcp, args: [auth, github] }
 Harness->>Ext: route to registered extension
 Ext-->>Harness: HarnessInfo / ExtensionEvent (response)
 Harness-->>CLI: render inline
Loading

Philosophical alignment

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
Collision with built-in commands? Built-ins win; extensions cannot shadow core commands
Extension restart/reload? 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.

You must be logged in to vote

Replies: 0 comments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Ideas
Labels
None yet
1 participant

AltStyle によって変換されたページ (->オリジナル) /