> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/nullclaw/nullclaw/llms.txt
> Use this file to discover all available pages before exploring further.

# Shell

> Execute shell commands with security policies and workspace scoping

# Shell Tool

The `shell` tool executes shell commands in the workspace directory with comprehensive security controls:

* **Command validation** against SecurityPolicy
* **Environment sanitization** to prevent API key leaks
* **Working directory control** with `cwd` parameter
* **Timeout enforcement** (default: 60 seconds)
* **Output limits** (default: 1 MB)

## Parameters

<ParamField path="command" type="string" required>
  The shell command to execute
</ParamField>

<ParamField path="cwd" type="string">
  Working directory (absolute path within allowed paths; defaults to workspace)
</ParamField>

## Configuration

```zig theme={null}
const st = try allocator.create(shell.ShellTool);
st.* = .{
    .workspace_dir = "/path/to/workspace",
    .allowed_paths = &.{},  // Additional allowed directories
    .timeout_ns = 60 * std.time.ns_per_s,  // 60 second default
    .max_output_bytes = 1_048_576,  // 1 MB default
    .policy = &security_policy,  // Optional SecurityPolicy
};
```

## Usage

### Basic Command

```json theme={null}
{
  "tool": "shell",
  "command": "ls -la"
}
```

**Response:**

```
total 24
drwxr-xr-x  5 user  staff  160 Mar  1 12:00 .
drwxr-xr-x  3 user  staff   96 Mar  1 11:00 ..
-rw-r--r--  1 user  staff  100 Mar  1 12:00 README.md
drwxr-xr-x  3 user  staff   96 Mar  1 11:30 src
```

### Custom Working Directory

```json theme={null}
{
  "tool": "shell",
  "command": "pwd",
  "cwd": "/workspace/src"
}
```

**Response:**

```
/workspace/src
```

### Pipeline Commands

```json theme={null}
{
  "tool": "shell",
  "command": "git status --short | grep M"
}
```

**Response:**

```
 M src/main.zig
 M src/config.zig
```

## Security Model

### SecurityPolicy Validation

When a `SecurityPolicy` is configured, all commands are validated before execution:

```zig theme={null}
const policy = SecurityPolicy{
    .autonomy = .supervised,
    .workspace_dir = "/workspace",
    .allowed_commands = &.{ "git", "ls", "cat", "grep", "echo", "touch" },
    .require_approval_for_medium_risk = true,
    .block_high_risk_commands = true,
    .tracker = &rate_tracker,
};
```

**Command Risk Levels:**

* **Low risk** — Read-only operations (ls, cat, grep, pwd, echo)
* **Medium risk** — Write operations (touch, mkdir, git add, git commit)
* **High risk** — Destructive operations (rm -rf, dd, mkfs, iptables, kill)

**Policy Actions:**

| Risk Level | autonomy=supervised | autonomy=full    |
| ---------- | ------------------- | ---------------- |
| Low        | Execute             | Execute          |
| Medium     | Require approval\*  | Execute          |
| High       | Block\*\*           | Require approval |

\*If `require_approval_for_medium_risk = true`\
\*\*If `block_high_risk_commands = true`

### Example: Approval Required

```json theme={null}
{
  "tool": "shell",
  "command": "touch test.txt"
}
```

**Response (if approval required):**

```
Command requires approval (medium/high risk): touch test.txt
```

### Example: Blocked Command

```json theme={null}
{
  "tool": "shell",
  "command": "rm -rf /"
}
```

**Response:**

```
High-risk command blocked by security policy
```

### Allowed Commands Allowlist

When `allowed_commands` is configured, only listed commands are permitted:

```zig theme={null}
.allowed_commands = &.{ "git", "ls", "cat", "grep" },
```

```json theme={null}
{
  "tool": "shell",
  "command": "rm file.txt"
}
```

**Response:**

```
Command not allowed by security policy
```

## Environment Sanitization

The shell tool clears all environment variables by default, then re-adds only safe functional variables:

**Safe environment variables:**

* `PATH` — Command search path
* `HOME` — User home directory
* `TERM` — Terminal type
* `LANG`, `LC_ALL`, `LC_CTYPE` — Locale settings
* `USER` — Username
* `SHELL` — Default shell
* `TMPDIR` — Temporary directory

**Blocked variables:**

* `OPENAI_API_KEY`
* `ANTHROPIC_API_KEY`
* `GEMINI_API_KEY`
* All other environment variables

