Command Line Agent Safety Harness
Stop babysitting your coding agent, go touch grass.
Important
Clash is under heavy development. It's being used by engineers at Empathic and is quite productive, but the API is not stable and is subject to change. Please report bugs!
Clash is designed to be agent-agnostic — a universal safety harness for any coding agent that executes tools on your behalf. The policy language and capability model are agent-independent; only the integration layer is specific to each agent.
| Agent | Status | Tracking |
|---|---|---|
| Claude Code | Supported | — |
| Codex CLI | Planned | #195 |
| Gemini CLI | Planned | #196 |
| OpenCode | Planned | #197 |
Currently, the Claude Code integration is the most mature. If you'd like to help bring Clash to another agent, contributions are welcome!
Coding agents operate with broad tool access — executing commands, editing files, and making network requests on your behalf. Their permission models tend to be all-or-nothing: either you allow a tool entirely or get prompted every time. You end up clicking "yes" hundreds of times a session, or giving blanket approval and hoping for the best.
Clash gives you granular control. Write policy rules that decide what to allow, deny, or ask about — then let the agent work freely on safe operations while blocking dangerous ones. On Linux, rules can generate kernel-enforced filesystem sandboxes so even allowed commands can only touch the files you specify.
There are two ways to run clash depending on what you're doing:
curl -fsSL https://raw.githubusercontent.com/empathic/clash/main/install.sh | bash
clash init
claudeThis downloads the latest release binary to ~/.local/bin/ (Apple Silicon Mac, Linux x86_64, Linux aarch64). On Intel Mac or other platforms, install via Cargo:
cargo install clashclash init writes a default policy, installs the Claude Code plugin from GitHub, installs the status line, and walks you through initial configuration. After init, every claude session automatically loads clash.
If you have the repo checked out, you can also use just install which registers the plugin from the local source tree instead of GitHub.
just devThis builds the binary, symlinks it into the source plugin directory, and launches a one-off Claude Code session with the plugin loaded directly from source. Changes to skills, hooks, or Rust code take effect on the next just dev — no install step needed.
Once clash is running inside Claude Code, you have access to slash commands (skills) for managing your policy without leaving your session:
| Skill | What it does |
|---|---|
/clash:onboard |
Interactively build your policy from scratch |
/clash:edit |
Guided editing of your policy file |
/clash:status |
Show current policy, rules, and enforcement status |
/clash:describe |
Plain-English description of your active policy |
/clash:explain |
See which rule matches a specific tool invocation |
/clash:allow |
Quickly add an allow rule |
/clash:deny |
Quickly add a deny rule |
/clash:test |
Test your policy against hypothetical tool uses |
/clash:audit |
View recent permission decisions from the audit log |
If you're new, start with /clash:onboard — it walks you through creating a policy tailored to your workflow.
Policies use s-expression syntax: (effect (capability ...)). Clash reads them on every tool invocation, so edits take effect immediately — no restart needed.
Clash supports three policy levels, each automatically included and evaluated in order of precedence:
| Level | Location | Purpose |
|---|---|---|
| User | ~/.clash/policy.sexpr |
Your personal defaults across all projects |
| Project | <project>/.clash/policy.sexpr |
Shared rules for a specific repository |
| Session | Created via --scope session |
Temporary overrides for the current session |
Layer precedence: Session > Project > User. Higher layers can shadow rules from lower layers — for example, a project-level deny overrides a user-level allow for the same capability. Use clash status to see all active layers and which rules are shadowed.
; ~/.clash/policy.sexpr (user level)
(default ask "main")
(policy "main"
(include "cwd-access")
(allow (exec "cargo" *)) ; let it run cargo commands
(allow (exec "git" *)) ; let it run git commands
(deny (exec "git" "push" *)) ; never allow push
(deny (exec "git" "reset" "--hard" *))
(allow (net "github.com"))) ; allow github.com access
(policy "cwd-access"
(allow (fs read (subpath (env PWD))))
(allow (fs (or write create) (subpath (env PWD)))))Effects: allow (auto-approve), deny (block), ask (prompt you)
Capabilities: exec (commands), fs (filesystem), net (network)
Precedence: deny always wins. More specific rules beat less specific. Within the same specificity, ask beats allow. Higher layers shadow lower layers at the same specificity. See Policy Semantics for the full algorithm.
Rules are organized into named policy blocks that can include other blocks, letting you compose reusable layers:
(policy "readonly"
(allow (fs read (subpath (env PWD)))))
(policy "main"
(include "readonly") ; import rules from other blocks
(allow (exec "git" *)))Allowed exec rules can carry sandbox constraints that clash compiles into OS-enforced sandboxes (Landlock on Linux, Seatbelt on macOS):
(allow (exec "cargo" *)
(sandbox "cargo-sandbox"))
(sandbox "cargo-sandbox"
(fs read (subpath (env PWD)))
(fs write (subpath "./target"))
(net allow))Even if a command is allowed by policy, the sandbox ensures it can only access the paths you specify.
Note: Exec rules (like
(deny (exec "git" "push" *))) apply to the top-level command Claude runs. If an allowed command spawns a subprocess that runs a denied command, the exec rule does not fire. Kernel sandbox restrictions on filesystem and network access do apply to all child processes. See #136 for tracking deeper exec enforcement.
For the full rule syntax, see the Policy Writing Guide.
clash init # set up clash with a safe default policy
clash allow bash # allow command execution
clash allow edit # allow file editing in project
clash allow web # allow web access
clash deny '(exec "rm" *)' # deny rm commands
clash ask bash # require approval for bash commands
clash status # see all layers, rules, and shadowing
clash doctor # diagnose common setup issues
clash update # update clash to the latest release
clash update --check # check for updates without installing
clash explain bash "git push" # see which rule matches a command
clash policy list # list all rules with level tags
clash policy remove '(deny (exec "rm" *))' # remove a rule
clash edit # interactive policy editorFor the full command reference, see the CLI Reference.
Clash can display a live scoreboard in Claude Code's status bar, giving you ambient visibility into policy enforcement without interrupting your workflow.
⚡clash ✓12 ✗3 ?1 · ✗ Bash(touch ...)
allow with: clash allow '(exec "touch" *)'
The status line shows:
- Counts:
✓allowed,✗denied,?asked — color-coded green/red/yellow - Last action: the most recent policy decision with tool name and input summary
- Allow hint: when the last action was denied, a second line shows the narrowest rule to allow it
clash statusline install # add status line to Claude Code settings
clash statusline uninstall # remove itAfter installing, the status line appears automatically in your next Claude Code session.
- macOS (Apple Silicon or Intel) or Linux (x86_64 or aarch64)
- A supported coding agent installed
- Rust toolchain (for building from source)
- Windows is not supported
Run clash doctor to automatically diagnose common setup issues:
clash doctorIt checks policy files, plugin registration, PATH, file permissions, and sandbox support, reporting actionable fix instructions for each problem.
Make sure the install directory is on your PATH:
# If installed via the install script
export PATH="$HOME/.local/bin:$PATH"
# If installed via cargo
export PATH="$HOME/.cargo/bin:$PATH"This means Claude Code's built-in permissions are still active. Re-run init — it sets bypassPermissions: true in your Claude Code user settings by default so clash is the sole permission handler:
clash initUse clash explain to see exactly which rule matches:
clash explain bash "git push origin main"Or use the /clash:explain skill inside Claude Code for an interactive walkthrough.
If every tool use is being denied with a "policy failed to compile" message, your policy file has a syntax error. Clash blocks all actions when it can't compile the policy rather than silently degrading.
To diagnose:
clash policy validateThis will show which policy file has the error and suggest how to fix it. If you want to start fresh:
clash initYou're always in control of whether clash is active.
CLASH_DISABLE=1 claudeClash stays installed but becomes a complete pass-through — no policy enforcement, no sandbox, no prompts. clash status and the status line will reflect the disabled state. Set CLASH_DISABLE=0 or unset the variable to re-enable.
# 1. Remove the Claude Code plugin
claude plugin uninstall clash
# 2. Remove the binary
cargo uninstall clash # if installed via cargo
rm -f ~/.local/bin/clash # if installed via the install script
# 3. (Optional) Remove the plugin marketplace entry
claude plugin marketplace remove clash
# 4. (Optional) Remove the status line — only needed if you skipped step 2
clash statusline uninstall
# 5. (Optional) Clean up configuration and logs
rm -rf ~/.clash # user-level policy and logs
rm -rf .clash # project-level policy (per repo)After removing the plugin, Claude Code reverts to its built-in permission model. Policy files are left in place so you can pick up where you left off if you reinstall.
- Policy Writing Guide — rules, profiles, constraints, and recipes
- CLI Reference — all commands, flags, and options
- Policy Grammar — formal EBNF grammar
- Policy Semantics — evaluation algorithm and sandbox generation
Clash integrates with coding agents via their plugin or extension system. For each supported agent, an integration layer intercepts tool calls and evaluates them against your policy before the agent executes them.
Agent → integration hook → clash binary → policy evaluation → allow / deny / ask
Claude Code (current integration): The plugin lives in clash-plugin/ and registers hooks that intercept every tool call. It consists of hook definitions, skill definitions (slash commands), and the clash binary. In dev mode, just dev symlinks the freshly-built binary into clash-plugin/bin/ and points Claude Code at the source directory. In install mode, just install stages a self-contained copy and registers it via the marketplace.
just dev # build + launch Claude Code with plugin from source
just install # build + install system-wide via marketplace
just uninstall # remove installed plugin and binary
just check # fmt + test + clippy
just clester # end-to-end tests (YAML-based hook simulation)
just ci # full CI (check + clester)
just release 0.4.0 # bump versions, commit, tag (push to trigger release)clash/
├── clash/ # CLI binary + library (Rust)
├── clash-plugin/ # Claude Code plugin (hooks, skills, bin/)
├── clash_notify/ # Notification support (desktop, Zulip)
├── claude_settings/ # Claude Code settings library
├── clester/ # End-to-end test harness
└── docs/ # Documentation
Apache License 2.0