description: "Human slash-command registry for interactive UIs: plugin-owned commands that run directly against an agent without creating a model message, for users and maintainers composing or extending command surfaces."
English | 中文
dsh-commands lets users run /command [input] actions in interactive Harness UIs without turning the command or its result into a model message. Commands can advertise input hints, accept attachments, and target one agent while preserving a global command with the same name for other agents. Every admitted run is recorded in the receiving agent's session log, while the UI renders the settled result outside model history. Use it for direct human controls in the dsh CLI or Web client; UI-less demos and ACP automation do not provide this command surface.
Compose this service when an interactive UI should let users drive agent-side behavior with slash commands instead of model prompts. UI-less demo spines and ACP automation provide no command adapter and do not need it.
A plugin registers a command with ctx.commands.register(): a lowercase name, a discovery description, an optional input hint, and a handler. An optional branded definitionId gives the definition a stable, plugin-namespaced identity for adapters; it is independent of display copy and execution commandId. The effective descriptor carries only the selected definition's identity, so a scoped override never inherits the shadowed registration's identity.
ctx.commands.register({
name: 'plan',
description: 'Enter plan mode',
input: { hint: '<message>' },
handler: ({ agent, rawInput }) => {
// Runs directly against the agent; no model message is created.
return { kind: 'success', text: 'plan mode selected' }
},
})
The handler returns success or error plus optional UI text that the adapter renders. recordInput defaults to true; a command whose own authoritative domain event already carries the payload sets it to false so the session log does not duplicate the input. Registering the same name twice in one scope throws.
A command line starts with a slash at byte zero, a lowercase name containing letters, digits, _ or -, and then either end-of-input or whitespace. Everything after the name — including separator whitespace — is the command's rawInput, and the command owns its own grammar for it. Lines that are not syntactically a command, or that name an unknown command, are rejected by the adapter instead of becoming a model prompt.
A plain registration is global. A command-producing plugin mounted beneath an agent's own context declares its commands injection and registers an exact agent-scoped command, which shadows the global definition of the same name for that agent only.
A command may declare input.attachments to accept composer images and generic files. The executor enforces the declaration: attachments sent to a non-declaring command, an absent attachment store, an unknown Session-scoped file-upload receipt, or an over-limit image batch each settle as an error before the handler runs. Images cross the command wire as base64 input; generic files cite receipts from their completed background uploads, so command submission never reads their bytes again. Admitted ImageBlocks and FileBlocks reach the handler as one frozen invocation.attachments array in the user's selection order, and the handler owns their model-visible use.
An interactive adapter calls execute(agent, line, attachments, signal) with the exact receiving agent, the full command line, and the submission's ordered attachments. It returns the settled CommandExecution — the normalized result plus its lifecycle commandId — or undefined for invalid syntax or an unknown name. list(agent) and find(agent, name) serve discovery after agent-scoped shadowing.
The caller's abort signal stops the registry from awaiting a handler; a handler that ignores the signal may continue its own external side effects after the caller stops waiting. A cancelled or thrown handler settles as a command/done error in the log.
Read these pages when the package-level contract is not enough. They move from the shared command vocabulary to the design evidence and adjacent surfaces.
ctx.commands Cordis surface.The registry itself submits nothing. Known slash commands execute in the UI command plane, and their CommandResult text is not submitted as a user message. Unknown slash-command input is rejected by shipped adapters instead of becoming a model prompt. A command producer may explicitly use the receiving Agent; for example, dsh-plan-mode submits the optional message and ordered attachments in /plan [message] after selecting plan mode. The executor only admits attachments into durable objects; the declaring producer decides whether and how they become model-visible message content.
Command discovery, execution, and UI output add no model tokens. Explicit agent work scheduled by a command producer has the same token effect as the corresponding agent input.
Registry metadata, command input, and direct output never enter a model request and do not affect its cache. A mutated domain owns any later cache effect.
These limits define what the registry does not offer. They are current package constraints, not a UI backlog.