You are viewing v0.4.0. Switch to v0.4.5 (latest release).

clash

Stop babysitting your agents, go touch grass.

Command Line Agent Safety Harness

curl -fsSL https://raw.githubusercontent.com/empathic/clash/main/install.sh | bash
clash init
claude

The problem

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.

Three concepts

Rule

An effect paired with a capability matcher. exe("git").allow() lets the agent run any git command. exe("git", args=["push"]).deny() blocks pushes. Rules use first-match semantics — put specific rules before broad ones.

Domain

Rules target one of three capability domains: exec (shell commands), fs (file operations), and net (network access). Clash speaks in capabilities, not tool names — a single rule can cover multiple agent tools.

Layer

Policies stack in three levels: User (personal defaults), Project (repo-specific rules), and Session (temporary overrides). Higher layers shadow lower layers. Session > Project > User.

Without Clash vs. with Clash

Without Clash With Clash
Click "yes" hundreds of times per session Auto-approve safe operations, block dangerous ones
All-or-nothing tool permissions Granular rules by command, file path, and domain
No visibility into what the agent is doing Status line shows live allow/deny/ask counts
Trust the agent with everything or nothing Kernel-enforced sandboxes constrain even allowed commands
Same permissions for every project Per-project and per-session policy layers

A minimal policy

# ~/.clash/policy.star (user level)
load("@clash//builtin.star", "base")
load("@clash//std.star", "exe", "policy", "cwd", "domains")

def main():
    my_rules = policy(default = ask, rules = [
        cwd(follow_worktrees = True).allow(read = True, write = True),
        exe("cargo").allow(),
        exe("git", args = ["push"]).deny(),
        exe("git", args = ["reset", "--hard"]).deny(),
        exe("git").allow(),
        domains({"github.com": allow}),
    ])
    return my_rules.merge(base)
Compiled JSON IR
{
  "schema_version": 5,
  "default_effect": "ask",
  "sandboxes": {},
  "tree": [
    { "condition": { "observe": "tool_name", "pattern": { "literal": { "literal": "Bash" } },
        "children": [
          { "condition": { "observe": { "positional_arg": 0 }, "pattern": { "literal": { "literal": "cargo" } },
              "children": [{ "decision": { "allow": null } }] } },
          { "condition": { "observe": { "positional_arg": 0 }, "pattern": { "literal": { "literal": "git" } },
              "children": [
                { "condition": { "observe": { "positional_arg": 1 }, "pattern": { "literal": { "literal": "push" } },
                    "children": [{ "decision": "deny" }] } },
                { "condition": { "observe": { "positional_arg": 1 }, "pattern": { "literal": { "literal": "reset" } },
                    "children": [
                      { "condition": { "observe": { "positional_arg": 2 }, "pattern": { "literal": { "literal": "--hard" } },
                          "children": [{ "decision": "deny" }] } }
                    ] } },
                { "decision": { "allow": null } }
              ] } }
        ] } }
  ]
}

Three effects: allow auto-approves, deny blocks, ask prompts you. First matching rule wins — put specific rules before broad ones. Edits take effect immediately — no restart needed.

Quick start

  1. Install clash
    curl -fsSL https://raw.githubusercontent.com/empathic/clash/main/install.sh | bash
    Downloads the latest release binary for your platform (Apple Silicon Mac, Linux x86_64, Linux aarch64). On Intel Mac: cargo install clash.
  2. Initialize
    clash init
    Writes a default policy, installs the Claude Code plugin, configures the status line, and walks you through initial setup.
  3. Launch your agent
    claude
    Every Claude Code session now loads clash automatically. Use /clash:status inside a session to see your policy in action.

Agent support

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
Claude Code Supported
Codex CLI Planned
Gemini CLI Planned
OpenCode Planned

Currently, the Claude Code integration is the most mature. If you'd like to help bring Clash to another agent, contributions are welcome.

How it works

Agent hook clash allow deny ask

Clash integrates via the agent's plugin system. For Claude Code, a plugin registers hooks that intercept every tool call. Each invocation is evaluated against your policy and returns an allow, deny, or ask decision — before the agent executes anything.

The policy is read on every tool call, so edits take effect immediately. On Linux, allowed exec rules can generate Landlock sandboxes; on macOS, Seatbelt profiles constrain filesystem and network access at the kernel level.