clash 0.5.5

Command Line Agent Safety Harness — permission policies for coding agents
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
# Policy Writing Guide

A practical guide to writing clash policies. Clash policies are written in Starlark, a Python-like configuration language. For the built-in API, see the `@clash//std.star` standard library. For evaluation semantics, see [policy-semantics.md](./policy-semantics.md).

---

## Quick Start

Clash policies use Starlark (`.star` files) with three capability domains: **shell commands** (via `match()`), **fs** (file operations), and **net** (network access).

```python
# ~/.clash/policy.star
load("@clash//std.star", "allow", "deny", "match", "policy", "domains")

def main():
    return policy(default = deny(), rules = [
        match({"Bash": {"git": {"push": deny()}}}),
        match({"Bash": {"git": allow()}}),
        match({("Read", "Write", "Edit", "Glob", "Grep"): allow()}),
        domains({"github.com": allow()}),
    ])
```

This policy allows git commands (except push), file reads and writes under the current directory, and network access to github.com. Everything else is denied.

<details>
<summary>Compiled JSON IR (advanced)</summary>

The Starlark policy above compiles to the following JSON intermediate representation. Users typically do not write this directly.

```json
{
  "schema_version": 5,
  "default_effect": "deny",
  "sandboxes": {},
  "tree": [
    { "condition": { "observe": "tool_name", "pattern": { "literal": { "literal": "Bash" } },
        "children": [
          { "condition": { "observe": { "positional_arg": 0 }, "pattern": { "literal": { "literal": "git" } },
              "children": [
                { "condition": { "observe": { "positional_arg": 1 }, "pattern": { "literal": { "literal": "push" } },
                    "children": [{ "decision": "deny" }] } },
                { "decision": { "allow": null } }
              ] } }
        ] } },
    { "condition": { "observe": "tool_name", "pattern": "wildcard",
        "children": [{ "decision": { "allow": null } }] } }
  ]
}
```

</details>

---

## Policy File Location

| Path | Scope |
|------|-------|
| `~/.clash/policy.json` | User-level (machine-readable, preferred) |
| `~/.clash/policy.star` | User-level (Starlark, for power users) |
| `<project>/.clash/policy.json` | Project-level (machine-readable, preferred) |
| `<project>/.clash/policy.star` | Project-level (Starlark, for power users) |

JSON (`.json`) is the preferred format. If both `.json` and `.star` exist at the same level, the `.json` file takes precedence. Clash reads the policy on every hook invocation, so changes take effect immediately.

CLI commands like `clash policy allow`, `clash policy deny`, and `clash policy remove` operate on `policy.json` files. If only a `policy.star` exists, these commands will auto-create a `policy.json` that includes the existing `.star` file.

### policy.json Format

The `policy.json` file extends the v5 compiled policy format with an `includes` field for referencing Starlark files:

```json
{
  "schema_version": 5,
  "default_effect": "deny",
  "default_sandbox": "cwd",
  "sandboxes": {},
  "includes": [
    { "path": "@clash//builtin.star" },
    { "path": "team-rules.star" }
  ],
  "tree": []
}
```

- **`includes`** — References to `.star` files that are compiled and merged at load time. Use `@clash//` for stdlib modules or relative paths for local files.
- **`tree`** — Inline rules managed by CLI commands. These take precedence over included rules.
- **`sandboxes`** — Named sandbox definitions, also CLI-managed.

Included `.star` files are evaluated and their rules are appended after the inline `tree` rules, so inline rules always have higher priority.

---

## Capability Domains

Clash controls three capability domains, not individual tools. A single rule can cover multiple tools:

### Shell Commands

```python
match({"Bash": {"git": allow()}})
match({"Bash": {"git": {"push": deny()}}})
match({"Bash": {"cargo": {"test": allow()}}})
```

The `match()` function maps tool names to nested rules. Keys are matched against positional arguments -- deeper nesting = more specific matches.

