zeph-commands
Slash command registry, handler trait, and channel sink abstraction for Zeph.
This crate provides the non-generic infrastructure for slash command dispatch. It has no
dependency on zeph-core — the agent implements the provided traits and wires them in at
startup.
Modules
sink— [ChannelSink] minimal async I/O trait; replaces theC: Channelgeneric in handlerscontext— [CommandContext] non-generic dispatch context with trait-object fieldstraits— 15 per-domain subsystem-access sub-traits (MemoryAccess,GraphAccess,ModelAccess,SkillAccess,PolicyAccess,SchedulerAccess,LspAccess,SessionControlAccess,McpAccess,OrchestrationAccess,SubagentAccess,IntegrationAccess,TrackingAccess,WorktreeAccess,MiscAccess);AgentAccessis an empty marker supertrait over all 15 (blanket-impl'd) sodyn AgentAccesscall sites are unchangedhandlers— concrete handler implementations (session, debug, skill, mcp, plan, …)commands— staticCOMMANDSmetadata table used by/helptranscript— [TranscriptFormatter] / [TranscriptEntry] / [TranscriptRole], the single source of truth for rendering bounded conversation history into role-prefixed, tool-collapsed text. Both the flat-text channels (CLI, Telegram, Discord, Slack) and the TUI backfill path reuse it, so/historyrenders identically everywhere
Design
CommandRegistry<Ctx> and CommandHandler<Ctx> are non-generic over the channel type.
Handlers receive a &mut CommandContext whose fields are trait objects, so a change in
zeph-core's agent loop does not recompile this crate.
Dispatch algorithm
CommandRegistry::dispatch performs a linear scan over registered handlers and picks the
longest word-boundary match, enabling subcommand resolution without ambiguity:
/plan confirm → handler "/plan confirm" wins over "/plan"
/plan → handler "/plan" (no "/plan confirm" match)
Borrow splitting
When CommandRegistry is stored as an Agent<C> field, the dispatch site uses
std::mem::take to move the registry out temporarily, constructs a CommandContext, dispatches,
and restores the registry. This avoids borrow-checker conflicts with the channel field.
NullSink and NullAgent are zero-cost sentinels for dispatch blocks that do not need
channel I/O or agent-access commands respectively.
Authorization is fail-closed by default
CommandHandler::requires_auth() defaults to true: a handler that does not override it
requires a trusted (local) caller, and CommandRegistry::dispatch rejects it with a
CommandError when the dispatch site passes trusted = false (e.g. a remote channel such as
Telegram/Discord/Slack). Read-only or self-gated commands that are safe to expose on remote
channels must explicitly override requires_auth() to return false.
[!NOTE] This default was flipped from permissive (
false) to fail-closed (true) after repeated incidents where a new handler silently stayed reachable from untrusted channels until an audit caught it. New handlers — including thePingHandlerexample below — now require a trusted session unless they explicitly opt out.
Usage
Register and dispatch commands
use ;
// Build the registry once at agent startup.
let mut registry: = new;
// registry.register(MyHandler);
// At dispatch time, construct the context and call dispatch.
let mut sink = NullSink;
let mut agent = NullAgent;
let mut ctx = new;
// registry.dispatch(&mut ctx, "/help").await;
Implement a custom handler
use Future;
use Pin;
use ;
;
Slash categories
Commands are grouped into categories for /help output:
| Category | Commands |
|---|---|
Session |
/clear, /reset, /exit, /new, … |
Configuration |
/model, /provider, /guardrail, … |
Memory |
/memory, /graph, /compact, /guidelines, /store, … |
Skills |
/skill, /skills, /feedback, … |
Planning |
/plan, /focus, /sidequest, … |
Debugging |
/debug-dump, /log, /lsp, /status, … |
Integration |
/mcp, /image, /agent, /search, … |
Advanced |
/experiment, /policy, /scheduler, … |
Features
| Feature | Description | Default |
|---|---|---|
cocoon |
Enables the /cocoon handler (Cocoon sidecar status and model listing) |
No |
profiling |
Extra tracing instrumentation spans for dispatch latency profiling |
No |
Installation
Documentation
Full documentation: https://bug-ops.github.io/zeph/
License
Licensed under either of MIT or Apache License, Version 2.0 at your option.