This prevents accidental API key leaks via command injection (CWE-200).

## Working Directory Control

### Default: workspace\_dir

By default, commands run in `workspace_dir`:

```json theme={null}
{
  "tool": "shell",
  "command": "pwd"
}
```

**Response:**

```
/workspace
```

### Custom cwd (within workspace)

```json theme={null}
{
  "tool": "shell",
  "command": "ls",
  "cwd": "/workspace/src"
}
```

**Response:**

```
main.zig
config.zig
utils.zig
```

### Custom cwd (outside workspace)

Requires `allowed_paths` configuration:

```zig theme={null}
st.* = .{
    .workspace_dir = "/workspace",
    .allowed_paths = &.{
        "/data",
        "/home/user/projects",
    },
};
```

```json theme={null}
{
  "tool": "shell",
  "command": "ls",
  "cwd": "/data"
}
```

**Allowed** (in allowed\_paths)

```json theme={null}
{
  "tool": "shell",
  "command": "ls",
  "cwd": "/etc"
}
```

**Blocked:**

```
cwd is outside allowed areas
```

### cwd Validation Rules

* `cwd` must be an absolute path
* `cwd` must be within `workspace_dir` or `allowed_paths`
* `cwd` is resolved with `realpathAlloc()` to prevent symlink escapes
* Relative `cwd` is rejected: "cwd must be an absolute path"

## Platform Shells

The shell tool uses the platform's default shell:

| Platform | Shell     | Command Format         |
| -------- | --------- | ---------------------- |
| macOS    | `/bin/sh` | `sh -c "command"`      |
| Linux    | `/bin/sh` | `sh -c "command"`      |
| Windows  | `cmd.exe` | `cmd.exe /c "command"` |

Commands are passed as a single string to the shell's `-c` flag (Unix) or `/c` flag (Windows).

## Timeout and Output Limits

### Timeout

Commands are terminated after `timeout_ns` nanoseconds:

```zig theme={null}
.timeout_ns = 60 * std.time.ns_per_s,  // 60 seconds
```

**Example: Long-running command**

```json theme={null}
{
  "tool": "shell",
  "command": "sleep 120"
}
```

**Response (after 60 seconds):**

```
Command terminated by signal
```

### Output Limit

Stdout and stderr are truncated to `max_output_bytes`:

```zig theme={null}
.max_output_bytes = 1_048_576,  // 1 MB
```

**Example: Large output**

```json theme={null}
{
  "tool": "shell",
  "command": "cat /dev/zero | head -c 10M"
}
```

**Response:**

```
[Binary output truncated to 1 MB]
```

## Error Handling

### Command Failure (Non-Zero Exit Code)

```json theme={null}
{
  "tool": "shell",
  "command": "ls /nonexistent"
}
```

**Response:**

```
ls: /nonexistent: No such file or directory
```

`ToolResult.success = false`

### Signal Termination

```json theme={null}
{
  "tool": "shell",
  "command": "sleep 1000"
}
```

**Response (after timeout):**

```
Command terminated by signal
```

### Missing Command

```json theme={null}
{
  "tool": "shell",
  "command": "nonexistent_program"
}
```

**Response:**

```
sh: nonexistent_program: command not found
```

### No Output

If a command succeeds but produces no output:

```json theme={null}
{
  "tool": "shell",
  "command": "touch file.txt"
}
```

**Response:**

```
(no output)
```

## Use Cases

### Git Operations

```json theme={null}
{
  "tool": "shell",
  "command": "git status --short"
}
```

### Build Commands

```json theme={null}
{
  "tool": "shell",
  "command": "zig build"
}
```

### File Search

```json theme={null}
{
  "tool": "shell",
  "command": "find src -name '*.zig' | wc -l"
}
```

### Testing

```json theme={null}
{
  "tool": "shell",
  "command": "zig build test --summary all"
}
```

### System Info

```json theme={null}
{
  "tool": "shell",
  "command": "uname -a"
}
```

<Warning>
  Always validate shell commands for security risks. Use `SecurityPolicy` to enforce safe command patterns.
</Warning>

## Source

`src/tools/shell.zig:21-117`

## Testing

Run shell tool tests:

```bash theme={null}
zig build test --summary all
```

Tests cover:

* Basic command execution
* Path validation (cwd)
* Policy enforcement
* Timeout handling
* Output limits
* Error cases
