Readable from afar: what remote observers see while you're in vim
You're in vim, htop, or a full-screen TUI. Your pane's remote observers still get readable text — not ANSI soup. Here's how.
Here's a problem you've never thought about until the moment it ruins your demo.
You're sharing your terminal with a teammate — live stream, not screen share. It's going great: they see your commands, your agent's tool calls, your test output. Clean, readable text in their own terminal.
Then you open vim.
In most naive terminal-sharing schemes, your observer's feed now becomes this:
^[[2J^[[H^[[?1049h^[[1;24r^[[?12h^[[?25h^[[27m^[[23m^[[29m...
Raw ANSI escape soup. Cursor jumps, screen clears, alternate-buffer switches — instructions meant for a terminal emulator, not for a human reading a stream. Forward those bytes verbatim and the observer gets garbage; strip everything naively and they often get nothing at all. Either way, the share goes dark exactly when something interesting is happening.
Why full-screen apps break streams
Regular shell output is append-only text — a natural fit for streaming, since watching it is just reading a log.
Full-screen programs — vim, htop, less, nano — work differently. They switch the terminal to the alternate screen buffer and start painting: jump the cursor to row 12 column 40, redraw this cell, clear that region. The "output" stops being a stream of lines and becomes a stream of edits to a 2D grid. Meaningful only if you maintain the grid.
Your local terminal maintains that grid. A remote observer's pane, fed someone else's raw bytes, does not — the escape sequences would collide with everything else in their terminal.
What rysh does: emulate locally, stream readable text
Rysh handles this because each pane already contains a real terminal emulator.
Every pane's PTY output feeds a virtual terminal emulator (built on vt10x) that maintains the actual 2D screen state. That's how rysh supports interactive programs in the first place: when the emulator detects the alternate-screen switch, the pane automatically enters raw mode, and your local view renders the emulator's screen — so vim looks and behaves like vim, keystroke for keystroke. (Yes, you can run vim inside an agentic multiplexer. Ctrl+O is your escape hatch.)
The shared-output path is deliberately separate from that rendering path. What goes out to observers is ANSI-stripped, readable text — and that keeps flowing even while you're in raw mode. The escape sequences that only make sense to an emulator get consumed by your emulator; the shared stream carries content, not control codes.
So while you're inside vim, your observer's pane shows readable text tagged [remote:alias] — not a byte-perfect replica of your editor, and not ^[[?1049h garbage either. When you quit back to the shell, the stream continues seamlessly: same pane, same share, no re-subscription, no gap. And your agent's output rides alongside unaffected throughout, because in rysh a pane's shell stream and agent stream are separate NATS topics forwarded through the same share.
An observation stream, not a remote desktop
This is a deliberate design position, so let's state it plainly.
When you share a rysh pane, observers get an observation stream: everything that happens — commands, output, agent tool calls, results — as text they can read, scroll, and copy in their own terminal, with their own font and colors. They do not get a pixel-faithful mirror of your full-screen editor UI.
Why we like this trade:
- Text over pixels. For terminal work, content-as-text beats content-as-video in every way that matters: copyable, greppable, readable at any window size, and a fraction of the bandwidth.
- Observation is the actual use case. People subscribe to a pane to follow an investigation or watch an agent work — an activity log, not a request to operate your vim splits by proxy.
- Graceful, not brittle. The worst version of terminal sharing is the one that randomly degrades into escape-code noise. Never showing garbage is worth occasionally showing less than everything.
If what you truly need is full co-editing fidelity, share your screen — that tool exists and is fine. The rysh share solves the thing screen sharing is bad at: making terminal + agent activity legible to remote teammates, continuously, cheaply.
The plumbing, briefly
For the architecture-curious: the PTY read loop feeds raw bytes to the pane's vt10x emulator (that's the local rendering truth). The pane's output stream — the readable text — is published to per-pane NATS subjects. When the pane is shared, an actor forwards that stream to the upstream server on a workspace-scoped subject (ws.{workspace}.share.{shareID}.output), where subscribers' sessions pick it up and print it with the remote prefix. The upstream's proxy enforces subscriber checks and share mode the whole time — view-mode observers stay observers even mid-vim.
The design rule underneath: the local view and the shared view are different renderings of the same pane, each built for its consumer. Your rendering is a live grid, because you're operating the program. Theirs is readable text, because they're following the work.
Honest edges: "readable text during full-screen apps" means exactly that — an htop observer sees textual output, not the live dashboard repainting; some heavily cursor-driven interactions summarize poorly by nature. Standard share hygiene applies (scrollback goes to subscribers — don't open secrets in a shared pane). And this rides the usual rysh stack: upstream hosted or self-hosted on your infra, agents on Claude with your own key.
Small feature, disproportionate payoff: shares survive your workflow. You don't plan your editor usage around who's watching — you just work, and it stays legible from afar.
We're looking for design partners — teams who'll share real panes, hit real edges, and tell us which ones hurt. Hands-on onboarding, direct line to the founders: rysh.ai/design-partner
Related: ##upstream subscribe: watch a teammate's agent work from your own terminal · Yes, you can run vim inside an agentic multiplexer