{"id":46186920,"url":"https://github.com/empathic/clash","last_synced_at":"2026-04-01T17:40:45.850Z","repository":{"id":337886020,"uuid":"1143689356","full_name":"empathic/clash","owner":"empathic","description":"Command Line Agent Safety Harness. Stop babysitting your agents, go touch grass.","archived":false,"fork":false,"pushed_at":"2026-03-30T21:17:26.000Z","size":4987,"stargazers_count":24,"open_issues_count":51,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-30T22:22:57.043Z","etag":null,"topics":["agent","ai","claude-code"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/empathic.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-01-27T22:10:52.000Z","updated_at":"2026-03-30T20:45:12.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/empathic/clash","commit_stats":null,"previous_names":["empathic/clash"],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/empathic/clash","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/empathic%2Fclash","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/empathic%2Fclash/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/empathic%2Fclash/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/empathic%2Fclash/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/empathic","download_url":"https://codeload.github.com/empathic/clash/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/empathic%2Fclash/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31290539,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent","ai","claude-code"],"created_at":"2026-03-02T23:02:11.866Z","updated_at":"2026-04-01T17:40:45.801Z","avatar_url":"https://github.com/empathic.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# clash\n\n**C**ommand **L**ine **A**gent **S**afety **H**arness\n\nStop babysitting your coding agent, go touch grass.\n\n---\n\u003e [!IMPORTANT]\n\u003e 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!\n\n## Agent Support\n\nClash 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.\n\n| Agent | Status | Tracking |\n|-------|--------|----------|\n| [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | **Supported** | — |\n| [Gemini CLI](https://github.com/google-gemini/gemini-cli) | **Protocol ready** | [#196](https://github.com/empathic/clash/issues/196) |\n| [Codex CLI](https://github.com/openai/codex) | **Protocol ready** | [#195](https://github.com/empathic/clash/issues/195) |\n| [Amazon Q CLI](https://github.com/aws/amazon-q-developer-cli) | **Protocol ready** | — |\n| [OpenCode](https://github.com/opencode-ai/opencode) | **Protocol ready** | [#197](https://github.com/empathic/clash/issues/197) |\n| [Copilot CLI](https://github.com/github/copilot-cli) | **Protocol ready** | — |\n\nClaude Code is the most mature integration. The other 5 agents have protocol adapters (hook JSON parsing/formatting), extension packages, and `--agent` flag support throughout the CLI. Use `clash init --agent \u003cname\u003e` to set up any supported agent.\n\n---\n\n## The Problem\n\nCoding 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.\n\nClash 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. Rules can carry OS-enforced sandboxes (Landlock on Linux, Seatbelt on macOS) so even allowed commands can only touch the files you specify.\n\n---\n\n## Quick Start\n\nThere are two ways to run clash depending on what you're doing:\n\n### Install (use clash in your day-to-day work)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/empathic/clash/main/install.sh | bash\nclash init\nclaude\n```\n\nThis 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:\n\n```bash\ncargo install clash\n```\n\n`clash init` writes a default `.star` policy (or `.json`), 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.\n\nIf you have the repo checked out, you can also use `just install` which registers the plugin from the local source tree instead of GitHub.\n\n### Develop (hack on clash itself)\n\n```bash\njust dev\n```\n\nThis builds the binary and launches a one-off Claude Code session with the plugin loaded directly from source. Changes to hooks or Rust code take effect on the next `just dev` — no install step needed.\n\n---\n\n## Policy Rules\n\nPolicies are written in **Starlark** (`.star`), a Python-like configuration language that compiles to JSON IR. Clash reads policies on every tool invocation, so edits take effect immediately — no restart needed.\n\nYou can also write policies directly in JSON if you prefer — see the [Policy Writing Guide](docs/policy-guide.md) for the JSON schema.\n\n### Policy Layers\n\nClash supports three policy levels, each automatically included and evaluated in order of precedence:\n\n| Level | Location | Purpose |\n|-------|----------|---------|\n| **User** | `~/.clash/policy.json` (or `.star`) | Your personal defaults across all projects |\n| **Project** | `\u003cproject\u003e/.clash/policy.json` (or `.star`) | Shared rules for a specific repository |\n| **Session** | Created via `--scope session` | Temporary overrides for the current session |\n\n\u003e **Note:** Both `.json` and `.star` are supported. When both exist at the same level, `.json` takes precedence. CLI commands (`clash policy allow/deny/remove`) operate on `policy.json`.\n\n**Layer precedence:** Session \u003e Project \u003e 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.\n\n### Example\n\n```python\n# ~/.clash/policy.star\nload(\"@clash//std.star\", \"match\", \"policy\", \"sandbox\", \"subpath\", \"allow\", \"deny\", \"ask\")\n\ndef main():\n    cwd_access = sandbox(\n        name = \"cwd_access\",\n        default = deny(),\n        fs = {\n            subpath(\"$PWD\", follow_worktrees = True): allow(\"rwc\"),\n        },\n    )\n    return policy(\n        default = ask(),\n        rules = [\n            match({\"Bash\": {\n                (\"cargo\", \"git\"): allow(sandbox = cwd_access),\n            }}),\n        ],\n    )\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eEquivalent JSON IR\u003c/summary\u003e\n\n```json\n{\n  \"schema_version\": 5,\n  \"default_effect\": \"ask\",\n  \"sandboxes\": { \"cwd_access\": { \"name\": \"cwd_access\", \"default\": [\"execute\"], \"rules\": [...], \"network\": \"deny\" } },\n  \"tree\": [\n    { \"condition\": { \"observe\": \"tool_name\", \"pattern\": { \"literal\": { \"literal\": \"Bash\" } },\n        \"children\": [\n          { \"condition\": { \"observe\": { \"positional_arg\": 0 }, \"pattern\": { \"any_of\": [\n                { \"literal\": { \"literal\": \"cargo\" } },\n                { \"literal\": { \"literal\": \"git\" } }\n              ] },\n              \"children\": [{ \"decision\": { \"allow\": \"cwd_access\" } }] } }\n        ] } }\n  ]\n}\n```\n\n\u003c/details\u003e\n\n**Effects:** `allow` (auto-approve), `deny` (block), `ask` (prompt you)\n\n**Capabilities:** `exec` (commands), `fs` (filesystem), `net` (network)\n\n**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](docs/policy-semantics.md) for the full algorithm.\n\n### Reusable Sandboxes\n\nStarlark replaces JSON's named policy blocks and `include` with standard `load()` imports and function composition:\n\n```python\nload(\"@clash//rust.star\", \"rust_sandbox\")\nload(\"@clash//std.star\", \"match\", \"policy\", \"sandbox\", \"allow\", \"deny\")\n\ndef main():\n    git_sandbox = sandbox(\n        name = \"git\",\n        default = deny(),\n        fs = {\n            \"$PWD\": allow(\"r\"),\n        },\n    )\n    return policy(\n        default = deny(),\n        rules = [\n            match({\"Bash\": {\n                (\"rustc\", \"cargo\"): allow(sandbox = rust_sandbox),\n                \"git\": allow(sandbox = git_sandbox),\n            }}),\n        ],\n    )\n```\n\nThe `@clash//` prefix loads from the built-in standard library, which includes sandboxes for common toolchains (`rust.star`, `node.star`, `python.star`).\n\n### Kernel Sandbox\n\nExec rules can carry sandbox constraints that clash compiles into OS-enforced sandboxes (Landlock on Linux, Seatbelt on macOS):\n\n```python\nload(\"@clash//std.star\", \"match\", \"policy\", \"sandbox\", \"allow\", \"deny\")\n\ndef main():\n    cargo_box = sandbox(\n        name = \"cargo\",\n        default = deny(),\n        fs = {\n            \"$PWD\": allow(\"r\"),\n            \"$PWD/target\": allow(\"rwcd\"),\n            \"$TMPDIR\": allow(),\n        },\n        net = allow(),\n    )\n    return policy(default = deny(), rules = [\n        match({\"Bash\": {\"cargo\": allow(sandbox = cargo_box)}}),\n    ])\n```\n\nEven if a command is allowed by policy, the sandbox ensures it can only access the paths you specify.\n\n\u003e **Note:** Exec rules 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](https://github.com/empathic/clash/issues/136) for tracking deeper exec enforcement.\n\nFor the full rule syntax, see the [Policy Writing Guide](docs/policy-guide.md).\n\n### Examples\n\nSee the [`examples/`](examples/) directory for ready-to-use policies:\n\n- **[rust-dev.star](examples/rust-dev.star)** — Rust development with cargo sandboxing\n- **[node-dev.star](examples/node-dev.star)** — Node.js development with npm/bun\n- **[python-dev.star](examples/python-dev.star)** — Python development with pip/uv\n- **[paranoid.star](examples/paranoid.star)** — Maximum security, read-only access\n- **[permissive.star](examples/permissive.star)** — Minimal friction, common tools allowed\n\n---\n\n## Useful Commands\n\n```bash\nclash init                       # set up clash with a safe default policy\nclash status                     # see all layers, rules, and enforcement status\nclash doctor                     # diagnose common setup issues\nclash update                     # update clash to the latest release\nclash explain bash \"git push\"    # see which rule matches a command\nclash policy list                # list all rules with level tags\nclash policy validate            # validate policy syntax\nclash policy edit                # open the interactive policy editor\nclash policy allow \"gh pr create\"  # allow a command\nclash policy deny --bin rm         # deny a binary\nclash policy remove --tool Read    # remove a rule\nclash sandbox create dev           # create a named sandbox\nclash sandbox add-rule dev ./src   # add a sandbox filesystem rule\nclash playground                 # interactive policy sandbox for testing rules\nclash shell                      # sandboxed shell with per-command enforcement\nclash debug log                  # view audit log entries\nclash trace export               # export session trace as JSON\nclash session list               # list recent sessions\n```\n\nFor the full command reference, see the [CLI Reference](docs/cli-reference.md).\n\n---\n\n## Status Line\n\nClash can display a live scoreboard in Claude Code's status bar, giving you ambient visibility into policy enforcement without interrupting your workflow.\n\n```\n⚡clash ✓12 ✗3 ?1 · ✗ Bash(touch ...)\n```\n\nThe status line shows:\n\n- **Counts**: `✓` allowed, `✗` denied, `?` asked — color-coded green/red/yellow\n- **Last action**: the most recent policy decision with tool name and input summary\n\n### Setup\n\n```bash\nclash statusline install     # add status line to Claude Code settings\nclash statusline uninstall   # remove it\n```\n\nAfter installing, the status line appears automatically in your next Claude Code session.\n\n---\n\n## Requirements\n\n- **macOS** (Apple Silicon or Intel) or **Linux** (x86_64 or aarch64)\n- A [supported coding agent](#agent-support) installed\n- Rust toolchain (for building from source)\n- Windows is **not** supported\n\n---\n\n## Troubleshooting\n\nRun `clash doctor` to automatically diagnose common setup issues:\n\n```bash\nclash doctor\n```\n\nIt checks policy files, plugin registration, PATH, file permissions, and sandbox support, reporting actionable fix instructions for each problem.\n\n### \"command not found: clash\"\n\nMake sure the install directory is on your `PATH`:\n\n```bash\n# If installed via the install script\nexport PATH=\"$HOME/.local/bin:$PATH\"\n\n# If installed via cargo\nexport PATH=\"$HOME/.cargo/bin:$PATH\"\n```\n\n### Policy not working as expected\n\nUse `clash explain` to see exactly which rule matches:\n\n```bash\nclash explain bash \"git push origin main\"\n```\n\n### All actions blocked — policy error\n\nIf 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.\n\nTo diagnose:\n\n```bash\nclash policy validate\n```\n\nThis will show which policy file has the error and suggest how to fix it. If you want to start fresh:\n\n```bash\nclash init\n```\n\n---\n\n## Disabling \u0026 Uninstalling\n\nYou're always in control of whether clash is active.\n\n### Disable for one session\n\n```bash\nCLASH_DISABLE=1 claude\n```\n\nClash 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.\n\n### Uninstall completely\n\n```bash\nclash uninstall\n```\n\nThis removes bypass permissions, the Claude Code plugin, the status line, policy files (`~/.clash/`), and the binary itself — regardless of how clash was installed. Use `clash uninstall -y` to skip confirmation prompts.\n\nAfter uninstalling, Claude Code reverts to its built-in permission model.\n\n---\n\n## Documentation\n\n- [Policy Writing Guide](docs/policy-guide.md) — rules, profiles, constraints, and recipes\n- [CLI Reference](docs/cli-reference.md) — all commands, flags, and options\n- [Policy Semantics](docs/policy-semantics.md) — evaluation algorithm and sandbox generation\n\n---\n\n## Development\n\n### How it works\n\nClash 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.\n\n```\nAgent → integration hook → clash binary → policy evaluation → allow / deny / ask\n```\n\n**Claude Code** (current integration): The plugin lives in `clash-plugin/` and registers hooks that intercept every tool call. Hook definitions in `hooks/hooks.json` handle PreToolUse, PostToolUse, PermissionRequest, Notification, and SessionStart events — all delegating to the `clash` binary. In dev mode, `just dev` builds the binary and launches Claude Code with the plugin loaded from source. In install mode, `just install` registers the plugin via the Claude Code marketplace.\n\n### Recipes\n\n```bash\njust dev         # build + launch Claude Code with plugin from source\njust install     # build + install system-wide via marketplace\njust uninstall   # remove installed plugin and binary\njust check       # fmt + test + clippy\njust clester     # end-to-end tests (YAML-based hook simulation)\njust ci          # full CI (check + clester)\njust release 0.4.0  # bump versions, commit, tag (push to trigger release)\n```\n\n### Project Structure\n\n```\nclash/\n├── clash/                    # CLI binary + library (Rust)\n├── clash_starlark/           # Starlark policy evaluator (.star → JSON IR)\n├── clash-plugin/             # Claude Code plugin (hooks)\n├── clash-brush-core/         # Sandboxed shell core engine\n├── clash-brush-parser/       # Shell command parser\n├── clash-brush-builtins/     # Shell built-in commands\n├── clash-brush-interactive/  # Interactive shell (REPL)\n├── clash_notify/             # Notification support (desktop, Zulip)\n├── claude_settings/          # Claude Code settings library\n├── clester/                  # End-to-end test harness\n└── docs/                     # Documentation\n```\n\n---\n\n## License\n\nApache License 2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fempathic%2Fclash","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fempathic%2Fclash","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fempathic%2Fclash/lists"}