Most AI coding agents are designed around a simple assumption: the machine running the agent is the machine being modified. Claude Code reads your local files and shells out to your local terminal. Aider does the same. Cursor embeds an agent directly into an editor process that is, by definition, running wherever you are. That assumption simplifies a lot of things, but it also means the agent’s execution environment is your environment, with all the entanglement that implies.
zmx, posted to Lobsters recently, challenges that assumption directly. The pitch is that you should be able to run a local agent against a remote machine, with the agent unaware of the boundary. The author frames it as an AI portal, which is a more precise description than “tunnel” or “proxy.” A portal implies that both sides see a native interface. The agent sees a local filesystem and shell. The remote machine sees well-formed requests. Neither side needs to care about the other’s implementation.
The Execution Environment Problem
Before dismissing this as over-engineering, consider the concrete failure modes of the current local-only model.
You ask an agent to refactor a service. The agent runs the test suite, reads the output, makes changes. But your laptop runs macOS and the service targets Linux. A test that passes locally fails in CI because of a subtle glibc difference. The agent never saw that failure. You’ve now generated a pull request that breaks the build, and you have to re-run the agent in a different environment anyway.
Or: you want to run multiple agents in parallel on different branches of the same project. Two agents writing to the same working tree at the same time is not a workflow that ends well. You could clone the repo twice, but then you’re managing multiple filesystem states, multiple dependency installs, and multiple editor windows.
Or: you want to audit what the agent actually did. Logs help, but an agent that ran inside your local shell is hard to fully isolate after the fact. If the agent ran in a VM that you can snapshot and inspect, the audit trail is much cleaner.
All three of these problems have the same root: the agent’s execution environment is fused with your development environment. zmx tries to unfuse them.
ZeroMQ Is the Right Transport Here
ZeroMQ has been around since 2007 and occupies a specific niche: high-performance socket patterns without a broker. Unlike RabbitMQ or Kafka, there is no central server. You link a library, pick a pattern (push/pull, pub/sub, dealer/router, request/reply), and connect sockets directly between processes.
For bridging an agent to a remote machine, the dealer/router pattern is particularly well-suited. A DEALER socket can send multiple requests without blocking on replies, so the agent can have several filesystem reads and a subprocess invocation in flight simultaneously. The ROUTER on the remote side multiplexes those into separate handlers and routes replies back to the right requestor. You get concurrency without writing your own async dispatch layer.
import zmq
# Remote side: router receives and dispatches
ctx = zmq.Context()
router = ctx.socket(zmq.ROUTER)
router.bind("tcp://*:5560")
while True:
identity, _, msg = router.recv_multipart()
request = json.loads(msg)
result = dispatch(request) # read file, run shell, etc.
router.send_multipart([identity, b"", json.dumps(result).encode()])
# Local side: dealer sends without blocking
ctx = zmq.Context()
dealer = ctx.socket(zmq.DEALER)
dealer.connect("tcp://remote-host:5560")
dealer.send_json({"op": "read", "path": "/project/src/lib.rs"})
ZeroMQ also handles reconnection transparently. If the remote machine reboots during a long agent session, the library will keep retrying until the connection restores. SSH tunnels don’t give you that for free.
For security, CurveZMQ provides mutual authentication and encryption built on the NaCl library. It is less common than TLS in recent tooling, but it fits ZeroMQ’s model well: you generate keypairs, configure them on both sides, and the library handles the handshake. No certificate authorities, no chain validation, just elliptic curve key agreement and forward secrecy.
How This Compares to What Already Exists
GitHub Codespaces and Gitpod move the entire development environment to the cloud. That solves the portability problem but changes the editing experience substantially. You’re working in a browser or through a remote SSH extension, which adds its own latency and complexity. zmx’s positioning seems to be: keep your local editing setup exactly as it is, only route the agent’s execution elsewhere.
VS Code Remote SSH is the closest analogy most developers will have used. It lets the editor’s language server and terminal run on a remote machine while the UI stays local. zmx is doing something structurally similar but for agents rather than editors, and with a purpose-built messaging layer rather than SSH’s general-purpose channel.
Claude Code’s Devcontainer support goes partway toward the same goal. You define a container image with devcontainer.json, and Claude Code runs inside it. That handles environment reproducibility but doesn’t help with running against a remote machine you already have, and it requires the container runtime to be local.
zmx seems aimed at a case none of these quite cover: you have a specific remote machine, maybe a beefy build server or a GPU node, and you want to point an agent at it without rebuilding your workflow around Codespaces or maintaining a devcontainer configuration.
What the Abstraction Enables
If the portal abstraction holds, the execution environment becomes a parameter, not a fixed property. That has downstream implications worth naming.
Agent isolation gets easier. If each agent run gets its own remote VM, you can snapshot the environment before the agent starts, let it run, and diff the result. You can also kill and restore without affecting anything local. For security-sensitive workflows, running agents in isolated VMs is good practice regardless of the transport layer.
Team-shared execution becomes possible. A team could run a single high-memory machine that multiple developers connect their agents to. The machine gets one warm dependency cache, one build cache, one set of compiled artifacts. Individual developers connect their local agents to it, each scoped to their own working directory. This is not dramatically different from how teams share CI infrastructure, except the agent is interactive.
Composability improves. An orchestration layer that can route agent requests to different machines based on the task type, send filesystem-heavy work to one node and GPU-heavy work to another, is a natural extension once the transport is a defined protocol rather than a Unix socket on localhost.
What Needs More Detail
The concept is clear, but the protocol specification matters as much as the transport choice. How are large file reads chunked? What does backpressure look like when the agent is writing faster than the remote machine can consume? How does the portal handle an agent that forks subprocesses, and does the remote machine inherit those correctly?
Latency benchmarks across a realistic WAN path would also clarify whether this is practical for everyday use or mainly suited to LAN and VPN deployments. ZeroMQ is fast, but every filesystem operation that was previously a local syscall now crosses a network boundary. For an agent doing hundreds of reads per iteration, that adds up.
The project is early and the Lobsters thread reflects that. But the direction is sensible. The assumption that an agent and its execution environment must be colocated is a historical artifact of how these tools were first built, not a technical requirement. Treating the execution environment as a configurable layer is the right move, and ZeroMQ is a credible foundation for it.