HomeBlog › The `##` command language: a tiny shell for driving your whole workspace
Blog

The `##` command language: a tiny shell for driving your whole workspace

Jul 19, 20265 min readBy the Rysh team

Menus don't compose and agents can't click them. Every rysh capability — panes, sessions, sharing, agents — is a typed ## command on the input line.

Every power tool eventually faces the same interface decision: menus or language?

Menus are discoverable and dead-ended — you can click them, but you can't script them, compose them, or hand them to an automation. Languages are the opposite: a learning curve that pays compound interest.

Terminals settled this argument decades ago. So when we built rysh, the multiplexer itself got a language too. It's spelled ##.

One prefix, the whole platform

In any rysh pane, a line starting with ## doesn't go to your shell and doesn't go to the AI — it's a system command, interpreted by the workspace itself. The family tree:

##help                      # discover everything below
##tab …                     # tab operations
##pane …                    # pane operations (name, listen, unlisten, …)
##panegroup … / ##pg …      # pane-group operations
##public / ##private        # control what leaves this pane
##snap                      # workspace snapshot
##session …                 # session management
##share … / ##unshare …     # collaboration
##upstream …                # remote shares
##raw                       # toggle raw terminal mode
##agent …                   # autonomous agents
##humanoid …                # agents on external channels

Same input line as your shell commands and your prompts. Double-Escape flips who you're talking to (shell vs AI); ## addresses the room itself.

A guided tour in six commands

Name things. ##pane name builder gives the active pane a given-name (unique per lane; Ctrl+P r does the same interactively). Names matter because everything else takes them as arguments.

Wire panes together. ##pane listen builder subscribes your pane to the builder pane's redacted output stream; ##pane unlisten disconnects. This one command is the foundation of cross-pane observation and pipeline events.

Manage sessions without leaving your seat.

##session            # info about this session
##session list       # all sessions, current marked >
##session switch qa  # ensure qa's daemon runs (spawn if stopped)
##session reload     # flush workspace state to KV now

These run daemon-side through the session registry — which is why they behave identically in the CLI and the desktop app. The UI is just the messenger.

Share your work, precisely.

##share pane view      # remote collaborators can watch this pane
##share pane control   # …or drive it
##share tab            # share a whole tab; ##share panegroup works too
##share list           # what am I sharing?
##share status         # upstream connection health
##unshare pane         # stop

Subscribe to someone else's.

##upstream shares            # what's available on the upstream server
##upstream subscribe <id>    # watch a remote share from a local pane
##upstream send "make test"  # send input (control-mode shares only)
##upstream unsubscribe

Set your privacy boundary. ##private routes subsequent output to a private buffer that never reaches any shared stream; ##public reopens the tap. Redaction is automatic; this is the manual override.

Beyond commands, two more prefixes complete the input grammar: @agent-name <prompt> addresses an autonomous agent by name, @@agent-name stop|activate|deactivate controls one, and ##> lines are pipeline events — signals other panes react to. The ##agent and ##humanoid families (spawning agents from markdown skill files, wiring them to Slack/email/website chat) are deep enough to deserve their own articles.

Why a language beats a settings panel

1. It composes with everything that speaks text. The killer consequence: rysh send delivers input to a pane in a running or detached session — including ## commands:

rysh send myproject "##share pane view" --mode shell
rysh send myproject "##session reload"

Your multiplexer's controls just became scriptable from cron, CI, SSH, anything. A menu can't do that.

2. Agents can drive the room too. Rysh agents have workspace-aware tools — inspecting panes, sending input to other panes, listing agents. The ## language means the workspace's capabilities are expressible in the medium agents already work in: text. An agent that can be told "share your pane when you're done" lives in a different universe from one whose environment is controlled by mouse-only chrome.

3. One path, no drift. Every ## command is parsed and routed through the same actor pipeline as everything else — published to the workspace inbox as a typed message, dispatched to the owning actor (workspace, tab, pane), executed sequentially in its mailbox. Command output comes back on its own dedicated stream (.output.rysh — one of the pane's four output streams), so system chatter never pollutes your shell/AI transcript. There is no privileged UI backdoor that behaves differently from the language. The language is the interface.

Keybindings for the hands, language for the system

To be clear: rysh is not keyboard-hostile. Ctrl+P/Ctrl+T/Ctrl+S/Ctrl+L modes handle the split-rotate-resize choreography your hands do a hundred times a day — spatial actions belong on keys.

The division of labor is deliberate: keybindings for reflexes, ## for semantics. Splitting a pane is a reflex. "Subscribe this pane to that one's output, redacted" is a sentence — and sentences deserve a grammar, not a chord.

Learn six commands and the multiplexer stops being an app you operate and becomes a system you address — and so can your scripts, and so can your agents. That's the point of a command language: everyone who speaks text gets to be a power user, including the colleagues you spawned from a markdown file.


Rysh is early. Want to help decide what the language grows next? Become a design partner: rysh.ai/design-partner

Related: rysh send: headless control · ##pane listen

Try Rysh

Every pane is a shell and an AI agent — install takes one command.

Get started free →