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

# Approvals API

> Review and approve or deny pending shell command executions before they run.

When `ShellTool` is configured with `require_approval=True`, every shell command is queued and waits for explicit approval before executing. The approvals API lets you review, approve, or deny these queued commands.

## GET /approvals/pending

List all commands waiting for approval.

```bash theme={null}
curl http://localhost:7432/api/v1/approvals/pending
```

```json theme={null}
{
  "pending": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "tool_name": "shell",
      "command": "rm -rf /tmp/old-logs",
      "arguments": {
        "command": "rm -rf /tmp/old-logs",
        "timeout": 30,
        "workdir": "/home/user"
      },
      "session_id": "default",
      "created_at": 1723123200.0
    }
  ]
}
```

## POST /approvals/{approval_id}/approve

Approve a pending command. The command executes immediately after approval.

```bash theme={null}
curl -X POST http://localhost:7432/api/v1/approvals/550e8400-e29b-41d4-a716-446655440000/approve
```

```json theme={null}
{ "approved": true, "id": "550e8400-e29b-41d4-a716-446655440000", "always_allowed": false }
```

Pass `{"always": true}` in the body to also persist a durable allowlist entry for the command's program name, so future matching commands skip the prompt entirely:

```bash theme={null}
curl -X POST http://localhost:7432/api/v1/approvals/550e8400.../approve \
  -H "Content-Type: application/json" -d '{"always": true}'
```

Returns `404` if the approval ID is not found (expired or already resolved).

## POST /approvals/{approval_id}/deny

Deny a pending command. The agent receives an error: `"Command denied by user approval gate."`.

```bash theme={null}
curl -X POST http://localhost:7432/api/v1/approvals/550e8400-e29b-41d4-a716-446655440000/deny
```

```json theme={null}
{ "denied": true }
```

## Approval timeout

Approval requests expire after 120 seconds. If no decision is made, the command is automatically denied.

## Persistent allowlist

Commands matching a stored entry skip the prompt entirely (subject to the `ask` mode below).

```bash theme={null}
curl http://localhost:7432/api/v1/approvals/allowlist
curl -X POST http://localhost:7432/api/v1/approvals/allowlist \
  -H "Content-Type: application/json" -d '{"pattern": "git", "arg_pattern": "^git log"}'
curl -X DELETE http://localhost:7432/api/v1/approvals/allowlist/3
```

`pattern` is a glob matched against the program name (e.g. `git`, `curl*`); `arg_pattern` (optional) is a regex matched against the full command line.

## Security & ask modes

```bash theme={null}
curl http://localhost:7432/api/v1/approvals/policy
curl -X POST http://localhost:7432/api/v1/approvals/policy \
  -H "Content-Type: application/json" -d '{"security": "allowlist", "ask": "on-miss"}'
```

| `security`  | Behavior                                                                |
| ----------- | ----------------------------------------------------------------------- |
| `deny`      | Every gated command is denied outright — no prompt.                     |
| `allowlist` | Matching commands auto-approve; others fall through to `ask`. (default) |
| `full`      | Every gated command auto-approves — gate effectively disabled.          |

| `ask`     | Behavior                                               |
| --------- | ------------------------------------------------------ |
| `off`     | Never prompt; an unmatched command is denied silently. |
| `on-miss` | Prompt only when no allowlist entry matches. (default) |
| `always`  | Always prompt, even when an entry matches.             |

`GET /api/v1/approvals/policy` also returns `require_shell_approval` — whether the gate itself is actually enabled on the running `shell`/`browser` tools right now (defaults from `[security] require_shell_approval` in `config.toml`, see [Configuration](/configuration)). The `security`/`ask` modes above have no effect at all when this is `false` — every command just runs. It's `null` if the tool registry isn't available yet (still starting up).

`POST /api/v1/approvals/policy` also accepts `require_shell_approval` to toggle the gate live on both tools, no restart needed:

```bash theme={null}
curl -X POST http://localhost:7432/api/v1/approvals/policy \
  -H "Content-Type: application/json" -d '{"require_shell_approval": true}'
```

## Channel-forwarded approval

A pending approval is also sent as a plain-text message via the channel that triggered it (Telegram, Slack, Discord, etc. — any of the 34 adapters). Reply directly in that channel:

```
approve a1b2c3d4
deny a1b2c3d4
```

matching the short id shown in the notification — no separate UI visit required.

## CLI equivalents

```bash theme={null}
neuralcleave approvals pending
neuralcleave approvals approve <id> [--always]
neuralcleave approvals deny <id>
neuralcleave approvals allowlist list|add|remove
```

## Enabling the approval gate

```python theme={null}
from neuralcleave.tools.shell import ShellTool

tool = ShellTool(require_approval=True, session_id="default")
```

## Dashboard

The `/terminal` page in the dashboard shows pending approvals and lets you approve or deny them with a click — without needing to call the API directly.
