Rexec: How to Safely Give AI Agents a Terminal
How to safely give AI agents a terminal - using Rexec.
Agents still get a terminal. It just shouldn’t be your workstation.
They need to run commands - that’s the product. The shortcut everyone takes is running those commands as you on a laptop, bastion, or shared runner, held together by system prompts and “approve tool use.”
This is not “harden your personal shell for AI.”
It’s give the agent its own disposable terminal - isolated, capped, networked on purpose, then deleted. That’s what Rexec is for (cloud sandboxes or BYOS).
TL;DR: Isolation + lifecycle. How Rexec reasons about security, enforces limits, controls network access, what the pieces are, and what happens when you send a request. The checklist still applies if you wire your own stack.
Talk deck: Rexec: How to Safely Give AI Agents a Terminal (SysConf 2026)
Goals - what this talk covers
How to safely give AI agents a terminal using Rexec - and the controls that still matter if you wire your own stack:
- The problem - agent exec on your workstation, not a sandbox terminal
- Security & limits - what walls that terminal gets; CPU / memory / TTL
- Reach & disposal - what the terminal can talk to, and when it dies
- Rexec build - components, then request dataflow
- Practice - create → prove → delete
Rexec is the through-line. The controls travel without it.
Content - the problem
Useful agents shell out. You’re doing untrusted remote code execution with a friendly UI.
What breaks without a jailbreak:
- Secrets land on disk
- Creative
rm/ path expansion - Env leaves over HTTPS or DNS
- Packages phone home
~/.kubeand other prod creds sit next to the agent
Models thrash. Hope is not a control.
Give the agent its own disposable terminal. That’s what Rexec is for.
Disposable terminal. Now make the walls real.
Content - what walls does that terminal get?
Before Docker I ran Proxmox at home - one VM per agent. Heat, maxed box, nowhere to scale. That dead end is why Rexec exists.
Two approaches when I built it: shared host with runtime + kernel protection, or VM / node per agent when the threat model pays for a harder boundary. A delete button is not a boundary - pick a path, then a rung, then hard-cap it.
Isolation ladder
- cgroup + caps + network - baseline on any shared host
- gVisor (
runsc= its OCI runtime; user-space kernel between container and host) - shared-host default - Firecracker / microVM - when one sandbox must not share fate with the next
- Dedicated node / account - real budget, not cosplay
Default Docker (runc) shares the host kernel - say so if that’s all you’re using.
Limits: hard CPU / memory / PIDs; concurrency + TTL (kill on a timer) on both paths. Thrash is a DoS on yourself. Limits = security, not just FinOps.
Trade-off in Rexec: Proxmox taught density. Needed density on shared hosts, including hosts without KVM → gVisor default. Pay syscall/compat tax. Escalate to Firecracker / a node when the threat model says so.
Content - what the terminal can reach, and when it dies
Shared host or VM-per-agent - neither is safe if the shell can phone home forever.
Network: a shell is a network endpoint. Pick at create: none · allowlist · full (you accepted the leak). ICC (inter-container communication on a Docker bridge) off only stops sandbox-to-sandbox on that bridge - not “no internet.”
Lifecycle: create → short-lived secrets → run → attach if needed → delete. Long-lived sandboxes become bastions with worse accountability (Proxmox pets included).
Content - Rexec pieces (one line each)
| Piece | Job |
|---|---|
| Browser / CLI | Where humans and agents attach (xterm.js, API clients). |
| Rexec API | Auth, policy, create / exec / delete, WebSocket sessions. |
| PostgreSQL | Users, agents, session metadata. |
| Container Manager | Talks to Docker for disposable cloud sandboxes (limits, network, runtime). |
| Docker Engine | Where cloud sandboxes actually run. |
| Agent Handler | Relays sessions to machines you connect. |
| BYOS agent | Outbound WebSocket from your laptop/server; no inbound SSH. |
BYOS = bring your own server. Mediated access, not a jail.
Content - what happens when you send a request
Input (create / exec)
│
▼
Rexec API ──persist──► PostgreSQL
│
├── Container Manager ──► Docker Engine (cloud sandbox)
└── Agent Handler ──outbound WS──► BYOS agent
│
▼
Output stream ──► UI / agent
One request in. Routed. Persisted. Executed. Streamed back.
Self-host sketch:
git clone https://github.com/PipeOpsHQ/Rexec.git
cd Rexec/docker
docker compose up --build
# UI/API on localhost:8080 - change default admin credentials immediately
Docs: rexec.sh/docs
Failures I’ve hit: Docker socket in the sandbox; full egress by default; no TTL/concurrency; prompt as the boundary; gVisor in the README and runc in prod.
Conclusion
Build the agent a terminal. Don’t share the one you live in.
- Secrets and prod never meet an agent on your laptop
- One sandbox per task. Then delete it
- Untrusted agent code → gVisor or stronger
- Egress is a decision. DNS is data
- Hard caps + TTL. Outbound agents, not inbound SSH
No Rexec? Same controls with Kubernetes Jobs + RuntimeClass + NetworkPolicy.
Resources
This talk
- Talk deck: Rexec: How to Safely Give AI Agents a Terminal (SysConf 2026)
- Rexec: github.com/PipeOpsHQ/Rexec
- Docs: rexec.sh/docs
- Related: Rexec control room · Namespaces aren’t isolation · Work
Isolation & runtimes
- gVisor: gvisor.dev · github.com/google/gvisor
- Firecracker: firecracker-microvm.github.io · github.com/firecracker-microvm/firecracker
- runc: github.com/opencontainers/runc
- cgroup v2: kernel docs
- Linux capabilities: capabilities(7)
Platform building blocks
- Docker: docs.docker.com
- PostgreSQL: postgresql.org/docs
- Kubernetes Jobs: docs
- RuntimeClass: docs
- NetworkPolicy: docs
Share
Newsletter
Platform engineering, multi-tenant isolation, and cloud-native security. No fluff.
Comments