> **Scope:** Shell command rules evaluate the top-level command that Claude Code invokes via the Bash tool. They do not apply to child processes spawned by that command. For example, a deny rule on `git push` prevents Claude from directly running `git push`, but if an allowed command like `make deploy` internally calls `git push`, the deny rule does not fire -- the policy engine only sees the top-level `make` command. Sandbox restrictions for filesystem and network access *are* enforced on all child processes at the kernel level (see [Sandbox Policies](#sandbox-policies)).

### Fs -- File Operations

File access for Claude Code tools is controlled via `match()` rules. Use `match()` to allow or deny the file-operation tools directly:

```python
match({("Read", "Glob", "Grep"): allow()})                        # read-only
match({("Read", "Write", "Edit", "Glob", "Grep"): allow()})       # read + write
```

To scope filesystem access to specific paths, attach a sandbox to an exec or tool match rule via the `sandbox=` parameter on `allow()`:

```python
match({("Read", "Write", "Edit"): allow(sandbox = sandbox(fs={"$PWD": allow("rwc")}))})
```

The fs domain maps to these tools:
- `Read` -> `fs read`
- `Write` -> `fs write`
- `Edit` -> `fs write`
- `Glob`/`Grep` -> `fs read`

### Net -- Network Access

```python
domains({"github.com": allow()})
domains({"github.com": allow(), "crates.io": allow()})
```

The net domain maps to:
- `WebFetch` -> `net` with the URL's domain
- `WebSearch` -> `net` with wildcard domain

### Tool -- Agent Tools

```python
match({"WebSearch": deny()})
match({("Read", "Glob", "Grep"): allow()})
```

The tool domain matches agent tools by name via `match()`. Use this for tools that don't map to exec/fs/net capabilities (e.g., `Skill`, `Agent`, `AskUserQuestion`) or when you want to control a tool directly rather than through its capability.

---

## Precedence

Rules use **first-match semantics**: within a capability domain, the first matching rule wins. Order matters — put more specific rules before broader ones.

### Example

```python
match({"Bash": {"git": {"push": deny()}}})
match({"Bash": {"git": allow()}})
```

`git push origin main` matches the deny rule first (it's listed first and matches). `git status` skips the deny (doesn't match "push") and matches the allow.

If the rules were reversed, `git push` would match the `allow()` first and be allowed — the deny would never fire.

### Cross-Domain Resolution

When a request matches rules in multiple capability domains (rare), deny-overrides applies: deny > ask > allow.

If no rules match, the `default` effect applies.

---

## Policy Composition

Starlark policies compose naturally using functions and variables:

```python
load("@clash//std.star", "allow", "deny", "match", "policy", "domains")

def file_access():
    return [
        match({("Read", "Write", "Edit", "Glob", "Grep"): allow()}),
    ]

def safe_git():
    return [
        match({"Bash": {"git": {"push": deny()}}}),
        match({"Bash": {"git": {"reset": deny()}}}),
        match({"Bash": {"git": allow()}}),
    ]

def main():
    return policy(default = deny(), rules = [
        *file_access(),
        *safe_git(),
        domains({"github.com": allow(), "crates.io": allow()}),
    ])
```

You can also use `load()` to import from other `.star` files.

### Updating Policies

The `update()` method combines two policies. In `a.update(b)`, `b`'s default effect is used, tree nodes from both are concatenated (`a`'s first, then `b`'s), and sandboxes are merged (first defined wins on name conflicts).

```python
load("@clash//builtin.star", "base")
load("@clash//std.star", "allow", "deny", "match", "policy", "domains")

def main():
    my_policy = policy(default = deny(), rules = [
        match({("Read", "Write", "Edit", "Glob", "Grep"): allow()}),
        match({"Bash": {"git": allow()}}),
        domains({"github.com": allow()}),
    ])
    return base.update(my_policy)
```

The `base` policy from `@clash//builtin.star` includes built-in rules for clash CLI commands and Claude Code interactive tools (Agent, Skill, etc.). Updating `base` with your policy ensures these tools work correctly alongside your custom rules.

### Built-in Policy (`@clash//builtin.star`)

The `@clash//builtin.star` module exports a `base` policy that bundles rules for:

- **Clash CLI** — allows `clash status`, `clash policy list`, `clash policy show`, `clash explain`, and `clash bug` with appropriate sandboxes
- **Claude Code tools** — allows interactive tools (`Agent`, `AskUserQuestion`, `EnterPlanMode`, `Skill`, `ToolSearch`, etc.) with a sandbox scoped to `~/.claude`

Load and update it with your policy to get sensible defaults for these tools:

```python
load("@clash//builtin.star", "base")
```

If you don't use `base`, you'll need to write your own rules for clash CLI commands and Claude Code interactive tools.

---

## Sandbox Policies

Shell command rules can attach a **sandbox policy** that defines what filesystem and network access a spawned process gets.

### Defining sandboxes

```python
load("@clash//std.star", "allow", "deny", "match", "sandbox", "policy", "domains")

def main():
    cargo_env = sandbox(
        default = deny(),
        fs = {
            "$PWD": allow("r"),
            "$PWD/target": allow("rwcd"),
        },
        net = allow(),
    )

    git_env = sandbox(
        default = deny(),
        fs = {
            "$PWD": allow("r"),
        },
    )

    return policy(default = deny(), rules = [
        match({"Bash": {"git": {"push": deny()}}}),
        match({"Bash": {"cargo": allow(sandbox = cargo_env)}}),
        match({"Bash": {"git": allow(sandbox = git_env)}}),
        match({("Read", "Glob", "Grep"): allow()}),
        domains({"github.com": allow()}),
    ])
```

When `cargo build` matches the shell command rule, the `cargo_env` sandbox defines the restrictions: the process can read the project, write to `./target`, and has unrestricted network access. When `git status` matches, it gets only read access to the project via `git_env`.

Note: Pass the sandbox via the `sandbox=` parameter on `allow()`, e.g. `allow(sandbox = my_sandbox)`.

### Sandbox presets

Intent-based sandbox presets express what you trust a command to do:

| Preset | Filesystem | Network | Use case |
|---|---|---|---|
| `restricted` | Read-only project | Deny | Untrusted scripts |
| `read_only` | Read project + home, write temp | Deny | Linters, analyzers |
| `dev` | Read+write project, read home | Deny | Build tools, git |
| `dev_network` | Read+write project, read home | Allow | Package managers, gh |
| `unrestricted` | Full project + home access | Allow | Fully trusted tools |

```python
load("@clash//sandboxes.star", "dev", "dev_network")

def main():
    return policy(default = deny(), rules = [
        match({"Bash": {"gh": allow(sandbox = dev_network)}}),
        match({"Bash": {"git": allow(sandbox = dev)}}),
        match({"Bash": allow(sandbox = dev)}),
    ])
```

### Language-specific sandboxes

Load pre-built sandbox configurations for common toolchains:

```python
load("@clash//rust.star", "rust_sandbox")

def main():
    return policy(default = deny(), rules = [
        match({"Bash": {("cargo", "rustc"): allow(sandbox = rust_sandbox)}}),
    ])
```

### Default behavior

When no sandbox is specified on a shell command allow, the spawned process gets no filesystem/network access beyond bare minimum (deny-all sandbox by default).

### What sandboxes enforce

Sandbox policies constrain **filesystem and network access** at the kernel level -- these restrictions are inherited by all child processes and cannot be bypassed. However, sandboxes do not enforce **argument matching** on child processes. If a sandboxed command spawns a subprocess, the subprocess inherits the filesystem and network restrictions but is not checked against shell command rules. Tracking issue: [#136](https://github.com/empathic/clash/issues/136).

### Automatic sandbox inclusions

Sandboxes automatically grant access to:

- **Temp directories**: `/tmp`, `/var/tmp` (Linux) or `/private/tmp`, `/private/var/folders` (macOS), plus `$TMPDIR`

### Sandbox network restrictions

Sandbox network access has four modes:

- `net = allow()` -- sandbox **allows** all network access (no restrictions)
- Localhost-only -- sandbox allows **localhost-only** connections, enforced at the kernel level without a proxy
- Domain list -- sandbox allows network access **only to listed domains** via a local HTTP proxy
- No net rule -- sandbox **denies** all network access

**Localhost-only mode**: When all allowed domains are loopback addresses (`"localhost"`, `"127.0.0.1"`, `"::1"`), Clash uses a lightweight localhost-only mode that is enforced directly by the OS sandbox without spawning an HTTP proxy. This is useful for processes that need to connect to local development servers but should not access the internet. On macOS, Seatbelt blocks non-localhost connections at the kernel level. On Linux, enforcement is advisory (seccomp cannot filter connect destinations).

**Domain filtering**: Domain-specific net rules are enforced using a local HTTP proxy. The OS sandbox restricts the process to localhost-only connections, and clash starts a proxy that checks each request against the domain allowlist. Programs that respect `HTTP_PROXY`/`HTTPS_PROXY` environment variables (curl, cargo, npm, pip, etc.) are filtered; programs that bypass the proxy can still reach any host on Linux (advisory enforcement). On macOS, Seatbelt blocks non-localhost connections at the kernel level.

Subdomain matching is supported: `"github.com"` also permits `api.github.com`.

---

## Starlark API Reference

### Patterns

```python
# Literal match (exact binary name or domain)
match({"Bash": {"git": allow()}})
domains({"github.com": allow()})

# Regex match
match({"Bash": {regex("^cargo-.*"): allow()}})

# Multiple binaries
match({"Bash": {("cargo", "rustc"): allow()}})

# Nested argument matching (tree builder)
match({"Bash": {"git": {"push": deny(), "pull": allow()}}})
```

### Platform Constants

```python
load("@clash//std.star", "allow", "match", "OS", "ARCH")

# OS is "macos" or "linux"; ARCH is "aarch64" or "x86_64"
if OS == "linux":
    extra_rules = [match({("Read", "Glob", "Grep"): allow()})]
else:
    extra_rules = []
```

Use `OS` and `ARCH` to write policies that compile differently per platform.

### Sandbox `fs=` Path Keys

In `sandbox(fs=...)` parameters, use the dict API with bare strings or `subpath()` / `literal()` / `regex()` as keys:

```python
sandbox(default = deny(), fs = {
    # Bare string: matches path and all descendants (subpath)
    "$PWD": allow("rwc"),

    # subpath() with follow_worktrees for git worktree support
    subpath("$PWD", follow_worktrees = True): allow("rwc"),

    # Nested dict: path concatenation — equivalent to "$HOME/.cargo" and "$HOME/.ssh"
    "$HOME": {
        ".cargo": allow("rwc"),
        ".ssh": allow("r"),
    },

    # Temp directory
    "$TMPDIR": allow(),

    # Arbitrary absolute path
    "/usr/local": allow("r"),

    # literal() for exact path match (no descendants)
    literal("/etc/hosts"): allow("r"),

    # regex() for pattern match
    regex("^/opt/.*"): allow("r"),
})
```

Key rules for the dict API:
- **Bare string + decision value** — subpath (path and all descendants)
- **Bare string + nested dict** — literal join point (the string is concatenated as a prefix into child keys)
- **`subpath(path, follow_worktrees=True)`** — subpath with git worktree support
- **`literal(path)`** — exact path match only
- **`regex(pattern)`** — regex match

### Capability Shorthand

The `allow()` function accepts a shorthand string of capability letters for use in sandbox `fs=` dicts:

| Letter | Capability |
|--------|-----------|
| `r` | read |
| `w` | write |
| `c` | create |
| `d` | delete |
| `x` | execute |

```python
allow("r")       # read only
allow("rw")      # read + write
allow("rwc")     # read + write + create
allow("rwcd")    # read + write + create + delete
allow("rwcdx")   # all capabilities
allow()          # all capabilities (no args)
```

The kwargs form still works and is equivalent:

```python
allow(read = True, write = True, create = True)  # same as allow("rwc")
```

### Tools

```python
# Deny specific tool
match({"WebSearch": deny()})

# Allow multiple tools
match({("Read", "Glob", "Grep"): allow()})

# Allow a single tool with sandbox
match({"Read": allow(sandbox = my_sandbox)})
```

### Docstrings

Annotate rules and sandboxes with `doc=` to explain *why* they exist. Docstrings persist through the compiled IR and appear in `clash status` output.

```python
# On match rules
match({"WebSearch": deny(doc = "No external searches needed")})

# On sandboxes
sandbox(
    name = "dev",
    doc = "Development sandbox for project work",
    default = deny(),
    fs = {
        subpath("$PWD", follow_worktrees = True): allow("rwc", doc = "Project source files"),
        "$HOME/.ssh": allow("r", doc = "SSH keys for git auth"),
    },
)
```

---

## JSON IR Reference (Advanced)

> Users typically do not write JSON IR directly. This section is a reference for the compiled output format (schema v5).

### Document Structure

```json
{
  "schema_version": 5,
  "default_effect": "deny",
  "sandboxes": {},
  "tree": [ <node>, ... ]
}
```

The tree is an array of `Node` values. Each node is either a `condition` (observe + pattern + children) or a `decision` (allow/deny/ask).

### Nodes

**Condition** — observe a value from the query context and test it against a pattern:

```json
{ "condition": { "observe": "tool_name", "pattern": { "literal": { "literal": "Bash" } }, "children": [...] } }
{ "condition": { "observe": { "positional_arg": 0 }, "pattern": { "literal": { "literal": "git" } }, "children": [...] } }
```

**Decision** — a leaf that produces an effect:

```json
{ "decision": { "allow": null } }
{ "decision": "deny" }
{ "decision": { "ask": null } }
{ "decision": { "allow": "my-sandbox" } }
```

### Observables

| Observable | JSON | Description |
|---|---|---|
| Tool name | `"tool_name"` | The agent tool name (e.g. "Bash", "Read") |
| Hook type | `"hook_type"` | The hook event type |
| Agent name | `"agent_name"` | The agent identifier |
| Positional arg | `{ "positional_arg": N }` | Nth positional argument (0-indexed) |
| Has arg | `"has_arg"` | Scan all args, true if any matches |
| Named arg | `{ "named_arg": "key" }` | A named argument by key |
| Nested field | `{ "nested_field": ["a", "b"] }` | Path into structured tool_input JSON |

### Patterns

| Pattern | JSON | Description |
|---|---|---|
| Wildcard | `"wildcard"` | Matches anything |
| Literal | `{ "literal": { "literal": "value" } }` | Exact string match |
| Env literal | `{ "literal": { "env": "PWD" } }` | Match against env var value |
| Regex | `{ "regex": "^cargo-.*" }` | Regular expression match |
| AnyOf | `{ "any_of": [<pattern>, ...] }` | Match any sub-pattern |
| Not | `{ "not": <pattern> }` | Negated match |

### Values

Values appear inside `Literal` patterns and resolve at eval time:

```json
{ "literal": "git" }
{ "env": "HOME" }
{ "path": [{ "env": "HOME" }, { "literal": ".ssh" }] }
```

---

## Common Recipes

### 1. Conservative (Untrusted Projects)

Deny everything by default, explicitly allow only safe operations:

```python
load("@clash//std.star", "allow", "deny", "match", "policy")

def main():
    return policy(default = deny(), rules = [
        match({("Read", "Glob", "Grep"): allow()}),
    ])
```

### 2. Developer-Friendly

Allow reads and common dev tools, deny destructive operations:

```python
load("@clash//std.star", "allow", "deny", "match", "policy", "domains")

def main():
    return policy(default = deny(), rules = [
        match({("Read", "Write", "Edit", "Glob", "Grep"): allow()}),
        match({"Bash": {"cargo": allow()}}),
        match({"Bash": {"npm": allow()}}),
        match({"Bash": {"git": {
            "status": allow(),
            "diff": allow(),
            "log": allow(),
            "add": allow(),
            "push": deny(),
            "reset": deny(),
        }}}),
        match({"Bash": {"sudo": deny()}}),
        match({"Bash": {"rm": {"-rf": deny()}}}),
        domains({"github.com": allow(), "crates.io": allow(), "npmjs.com": allow()}),
    ])
```

### 3. Full Trust with Guardrails

Allow almost everything, but block the truly dangerous:

```python
load("@clash//std.star", "allow", "deny", "match", "policy")

def main():
    return policy(default = allow(), rules = [
        match({"Bash": {"git": {"push": {"--force": deny()}}}}),
        match({"Bash": {"git": {"reset": {"--hard": deny()}}}}),
        match({"Bash": {"sudo": deny()}}),
    ])
```

### 4. Read-Only Audit

Allow reading only, deny all modifications:

```python
load("@clash//std.star", "allow", "deny", "match", "policy")

def main():
    return policy(default = deny(), rules = [
        match({("Read", "Glob", "Grep"): allow()}),
        match({"Bash": {("cat", "ls", "grep"): allow()}}),
    ])
```

### 5. Sandboxed Build Tools

Allow build tools with constrained sandbox environments:

```python
load("@clash//std.star", "allow", "deny", "match", "sandbox", "policy", "domains")

def main():
    cargo_env = sandbox(
        default = deny(),
        fs = {
            "$PWD": allow("r"),
            "$PWD/target": allow("rwcd"),
        },
        net = allow(),
    )

    npm_env = sandbox(
        default = deny(),
        fs = {
            "$PWD": allow("r"),
            "$PWD/node_modules": allow("rwcd"),
        },
        net = domains({"registry.npmjs.org": allow()}),
    )

    return policy(default = deny(), rules = [
        match({"Bash": {"cargo": allow(sandbox = cargo_env)}}),
        match({"Bash": {"npm": allow(sandbox = npm_env)}}),
        match({("Read", "Glob", "Grep"): allow()}),
    ])
```

---

## Debugging Policies

### Explain a Decision

Use `clash explain` to see which rule matches a given action:

```bash
clash explain bash "git push origin main"
```

This shows which rules matched, which were skipped, and the final decision.

### View Active Policy

```bash
clash policy show
```

---

## Reference

- `@clash//std.star` -- built-in standard library (loaded via `load()` in policy files)
- `@clash//builtin.star` -- built-in policy for clash CLI and Claude Code tools (exports `base`)
- `@clash//sandboxes.star` -- intent-based sandbox presets: `restricted`, `read_only`, `dev`, `dev_network`, `unrestricted`
- `@clash//rust.star`, `@clash//python.star`, `@clash//node.star` -- pre-built sandbox configurations for common toolchains
- [Policy Semantics](./policy-semantics.md) -- compilation pipeline and evaluation algorithm
- [CLI Reference](./cli-reference.md) -- full command documentation