git. The usual answer is a sandbox, a container or microVM for each agent.
A sandbox reserves memory for every agent, takes time to start and needs a
service to manage it.
Most of what an agent runs does not need a machine. It reads files, calls
services and pipes text from one command to the next. A lightweight terminal
runs that work inside the server you already have. Each terminal is a Mirage
session with its own working directory, environment and history, and
Monty runs Python in-process. One server process
holds many terminals on its event loop.
A command that needs more, such as
numpy or a GPU, can still go to a machine:
Runtime Routing sends only those commands
there.
What an agent can run
The files they work on live in a virtual filesystem (VFS). Each source of
files, such as memory, an S3 bucket or Google Drive, is a
VFS mounted under its own path, and a server can mount
several side by side:
This page mounts memory at
/work, which needs no account.
Installation
- FastAPI
- Express
Server
One endpoint creates a terminal, another runs a command in it.- FastAPI
- Express
app.py
Usage
45. A later call to session a starts in /work, where the
cd left it.
The examples below send several lines in one request. This shell function
reads the lines from standard input, sends them to session a as the
command, and prints what they print, errors included. It needs
jq:
SH and SH run in the terminal on the server, not in
the shell that calls run.
Terminals per server
A sandbox is a machine, so it reserves memory for its agent whether the agent is working or waiting. A terminal is not a machine. It is a record in your server’s memory: a working directory, variables and a history. Each square is 128 MB, the least that the sandbox services linked above reserve for one agent. The server is drawn at the same scale, four squares for 512 MB, and then enlarged to show its terminals and its memory. Mirage and its runtime take about 100 MB of it. An idle terminal adds about 20 KB, plus any files it keeps in a memory mount. A busy terminal adds what its command holds: files, a cache, the data in its pipes. Move the slider to add agents, and choose how many are busy and how much each holds. What a terminal costs depends on what it is doing:- Idle terminals are nearly free. An idle terminal has no process or thread of its own, only a record of about 20 KB on Python and on TypeScript. One server holds thousands of them, so an agent can keep its terminal between turns.
- Terminals waiting on a service run at once. A command that waits for a reply uses no CPU while it waits, and the server runs other terminals’ commands in the meantime. See Async.
- Terminals working on data share the CPU. Commands such as
sortandgreptake turns on it, so each takes longer as more run together. A command that needs a core to itself belongs on a machine: see Runtime Routing.
Async
ws.shell is a coroutine in Python and a promise in TypeScript, and it never
blocks the event loop. The handlers above are async, so while one terminal
waits on a file read, a runtime or a slow command, the server keeps serving
every other terminal, with no thread or process per terminal.
- Python
- TypeScript
sleep 1 commands on session a take three seconds.
Sharing and security
- By default, terminals share the workspace’s mounts, so a file one writes
under
/workis visible to the others. - A session profile and a policy decide which commands a terminal may run and which files it sees, so each agent can have a folder the others cannot see. Policy & Security walks through one. To keep everything apart, give an agent its own workspace.
Use cases
Each page adds a few lines to this server and shows what an agent does with the terminal.Code Review
Review a pull request and a dependency bump with
gh, git, a GitHub
mount and an MCP server.Co-Work
Schedule candidate interviews from an inbox, a calendar and Slack.
Release Notes
Turn a week of merged work into release notes.