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

# Permissions

> Permission modes, categories, layered settings, risk classification, and path-traversal protections in Claurst.

Claurst uses a layered permission system that controls which tool calls can execute automatically and which require user approval. The system is deliberately conservative by default and supports several operational modes.

## Permission modes

The active mode is set via `--permission-mode` on the CLI or the `permission_mode` field in settings.

| Mode                      | Rust variant                        | Behaviour                                                                                                          |
| ------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| **Default** (interactive) | `PermissionMode::Default`           | Read-only operations run automatically. All write and execute operations prompt the user.                          |
| **AcceptEdits**           | `PermissionMode::AcceptEdits`       | All operations — including writes and edits — run automatically.                                                   |
| **BypassPermissions**     | `PermissionMode::BypassPermissions` | Every permission check returns `Allow` immediately; no prompts are shown. Use only in trusted automation contexts. |
| **Plan**                  | `PermissionMode::Plan`              | Read-only planning mode. Only tools with `is_read_only == true` are permitted; all others are denied.              |

<Warning>
  The original TypeScript codebase contains an additional mode called **YOLO** that, despite its name, actually **denies all** non-read-only operations. The name is counterintuitive. In Claurst the equivalent of "allow everything" is `BypassPermissions`, not a mode called YOLO.
</Warning>

The `auto` permission mode referenced in the TypeScript source uses an ML-based transcript classifier to approve tool calls automatically. In Claurst this maps to `AcceptEdits` for tool execution purposes — the classifier infrastructure is not part of the clean-room implementation.

## Permission categories

Every permission check is associated with one of these categories, which map directly to the tool types that trigger them:

| Category    | Tools that use it                                                                   |
| ----------- | ----------------------------------------------------------------------------------- |
| `Bash`      | `BashTool`, `PowerShellTool`                                                        |
| `FileRead`  | `FileReadTool`, `GlobTool`, `GrepTool`                                              |
| `FileEdit`  | `FileEditTool`, `NotebookEditTool`                                                  |
| `FileWrite` | `FileWriteTool`                                                                     |
| `WebFetch`  | `WebFetchTool`, `WebSearchTool`                                                     |
| `MCP`       | `ListMcpResourcesTool`, `ReadMcpResourceTool`, and dynamically registered MCP tools |
| `Sandbox`   | Sandboxed execution contexts                                                        |

## How the AutoPermissionHandler works

`AutoPermissionHandler` is the non-interactive handler used in headless and scripted runs. It implements the `PermissionHandler` trait:

```rust theme={null}
impl PermissionHandler for AutoPermissionHandler {
    fn check_permission(&self, tool_name: &str) -> PermissionDecision {
        match self.mode {
            PermissionMode::BypassPermissions => PermissionDecision::Allow,
            PermissionMode::AcceptEdits      => PermissionDecision::Allow,
            PermissionMode::Plan             => {
                if self.is_read_only(tool_name) {
                    PermissionDecision::Allow
                } else {
                    PermissionDecision::Deny
                }
            }
            PermissionMode::Default => {
                if self.is_read_only(tool_name) {
                    PermissionDecision::Allow
                } else {
                    PermissionDecision::Deny
                }
            }
        }
    }
}
```

In the interactive TUI, the `PermissionHandler` surfaces a dialog to the user and waits for a `y`/`n` response before returning a decision.

## Layered settings

Permission rules are stored in JSON settings files. The files are read in priority order — the highest-priority source wins:

<Steps>
  <Step title="Managed / enterprise settings (read-only)">
    Deployed by an organisation's device management system. Users cannot override these rules. Equivalent to a policy layer.
  </Step>

  <Step title="Local project: .claude/settings.local.json">
    Machine-local settings for the current project. This file should be added to `.gitignore`. Suitable for developer-specific overrides that should not be shared with the team.
  </Step>

  <Step title="Project: .claude/settings.json">
    Shared project settings checked into source control. Suitable for project-wide permission rules that every contributor should use.
  </Step>

  <Step title="Global: ~/.claude/settings.json">
    User-level settings applied to all projects. Loaded by `Settings::load()` in `cc-core`.
  </Step>
</Steps>

The `Settings` struct in `cc-core` handles loading and saving:

```rust theme={null}
// Load from ~/.claude/settings.json; returns default on missing file
pub async fn load() -> Result<Settings>

// Serialize to JSON and write; creates parent directories
pub async fn save(&self) -> Result<()>
```

### Example settings.json permission rule configuration

```json theme={null}
{
  "permissions": {
    "allow": [
      "Bash(git log *)",
      "Bash(git diff *)",
      "Read(*)"
    ],
    "deny": [
      "Bash(rm -rf *)",
      "Write(/etc/*)"
    ]
  }
}
```

Rules use permission rule syntax: `ToolName(pattern)`. Patterns support glob matching against the tool's input.

## Risk classification

Every tool action is internally classified as **LOW**, **MEDIUM**, or **HIGH** risk. This classification drives the auto-permission decision and determines what information the permission explainer surfaces to the user.

| Risk level | Examples                                         |
| ---------- | ------------------------------------------------ |
| **LOW**    | `Read`, `Glob`, `Grep`, `WebFetch`, `ToolSearch` |
| **MEDIUM** | `Edit`, `Write`, `NotebookEdit`, `WebSearch`     |
| **HIGH**   | `Bash`, `PowerShell`, `Task` (sub-agents)        |

## Protected files

The following files resist automatic editing. Any tool call that would write to these paths requires explicit user approval, even in `AcceptEdits` mode:

* `.gitconfig`
* `.bashrc`
* `.zshrc`
* `.mcp.json`
* `.claude.json`

These protections are enforced at the permission layer before the tool's `execute()` method is called.

## Path traversal prevention

Claurst's memory path validation (`validateMemoryPath()`) and team memory write validation (`validateTeamMemWritePath()`) guard against path traversal attacks using several techniques:

**URL-encoded traversal detection** — Patterns like `%2e%2e%2f` (URL-encoded `../`) are detected and rejected before path resolution.

**Unicode normalization attacks** — Fullwidth characters such as `．．／` normalise to `../` under NFC. Paths are normalised before comparison.

**Backslash injection** — Backslashes in path keys are rejected regardless of platform.

**Absolute path rejection** — Relative paths to the memory directory must not start with `/`.

**Two-pass symlink validation** — `validateTeamMemWritePath()` first uses `path::resolve()` to eliminate `..` segments, then follows symlinks using `realpathDeepestExisting()` to verify that the real filesystem path is still inside the permitted directory. Symlink loops (ELOOP) and dangling symlinks are handled explicitly.

**Null byte rejection** — Null bytes in path keys are rejected before any filesystem operation.
