In the [previous chapter](05_response___tool_call_handling.md), we learned how Codex listens to the AI and understands when it wants to use a tool, like running a specific shell command (`git status` or `npm install`). We also know from the [Approval Policy & Security](04_approval_policy___security.md) chapter that Codex checks if it *should* run the command based on your chosen safety level.
But once Codex has the command and permission (either from you or automatically), how does it actually *run* that command? And how does it do it safely, especially if you've given it more freedom in `full-auto` mode?
That's the job of the **Command Execution & Sandboxing** system.
## What's the Big Idea? The Workshop Safety Zones
Imagine Codex is working in a workshop. This system is like the different areas and safety procedures in that workshop:
***The Main Workbench (Raw Execution):** For simple, safe tasks (like running `ls` to list files), Codex might just use the tools directly on the main workbench. It's straightforward, but you wouldn't use dangerous chemicals there.
***The Safety Cage (Sandboxing):** For potentially risky tasks (like testing a powerful new tool, or maybe running a command the AI suggested that you haven't manually approved in `full-auto` mode), Codex moves the work inside a special safety cage. This cage has reinforced walls and maybe limited power outlets, preventing any accidents from affecting the rest of the workshop.
This system takes a command requested by the AI (like `python script.py` or `git commit -m "AI commit"`) and actually runs it on your computer's command line. Crucially, it decides *whether* to run it directly (on the workbench) or inside a restricted environment (the safety cage or "sandbox"). It also collects the results – what the command printed (output/stdout), any errors (stderr), and whether it finished successfully (exit code).
## Key Concepts
1.**Raw Execution:**
***What:** Running the command directly using your system's shell, just like you would type it.
***When:** Used for commands deemed safe, or when you explicitly approve a command in `suggest` or `auto-edit` mode.
***Pros:** Simple, has full access to your environment (which might be needed).
***Cons:** If the AI makes a mistake and suggests a harmful command, running it raw could cause problems.
2.**Sandboxing:**
***What:** Running the command inside a restricted environment that limits what it can do. Think of it as putting the command in "jail."
***How (Examples):**
***macOS Seatbelt:** Uses a built-in macOS feature (`sandbox-exec`) with a specific policy file to strictly control what the command can access (e.g., only allow writing to the project folder, block network access).
***Docker Container:** Runs the command inside a lightweight container (like the one defined in `codex-cli/Dockerfile`). This container has only specific tools installed and can have network rules applied (using `iptables`/`ipset` via `init_firewall.sh`) to limit internet access.
***When:** Typically used automatically in `full-auto` mode (as decided by the [Approval Policy & Security](04_approval_policy___security.md) check), or potentially if a specific command is flagged as needing extra caution.
***Pros:** Significantly reduces the risk of accidental damage from faulty or malicious commands suggested by the AI.
***Cons:** Might prevent a command from working if it legitimately needs access to something the sandbox blocks (like a specific system file or network resource). The setup can be more complex.
The Command Execution system doesn't decide *whether* to run a command – that's the job of the [Approval Policy & Security](04_approval_policy___security.md). This system comes into play *after* the approval check.
Remember the `handleExecCommand` function from the [Agent Loop](03_agent_loop.md) chapter? It first calls `canAutoApprove` ([Approval Policy & Security](04_approval_policy___security.md)). If the command is approved (either by policy or by you), `canAutoApprove` tells `handleExecCommand`*whether* sandboxing is needed (`runInSandbox: true` or `runInSandbox: false`).
runInSandbox=safety.runInSandbox;// Get sandbox flag from policy check
break;
// ... handle reject ...
}
// 3. *** Execute the command! ***
// Determine the actual sandbox mechanism (Seatbelt, Docker, None)
constsandboxType=awaitgetSandbox(runInSandbox);
// Call the function that handles execution
constsummary=awaitexecCommand(
args,
applyPatch,// (if it was an apply_patch command)
sandboxType,
abortSignal,
);
// 4. Format and return results
returnconvertSummaryToResult(summary);
}
```
***Steps 1 & 2:** Approval policy is checked, maybe the user is asked. We get the `runInSandbox` boolean.
***Step 3:** A helper (`getSandbox`) determines the specific `SandboxType` (e.g., `MACOS_SEATBELT` or `NONE`) based on `runInSandbox` and the operating system. Then, the core execution function (`execCommand`) is called, passing the command details and the chosen `sandboxType`.
***Step 4:** The results (stdout, stderr, exit code) from `execCommand` are packaged up.
## Under the Hood: Running the Command
Let's trace the execution flow:
```mermaid
sequenceDiagram
participant HEC as handleExecCommand
participant EC as execCommand (Helper)
participant Exec as exec (exec.ts)
participant Raw as rawExec (raw-exec.ts)
participant SB as execWithSeatbelt (macos-seatbelt.ts)
* It uses `child_process.spawn` to run the command. `spawn` is generally safer than `exec` as it doesn't involve an intermediate shell unless explicitly requested.
* It captures `stdout` and `stderr` data, enforcing a maximum buffer size to prevent memory issues.
* It listens for the `exit` event to get the exit code.
* It listens for the `error` event (e.g., if the command executable doesn't exist).
* It includes logic to kill the child process if the `abortSignal` is triggered (e.g., user presses Ctrl+C).
* Crucially, it always `resolve`s the promise, even on errors, packaging the error into the `ExecResult`.
### Sandboxing on macOS: `macos-seatbelt.ts`
This function wraps the command execution using macOS's `sandbox-exec` tool.
// 2. Construct the actual command to run: sandbox-exec + policy + original command
constfullCommand=[
"sandbox-exec",
"-p",policy,// Pass the policy string
...policyParams,// Pass parameters like -DWR_0=/path/to/project
"--",// End of sandbox-exec options
...cmd,// The original command and arguments
];
// 3. Execute the `sandbox-exec` command using rawExec
returnrawExec(fullCommand,opts,[],abortSignal);// writableRoots not needed by rawExec here
}
```
* It defines a base Seatbelt policy (`.sb` file format) that denies most actions by default but allows basic read operations and process execution.
* It dynamically adds `allow file-write*` rules for the specific `writableRoots` provided (usually the project directory and temp directories).
* It constructs a new command line that starts with `sandbox-exec`, passes the generated policy (`-p`), passes parameters defining the writable roots (`-D`), and finally appends the original command.
* It then calls `rawExec` to run this *entire*`sandbox-exec ... -- original-command ...` line. The operating system handles enforcing the sandbox rules.
### Sandboxing with Docker: `Dockerfile`
Another approach, often used on Linux or as a fallback, is Docker. The `Dockerfile` defines the restricted environment.
# Default command when container starts (might be codex or just a shell)
# ENTRYPOINT ["codex"]
```
***Minimal Tools:** The Docker image includes only a limited set of command-line tools, reducing the potential attack surface.
***Non-Root User:** Commands run as a non-privileged user (`node`) inside the container.
***Workspace:** Work typically happens in a specific directory (e.g., `/home/node/workspace`), often mapped to your project directory on the host machine.
***Network Firewall:** An `init_firewall.sh` script (run via `sudo` at startup or when needed) configures `iptables` to restrict network access. This prevents sandboxed commands from easily calling out to arbitrary internet addresses.
***Usage:** Codex might be run *entirely* within this container, or it might invoke commands *inside* this container from the outside using `docker exec`.
You've reached the end of the workshop tour! The **Command Execution & Sandboxing** system is Codex's way of actually *doing* things on the command line when instructed by the AI. It carefully considers the safety level decided by the [Approval Policy & Security](04_approval_policy___security.md) and chooses the right execution method: direct "raw" execution for trusted commands, or running inside a protective "sandbox" (like macOS Seatbelt or a Docker container) for potentially riskier operations, especially in `full-auto` mode. This layered approach allows Codex to be powerful while providing crucial safety mechanisms against unintended consequences.
We've seen how Codex handles input, talks to the AI, checks policies, and executes commands. But how does Codex know *which* AI model to use, what your API key is, or which approval mode you prefer? All these settings need to be managed.
Next up: [Configuration Management](07_configuration_management.md)
---
Generated by [AI Codebase Knowledge Builder](https://github.com/The-Pocket/Tutorial-Codebase-Knowledge)