Any Cables #34: CLI-over-WebSocket
March-April 2026
AI agents love CLIs, so CLIs are having a moment. We built one for our managed AnyCable+, and the interesting part isn’t the CLI, it’s that we didn’t really build one. It’s a thin WebSocket client pointing at our web app.
Also inside: lighter memory footprint, better docs and a new use case for AnyCable.
Highlights
AnyCable documentation makeover
We’ve migrated our documentation website to VitePress. Now we have modern UI, better search, and LLM-friendliness (/llms.txt and .md versions). This is the first step towards the upgrade of the documentation itself. Stay tuned!
Posts
Web slides are web apps: live interactivity for Reveal.js and Slidev
This post introduces a new side project by Team AnyCable—slide-quiz. It’s a plugin for JS-powered presentation software (Reveal.js and Slidev) for embedding interactive quizzes or surveys into slide decks. It’s powered by AnyCable (obviously) and is designed to work with our free PaaS offering, AnyCable+.
Lies I was Told About Collaborative Editing, Part 2: Why we don’t use Yjs
Yjs is a regular guest on our newsletter. This time, however, the perspective is quite new: the post by Moment engineers discusses the downsides of using Yjs and shares an alternative approach to collaborative editing.
Releases
This project contains a reverse-engineered Kiwi protocol—the one that powers Figma. The protocol itself is not as complex—just three message types for transferring the scene state and updates. One of the most interesting insights from this project is the usage of Kaitai Struct to describe and compile parsers for binary formats.
This release reduced AnyCable memory footprint and improved handling of large broadcast messages. Here is an example chart from one of our users: 🔥. Time to upgrade!
We upgraded the installation generator (bin/rails g anycable:setup) to be more suitable for Rails 8 applications with Import Maps and Hotwire. Now, a single command should be enough to configure both the server and the client and use reliable streams by default.
Frame of curiosity: CLI-over-WebSocket
Command-line interfaces are getting hot (again). AI agents seem to love them. Everyone’s building a CLI for their product. The world is being terminalized.
We also jumped on that train and released a CLI for AnyCable+:
# Install AnyCable+
curl -LSs https://anycable-plus.terminalwire.sh | bash
# Restart shell, then authenticate the CLI
anycable-plus login
# Create a cable
anycable-plus cable create my-app --public --waitThe flow is pretty common: install via cURL, authenticate (it opens a browser and lets you login via GitHub), and create a cable (optionally waiting for it to finish the provisioning). What’s more interesting is how it works inside.
It took us just a handful of hours to implement the CLI. And no, it’s not because we burnt millions of tokens running dozens of agents in parallel. The trick was the architecture: we didn’t write a CLI, we wrote a CLI interface within the web app.
We used the technology called Terminalwire. The CLI commands live in your web app defined in your backend framework’s native way. For example, in Ruby on Rails, you use Thor to declare commands, options, and stream data to the output device. A CLI connects to your web app via WebSockets and acts as a thin client between the user and your service: commands are handled by the server, the output is streamed to the user over sockets. We don’t even need to build a CLI: a universal Terminalwire CLI can be used (all it needs is a URL of the CLI WebSocket interface).
This technique, CLI-over-WebSockets, has a lot of advantages:
No need to write and maintain a separate project
No need to create an API for a CLI (or adjust the existing one to better reflect the terminal needs)
No need to upgrade CLIs with every change (the CLI schema lives on the server)
There are some trade-offs, of course. Every command requires calling a server, so local commands are impossible. When using Terminalwire, for example, calling --help requires network connectivity and the response is not immediate (like you might expect). Fancy TUI can also be tricky to implement with thin clients.
The final concern is infrastructure. Although CLI commands are typically short-lived (unless there is a need for user input), the number of concurrent WebSocket connections and messages passing in and out can become significant and would require either performance optimizations or separation of web and CLI workloads (so they do not interfere). Sounds like an “AnyCable for CLI-over-WebSocket” idea, right?
What do you think about the CLI-over-WebSocket approach? Would you use it to implement a CLI for your service? Reply to this email to chat with us.





