An autonomous agent is an agent that can make independent decisions to accomplish tasks—without constant human guidance.
But how do we measure the level of autonomy an agent has?
The answer lies in the variety of tasks an agent can perform on its own.
Consider an agent that has a single tool—the ability to write files. That's one degree of autonomy. It can create content, save it, and that's about it.
Now consider an agent with access to a terminal. Suddenly, the possibilities explode:
This is a high degree of autonomy—which, as we'll discuss, comes with both incredible power and important security considerations.
This is basically the idea behind modern coding tools like Claude Code—or even better, OpenClaw.
The main thing we need to enable is an implementation for executing tools in a loop.
I'll use a library I built for this—@mozaik-ai/core—a TypeScript framework for orchestrating AI agents.
With Mozaik, we can easily equip an agent with tools. So we just need to create a terminal tool for executing commands.
First, let's define the terminal class that will give our agent the ability to execute shell commands:
1import { spawn } from "child_process"23export class Terminal {45 runCommand(command: string, cwd: string): Promise<CommandResult> {6 return new Promise((resolve) => {7 const [cmd, ...args] = command.split(" ")8 const process = spawn(cmd, args, { cwd, shell: true })910 let stdout = "", stderr = ""1112 process.stdout?.on("data", (data) => stdout += data.toString())13 process.stderr?.on("data", (data) => stderr += data.toString())1415 process.on("close", (code) => {16 resolve({17 success: code === 0,18 stdout: stdout.trim(),19 stderr: stderr.trim(),20 exitCode: code ?? -1,21 })22 })23 })24 }25}
Now we define the tool that will give our agent the ability to execute shell commands:
The tool is straightforward: it takes a command string, executes it using Node.js's child_process module, and returns the output.
1const terminal = new Terminal()2const tools: Tool[] = [3 {4 name: "run_command",5 description: "Run a command in the terminal.",6 schema: {7 type: "object",8 properties: {9 command: { type: "string", description: "The command to run in the terminal." },10 cwd: { type: "string", description: "The current working directory." },11 },12 required: ["command", "cwd"],13 },14 async invoke({ command, cwd }) {15 console.log(`Running command: ${command} in directory: ${cwd}`)16 console.log("--------------------------------")17 const result = await terminal.runCommand(command, cwd)18 return result19 },20 },21]
Now we attach the terminal tool to our agent:
1const request: MozaikRequest = {2 model: "gpt-5-mini",3 tools: tools,4}5const userRequest = `Analyze the github respository and update the README.md file with a high level description of the project.`67const task = `You are a terminal agent.89You can run commands in the terminal to help the user with their request.10Do not ask any questions to the user. Just run the commands and return the result.1112Tools:13- run_command: Run a command in the terminal. You can use this tool to run any command in the terminal.1415User Request:16- ${userRequest}17`1819const agent = new MozaikAgent(request)20const result = await agent.act(task)
Let's give the agent a task and watch it work. Below you can see what happens step by step—the terminal commands the agent autonomously executes to get the job done.
1const userRequest = `Look at this folder and tell me in one sentence what it does2 — like you're explaining it to someone who has never written a line of code.`
The agent breaks it down on its own:

1const userRequest = `Analyze this directory and write2 a detailed description of the project3 in a file called purpose.md.`

With great autonomy comes great responsibility. Terminal access is powerful—but it can also be dangerous if not properly controlled.
Key security measures to consider:
The balance between autonomy and safety is a spectrum. Start with tighter controls and expand as you build confidence in your agent's behavior.
Building an autonomous agent with terminal access is surprisingly straightforward—the core pattern is just a tool execution loop.
What makes these agents powerful isn't the complexity of the implementation, but the emergent capabilities that arise from giving an LLM access to a shell.
The agent doesn't need to be explicitly programmed for every scenario. Give it a goal, give it tools, and it will find a way.
The prototype, which is in an early stage, is available in the GitHub repo:
github.com/jigjoy-ai/terminal-agentThe best way to predict the future is to invent it.