View vs control: two trust levels for a shared terminal
Every sharing tool eventually asks: can they type? Rysh answers with two explicit modes — and enforces them at the server, not in the client.
Every collaboration tool eventually hits the same question: can the other person type?
Screen-sharing tools bolt on "remote control" as an afterthought. SSH-based sharing gives everyone full control whether you like it or not — a shared tmux session doesn't have a read-only mode that anyone actually configures. And most "collaborative terminal" products pick one answer and force it on every session.
Rysh makes it a per-share decision, stated out loud at share time:
##share pane view # they can watch
##share pane control # they can watch AND type
Two modes. No third, fuzzy one. Let's talk about why this tiny keyword is doing a lot of work.
View: observation is the default posture
view is the mode you should reach for first, and the one we'd suggest for 90% of shares.
A view-mode share streams everything the pane emits — shell output, agent tool calls, results — to whoever subscribes with ##upstream subscribe <shareID>. The subscriber sees your pane's life in real time, prefixed [remote:alias] in their own terminal. What they cannot do is affect it. At all.
This maps to how most real collaboration actually works:
- A teammate reviews your agent's approach before you let it commit.
- A senior engineer keeps half an eye on a risky migration.
- Someone on another team wants to learn how you drive your agents.
None of these need a keyboard. All of these are worse over screen share, because terminal output is text and pixels destroy it — no copying an error message, no reading a long stack trace at your own pace.
Control: typing is a granted privilege
control adds one capability: the subscriber can send input into your pane.
##upstream send kubectl get pods -n payments
That command lands in your shell, on your machine, and the output streams back to both of you. It's genuine shared driving — pair-debugging where either human (and the agent) can act.
Which is exactly why it should scare you a little. Someone typing into your terminal is the highest trust grant in computing. Rysh treats it that way in three concrete ways.
1. The mode is enforced server-side, not client-side. This is the part that matters. When a command arrives at the upstream server for share X, the server's NATS proxy checks the share's registered mode before the message is routed anywhere. A view-mode share rejects inbound commands at the proxy — it's not a disabled button in the subscriber's UI, it's a message that never reaches your machine. Client-side enforcement is a politeness convention; server-side enforcement is a boundary.
2. Subscriber status is checked per message. Being able to guess a share ID gets you nothing. The proxy validates that the sender is an actual, current subscriber of that share. Unsubscribed? Your messages route nowhere.
3. Control mode has a command blocklist. Even with control granted, the proxy filters inbound commands against a configurable blocklist before forwarding. Trust, with seatbelts. (You configure this on your upstream — including the one you self-host.)
Under the hood, each share is managed by an UpstreamShareActor in your local session. In view mode, it only publishes — to ws.{workspace}.share.{shareID}.output. In control mode, it also subscribes — to ws.{workspace}.share.{shareID}.command — and routes what arrives into the local pane. The asymmetry is structural: a view share literally has no inbound path wired up on your side. Defense in depth means the "can they type?" question is answered twice — once by what the server allows, once by what your session even listens for.
The trust ladder
The pattern we use ourselves:
- Start with
view. Almost every session begins as observation. - Escalate deliberately. If watching isn't enough — the subscriber needs to run one diagnostic, poke one endpoint — stop the share and re-share as
control. The re-share is the point: escalation is an explicit act, visible in##share list, not a silent toggle. - End it.
##unshare panekills the share. Shares are session-scoped grants, not standing infrastructure.
If you've worked with capability-based security, this will feel familiar: grant the minimum, escalate explicitly, revoke cheaply. If you haven't — congratulations, you just did.
Why this matters more with agents in the pane
Here's the twist that makes two trust levels essential rather than nice: a rysh pane contains an agent.
When you share a pane, you're not just exposing your shell. You're exposing a conversation with an agent that has tools — file edits, shell execution, git. In view mode, a subscriber watches the agent work. In control mode, a subscriber can prompt it.
That's a capability worth being precise about. "Can my teammate ask my agent to do things on my machine?" should never be answered by vibes. In rysh it's answered by one word in the share command, checked by the server on every message.
The honest caveats: a shared pane streams whatever hits the scrollback — treat it like a screen share and don't share panes where secrets will appear. Shares transit an upstream rysh-server; use rysh.ai's or self-host your own (the stack is self-hostable, and agents run on Claude with your own API key). And we're early — the model is simple on purpose, because simple trust models are the ones people actually reason about correctly.
We're recruiting design partners: engineering teams who want shared, governed agent workspaces and are willing to tell us what's broken. Direct founder access, hands-on setup. rysh.ai/design-partner
Related: ##share pane: pair-debugging with a human and an agent at once · Multi-tenant NATS isolation: how workspaces stay out of each other's business