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

# Autonomy Levels

> Control how much freedom the agent has to act without human approval.

> **Status: Stable** — The three autonomy modes and the ApprovalManager are production-ready.

# Autonomy Levels

FERAL's autonomy system controls how much freedom the agent has to act without human approval. Three modes — **strict**, **hybrid**, and **loose** — determine which tools auto-execute and which require explicit confirmation.

## Strict Mode

Every tool call requires user approval. The agent proposes an action and waits.

```
User: "What's the weather in NYC?"
Agent: I'd like to call the weather API for NYC. Approve? [✓ / ✗]
User: ✓
Agent: It's 72°F and sunny in New York.
```

Best for: first-time setup, untrusted environments, auditing all agent behavior.

```json theme={null}
// ~/.feral/settings.json
{ "autonomy": { "mode": "strict" } }
```

## Hybrid Mode

Safe actions (`passive` + `active` permission tiers) execute automatically. Risky actions (`privileged` + `dangerous`) require approval.

```
User: "Search for flights to Tokyo and book the cheapest one."
Agent: [auto] Searching flights... found 3 options.
Agent: The cheapest is $450 on ANA. I need approval to book. Approve? [✓ / ✗]
```

This is the **default** mode. Most users stay here — the agent handles research and information retrieval instantly, but pauses before actions with real-world consequences.

```yaml theme={null}
autonomy: hybrid
```

### What Auto-Executes in Hybrid

| Action              | Tier       | Auto?           |
| :------------------ | :--------- | :-------------- |
| Search the web      | passive    | Yes             |
| Read memory         | passive    | Yes             |
| Get weather         | passive    | Yes             |
| Send a chat message | active     | Yes             |
| Create a file       | active     | Yes             |
| Run a shell command | privileged | No — asks first |
| Send an email       | privileged | No — asks first |
| Delete files        | dangerous  | No — asks first |
| Make a purchase     | dangerous  | No — asks first |

## Loose Mode

Everything except `dangerous`-tier tools auto-executes. The agent runs on full autopilot for most tasks.

```
User: "Clean up my Downloads folder — delete anything older than 30 days."
Agent: [auto] Listing files... found 47 files older than 30 days.
Agent: [auto] Moving 47 files to trash... done.
```

<Note>
  `dangerous` tools still require approval even in loose mode. See [Security Model](/guides/security) for the hard-coded deny list.
</Note>

```yaml theme={null}
autonomy: loose
```

## Configuration

### Environment Variable

```bash theme={null}
export FERAL_AUTONOMY=hybrid   # strict | hybrid | loose
```

The env var takes precedence over the config file, useful for per-session overrides:

```bash theme={null}
FERAL_AUTONOMY=strict feral start
```

### Config File

```json theme={null}
// ~/.feral/settings.json
{ "autonomy": { "mode": "hybrid" } }
```

### Per-Session Override

Clients can request an autonomy level during session initialization:

```python theme={null}
from feral_sdk import FeralClient

async with FeralClient("http://localhost:9090") as client:
    session = await client.create_session(autonomy="strict")
```

The server enforces that a session cannot escalate beyond the server-level setting. If the server is `hybrid`, a session can request `strict` (more restrictive) but not `loose` (less restrictive).

## ApprovalManager

The `ApprovalManager` handles approval requests and maintains a list of **standing approvals** — pre-authorized tool+argument patterns that skip the approval prompt.

```python theme={null}
from feral_core.security import ApprovalManager

manager = ApprovalManager()

manager.grant_standing(
    tool="shell_exec",
    pattern={"command": "ls *"},     # glob match on args
    expires_in=3600,                  # seconds; None = permanent
)

approved = manager.check("shell_exec", {"command": "ls -la ~/Documents"})
# approved == True (matches "ls *" pattern)
```

Standing approvals are stored in `~/.feral/exec_approvals.db` and persist across restarts. They are managed today through the Python `ApprovalManager` API (used by skills, channels, and the orchestrator); a public CLI/REST surface for granting and listing them is tracked as a follow-up.

## Approval Inbox API

Every blocked tool call also surfaces in a non-chat **approval inbox** so a web UI, mobile client, or automation can resolve it without typing into a chat session. See [REST API → Approvals (Execution Inbox)](/reference/api#approvals-execution-inbox) for the full reference.

| Method | Path                                  | Description                                             |
| ------ | ------------------------------------- | ------------------------------------------------------- |
| `GET`  | `/api/approvals`                      | List pending requests (optional `session_id`, `limit`). |
| `POST` | `/api/approvals/{request_id}/approve` | Approve and execute.                                    |
| `POST` | `/api/approvals/{request_id}/reject`  | Reject without executing.                               |

```bash theme={null}
curl http://localhost:9090/api/approvals?session_id=s-abc123

curl -X POST http://localhost:9090/api/approvals/apr_01HXYZ/approve \
  -H "Content-Type: application/json" \
  -d '{ "session_id": "s-abc123" }'
```

Both write endpoints accept an optional `{ "session_id": "…" }` body. When supplied it must match the session that owns the pending request, or the call returns `409 session_mismatch`. Resolving an unknown request returns `404`.

## Approval Flow

When a tool call needs approval, the following sequence occurs:

1. `enforce_safety()` determines the call requires approval and a pending request is created with a stable `request_id`.
2. The Brain sends an `approval_request` frame to the active chat session **and** the same request becomes visible at `GET /api/approvals`.
3. The user responds, either by acknowledging in chat or by hitting `POST /api/approvals/{request_id}/approve` or `…/reject`.
4. If approved, the tool executes and the result flows back normally.
5. If denied, the agent receives a "tool denied" signal and re-plans.

```json theme={null}
{
  "type": "approval_request",
  "payload": {
    "request_id": "apr_abc123",
    "tool": "shell_exec",
    "args": {"command": "rm -rf /tmp/old-cache"},
    "permission_tier": "privileged",
    "reason": "Shell command execution requires approval in hybrid mode"
  }
}
```

## Escalation Rules

| Server Setting | Session Request | Effective Level |
| :------------- | :-------------- | :-------------- |
| `strict`       | `strict`        | strict          |
| `strict`       | `hybrid`        | strict (capped) |
| `hybrid`       | `strict`        | strict          |
| `hybrid`       | `hybrid`        | hybrid          |
| `hybrid`       | `loose`         | hybrid (capped) |
| `loose`        | any             | as requested    |
