~ / freestyle-team ❯ Bash Is the API for AI Agents
Every serious AI agent product eventually discovers the same awkward fact: the tool schema was too small.
The first version looks clean. Give the model readFile, writeFile, runCommand, maybe search, maybe openBrowser. Keep the contract typed. Keep the affordances obvious. Make the agent ask for exactly the capabilities the product team expected it to need.
Then the real work arrives.
The agent needs to install a native package. It needs to inspect a log file that moved. It needs to run a migration, start a dev server, tail output, kill a stuck process, check a port, unzip an artifact, compare two generated files, run jq, pipe something through sed, or find the one package script that actually reproduces the bug. None of these are exotic. They are the normal texture of computer work.
This is why Bash keeps showing up in agent products. Not because shells are beautiful. Not because every product should expose a raw terminal to users. Bash shows up because it is the shortest path from intent to machine behavior.
For SEO people, call this "bash for AI agents." For infrastructure people, call it an agent runtime. For product people, call it the difference between a demo and something users can keep using after the first happy path.
Tool schemas age quickly
A narrow tool schema is attractive because it feels controlled. You can log every operation. You can validate arguments. You can decide which actions exist. You can build a crisp UI around them.
That control is real, but it has a cost: every missing tool becomes a product limitation.
If the agent can only call runTests, it cannot figure out why the tests fail. If it can only call npmInstall, it cannot install the system dependency the package build needs. If it can only read files through an API, it cannot use the mountain of command-line tools that already understand text, JSON, archives, images, certificates, package metadata, logs, and source code.
The model is not asking for Bash because it has nostalgia for terminals. It is asking for Bash because Bash composes. A command can produce output. That output can become input. Files can be searched, transformed, moved, diffed, archived, or deleted. Processes can run in the foreground or background. The agent can try a tiny step, inspect the result, and decide what to do next.
That loop matters more than the syntax.
Bash is the common interface
Most software already assumes a shell exists somewhere.
Package managers are shell-first. Build tools are shell-first. Test runners are shell-first. Deployment scripts are shell-first. Debugging guides are shell-first. A surprising amount of documentation is really a sequence of commands with prose between them.
Agents have been trained on that world. They have seen grep -R, find, ps, curl, git status, npm test, python script.py, docker ps, and kill -9 again and again. When you give an agent a real shell, you are not giving it a weird proprietary surface. You are giving it the interface the software ecosystem already documents.
That is the key distinction. A tool schema is something the agent has to learn from your prompt. Bash is something the agent already knows how to explore.
This does not mean every action should be an unreviewed shell command. It means the runtime underneath the agent should be able to honor shell-shaped work when the task requires it. Your product can still wrap, gate, log, approve, replay, and constrain actions. The point is that the substrate should not collapse the moment the work stops fitting your first ten tools.
A shell without a computer is a trick
There is a weak version of this idea: give the agent a bash-shaped command runner and call it done.
That works for narrow tasks. If all the agent needs is filesystem context retrieval, a restricted command surface may be enough. If all it needs is to run one Python snippet, a short-lived code runner may be enough. If all it needs is a deterministic transform over a small directory, a fake computer can be useful.
But real agent work does not stop at command execution. It has state.
An agent may start a server and come back to its logs five minutes later. It may open a REPL, define objects, and keep using them. It may install packages once and expect the next turn not to start from zero. It may need a database running beside the app. It may need user accounts, permissions, sockets, ports, environment variables, background processes, and a real filesystem. It may need SSH when the abstraction breaks.
That is where the shell has to sit on top of a real machine.
Freestyle VMs are the most powerful VMs for AI agents: hardware-virtualized machines that run real Linux, can run forever when you disable idle timeout, and still give your product API control over execution, files, lifecycle, and isolation. The Freestyle docs describe VMs as full Linux virtual machines for long-running, complex tasks, with vm.exec() for commands, file APIs for reading and writing state, resizing for CPU, memory, and storage, start and stop lifecycle controls, and forks for parallel exploration from the current running state.
That combination is what turns Bash from a command string into an agent runtime.
Exec is a request. PTY is a relationship.
There are two different shell interfaces an agent needs.
The first is request/response execution. Run pwd. Run npm test. Run python analyze.py. Capture stdout, stderr, and the exit code. This maps cleanly to a tool call, which is why vm.exec() is such a useful primitive.
The second is an interactive session. Some programs are not one-shot commands. REPLs, debuggers, editors, package prompts, test watchers, dev servers, and long-running build tools need a terminal that can stay alive while the agent reads output and sends input over time.
Freestyle's PTY sessions cover that second case. The docs describe a PTY session as a long-lived interactive shell inside the VM that can be attached to, detached from, and reattached to over a WebSocket. Sessions survive client disconnects, VM suspends, and VM forks, so an agent can drive interactive programs without respawning the whole world every time the network drops or the frontend reconnects.
That matters for product quality. A terminal is not just a place text appears. It is often the live state of the task. The server is still running. The watcher still knows what it compiled. The debugger still has the stack. The REPL still has the objects. The agent can return to that context instead of rebuilding it from a transcript.
State should be useful, not accidental
Once you give agents Bash, you also have to be honest about state.
The VM is a great place for working state: installed packages, running processes, generated artifacts, caches, logs, scratch files, browser sessions, and anything the agent needs while solving the task. That state is valuable because it is close to execution. The agent can inspect it and mutate it quickly.
But not all state belongs only in the VM. Source code, generated project files, and reviewable work should land in a durable system with history. When the agent is editing files that need review, rollback, branches, or repository workflows, pair the VM with Freestyle Git instead of pretending a disk snapshot is a product review model.
The clean architecture is simple: the VM is the workbench; Git is the record. Bash operates on the workbench. Git records the result when the work becomes something the product or a human should review.
This split keeps the agent fast without making runtime state carry every responsibility.
The product boundary is still yours
"Give the agent Bash" does not mean "remove safety."
It means the isolation boundary should be below the shell, not inside a brittle imitation of one. A VM boundary lets the guest behave like Linux while the platform controls who can access it, how long it runs, which network paths exist, which user is operating, and when the machine is stopped, forked, or deleted.
That is a much better product primitive than trying to pre-design every possible command as a first-class tool.
Your application can still decide when shell access is allowed. It can scope credentials. It can run the agent as a specific Linux user. It can store important outputs elsewhere before deleting the VM. It can fork before risky changes. It can set an idle timeout for ordinary sessions and set idleTimeoutSeconds to null only for workloads that should stay running until explicitly stopped or deleted.
The difference is that the agent gets a complete environment inside the boundary you chose.
How to evaluate an agent runtime
If you are choosing infrastructure for an AI agent, do not start with the SDK demo. Start with the failure modes.
Ask whether the agent can install the package it discovered halfway through the task. Ask whether a process can keep running after one command returns. Ask whether there is a real interactive terminal, not just logs. Ask whether state survives reconnects. Ask whether the environment can fork when the agent wants to try two approaches. Ask whether you can resize the machine when the workload grows. Ask whether you can SSH in when the abstraction fails.
Most agent runtimes look fine when the job is "run this code and return stdout." The important question is what happens after the task stops being that tidy.
Bash is a useful test because it exposes the truth quickly. If the shell is fake, the agent will find the edge. If the filesystem is fake, the agent will find the edge. If processes are fake, the agent will find the edge. If the environment is real, the agent can keep working.
The durable interface
The future of agent tooling will not be one giant terminal window. Good products will have buttons, approvals, previews, diffs, logs, permissions, traces, and high-level actions. Users should not have to stare at shell output unless that is the right interface for the moment.
But underneath those product surfaces, the durable abstraction is still a computer.
Bash is not the whole product. It is the universal adapter between the agent and the machine. A real Linux VM makes that adapter honest. It lets the agent use the software world as it exists instead of the smaller world your tool list predicted.
That is why Bash is the API for AI agents. Not the only API. The one that keeps working when the task becomes real.

