Giving an AI agent a shell is easy. Giving it a computer it can actually work with is a different problem.
When we started building WBX Sandbox, the idea was simple: give AI agents a real Linux environment where they can execute code safely. A shell, a filesystem, network access when needed, and a way to get results back.
We quickly discovered that running code was the easy part. The difficult questions came later:
- What happens when a task runs for 40 minutes?
- What if the AI disconnects halfway through?
- What happens when a test suite produces 100,000 lines of logs?
- How does an agent continue working on the same project tomorrow?
- How do you know what actually ran?
Most of what we built since then came from getting those wrong first. Today, WBX runs isolated Linux microVMs using Firecracker on our own infrastructure in the EU. Agents can access them through MCP, REST, a Python SDK, or a LangChain integration.
Here are ten things we learned along the way, including a few mistakes.
1. A remote shell is not an execution platform
Our first requirement was straightforward: an AI agent should be able to run real code. Not simulated code execution, not a restricted expression evaluator, but an actual Linux environment.
Every WBX sandbox runs in an isolated Firecracker microVM with its own kernel, filesystem, and network configuration. The agent can install packages, run tests, automate a browser, or launch a server and expose it on a public HTTPS URL.
Early on, every task started from an empty machine, and agents spent a lot of time just installing things. So we added ready-to-use templates for Python, Node.js, Go, Rust, browser automation, and other common workloads. We also use warm pools, snapshots, and verified dependency caches to reduce setup overhead.
Lesson: Isolation matters, but developer experience starts with how quickly useful work can begin.
2. Long-running tasks should not depend on an open connection
Imagine asking an agent to run a large test suite that takes 25 minutes. If the work is tied to one MCP tool request, a timeout or disconnected client becomes a serious problem.
We first tied everything to the tool request and kept hitting timeouts. The fix was to separate interactive execution from background jobs. For quick commands, the agent uses tools such as run_command. For longer work, it uses run_job.
AI Agent | | run_job(...) v WBX Sandbox | | Returns job_id immediately v Agent continues working Meanwhile: Job runs independently | v Logs + artifacts + execution receipt The job keeps running after the client disconnects, and the agent can return later and retrieve the results.
Lesson: The lifetime of a computation should not depend on the lifetime of a chat connection.
3. Don't make an AI agent poll every few seconds
One of the less obvious problems we encountered was polling. An agent starts a background job and then repeatedly asks:
Is it finished? Is it finished? Is it finished? Every call consumes tool overhead, context, and time. Instead, we implemented wait_jobs: the server waits for a job or batch to finish, or until a specified timeout, and the agent receives a result when something meaningful happens.
We also added get_job_summary, which returns a compact overview instead of forcing the model to read every detail, and list_jobs, so an agent can find earlier jobs and batches without having to remember their IDs.
Lesson: Move waiting and state management into the platform. Don't make the language model do repetitive coordination work.
4. Raw logs are terrible for AI context windows
Developers are used to scrolling through thousands of log lines. AI agents don't have that luxury. A large build or failing test suite can generate megabytes of output, and if you send everything back to the model, you're spending context on information that may not matter.
So we built log summaries that recognize common test frameworks, extract error messages with their surrounding context, and preserve the end of the log. The original logs remain available when deeper inspection is necessary.
A similar principle applies to datasets. In one experiment, we processed a CSV file containing 100,000 orders. Measured with common tokenizers:
- Full CSV: approximately 790,000 tokens.
- JSON summary: 55 tokens.
It's one experiment, not a general benchmark, but it shows why keeping data processing outside the context window matters.
Lesson: Return the information the agent needs, not every byte the computer produced.
5. Not every task needs a virtual machine
A microVM is the right tool when an agent needs a full Linux system. But many tasks are small, self-contained computations: parse a file, transform data, run a function.
For those we added a WebAssembly (WASI) runtime. Modules run without starting a VM, as unprivileged processes with no network, and see only /input, /output, and /tmp. They start almost instantly and have strict memory and time limits.
The agent uses the same job interface for both, so it doesn't have to learn a second system.
Lesson: Match the isolation to the task. A lighter sandbox for small work keeps the heavy one available for real environments.
6. Parallelism needs orchestration, not just more machines
AI workflows often involve independent tasks: testing different configurations, processing multiple datasets, running build matrices, evaluating several implementations.
We added run_batch to handle up to 1,000 jobs with configurable concurrency. Jobs can depend on one another and pass result files to downstream tasks.
As a sanity check we started 65 sandboxes across nine templates at the same time and let each run a five-minute task. All of them finished. It was a test of concurrency and lifecycle handling with mostly idle processes, not a performance benchmark.
Lesson: Good orchestration lets agents work in parallel without making the model manually coordinate every machine.
7. Never silently downgrade what the user requested
Suppose an agent requests an IPv6-only environment, or a higher-performance compute class. If the platform cannot provide it, quietly substituting something else is dangerous. The task might still run, but its results may no longer mean what the developer expects.
We decided that requested capabilities must be explicit. If the right environment is unavailable, the request waits or fails clearly.
WBX supports IPv4, dual-stack, and IPv6-only networking, and IPv6 sandboxes get their own public address for outgoing traffic. Incoming connections from the internet are closed for now; web apps get an HTTPS URL instead. In a live connectivity test, we verified public IPv6 allocation, IPv6 routing, successful ICMP ping and HTTPS requests. We also confirmed that ordinary IPv4 outbound connections were blocked in the IPv6-only mode.
Lesson: A clear failure is better than a successful execution in the wrong environment.
8. Agents need environments that survive conversations
A fresh sandbox is useful for a one-off task. It is much less useful when an agent is building a project over several days. Imagine spending hours installing dependencies, creating files, and configuring a development environment, and then the chat ends. Starting from zero next time is frustrating.
We added sandbox sleeping to preserve the disk while the VM is not running, and named sandboxes allow a later conversation to locate the same environment. We also built archive storage, so sleeping disks are moved to dedicated storage nodes and restored later on any compute node.
This introduced difficult engineering questions around crash recovery, metadata consistency, replication, and disk failure. Preserving files isn't just about successfully writing them once. It's about being able to recover them when something goes wrong.
Lesson: Persistence changes the reliability expectations of an execution platform. Treat user data as something you must protect, not disposable temporary output.
9. Execution results should be verifiable
An AI assistant might say: "I ran the tests. Everything passed." But how can the user verify that?
We added execution receipts. A completed job records information such as its runtime, exit code, resource usage, network policy, and output file hashes. It's an audit record, not a cryptographic attestation, but it provides a concrete record of execution independent of the assistant's summary.
Lesson: Agents should be able to show evidence of completed work, not just describe what they believe happened.
10. MCP tools are APIs whose primary user may be a model
This took us the longest to understand. When you're building a normal developer API, you write documentation for a person. When you're building an MCP server, the model itself often decides which tool to call. That makes tool descriptions part of the actual user experience.
We learned to explain:
- When to use
run_commandversusrun_job. - When to request a summary instead of raw logs.
- When a call is destructive.
- What happens if the operation is unavailable.
We also added MCP tool annotations such as readOnlyHint, destructiveHint, and openWorldHint. Better descriptions help models choose the right operation without repeatedly exploring the API.
Lesson: When AI models use your API, good tool descriptions become operational infrastructure.
What we'd do differently
If we were starting again, we'd prioritize these things much earlier:
- Asynchronous execution. Don't design long-running work around a blocking HTTP request.
- Compact results. Return summaries by default while keeping the original logs available.
- Crash recovery. Design persistence and background job recovery as first-class problems.
- Tool descriptions. Test MCP descriptions as carefully as the underlying API.
We also learned that the difficult bugs are rarely in the happy path. They're in the moments when a node disappears, a response gets lost, a disk runs out of space, or a process crashes between two writes. Those are the moments that determine whether an execution platform can be trusted.
Final thoughts
AI agents are becoming capable software operators, and the more capable they become, the more they need dependable infrastructure around them. Not just a shell, but isolation, background execution, persistent files, useful logs, explicit capabilities, and evidence of completed work.
That's what we're trying to get right with WBX Sandbox, and we're still learning.
If you're building infrastructure for AI agents, I'd really like to hear how you handle long-running tasks and persistent execution environments.
Project: https://sandbox.wbx.cz
MCP endpoint: https://sandbox.wbx.cz/mcp
Disclosure: I'm building WBX Sandbox. This post shares engineering lessons from developing the platform, including features and failure scenarios we've been working through.

