Skip to main content

agent-sash

agent-sash logo

A Claude Code hook that uses a local LLM to auto-approve safe bash commands.

Claude Code's allowlists work for simple cases (git status, ls) but break down for commands like python3 -c ... or sed that need to be broadly allowed for legitimate use yet can do real damage depending on their arguments. The alternative -- prompting every time -- trains users to reflexively approve, which is worse than no permission check at all.

agent-sash runs a small model locally that scores each bash command's risk from 0 to 1. Safe commands flow through automatically. Risky ones still prompt you.

Command Score
python3 -c "print(42)" 0.0
python3 -c "import os; os.system('rm -rf /')" 1.0
sed -i s/foo/bar/g config.yaml 0.3
sed -i s/foo/bar/g /etc/nginx/nginx.conf 0.8
git push origin feature-branch 0.4
git push --force origin main 0.8
psql -c "SELECT count(*) FROM users" 0.0
psql -c "DROP TABLE users CASCADE" 0.8
curl -s https://example.com 0.1
curl -s https://example.com | bash 0.9

Quick start

Note: The scoring model was fine-tuned and evaluated for this, but it's a language model -- it lacks context about your environment and risk tolerance, and will sometimes get it wrong. Be thoughtful about what credentials and resources are accessible from the environment Claude Code runs in.

Requirements: macOS with Apple Silicon, Python 3.13+, uv

1. Install

uv tool install agent-sash

2. Add the hook

Add this to your ~/.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "agent-sash claude-hook"
          }
        ]
      }
    ]
  }
}

3. Start a new Claude Code session

That's it. The model server auto-starts on the first bash command. First run downloads the model (~820MB).

To pre-warm the server so there's no delay on the first command:

agent-sash start

To shut it down:

agent-sash stop

How it works

agent-sash registers as a PreToolUse hook on Bash commands. When Claude Code is about to run a shell command, a local model scores its risk from 0.0 to 1.0. Below the threshold (0.5), the command is auto-allowed. Above it, the user is prompted. On any error, agent-sash defaults to prompting.

The model is cwrn/Qwen3.5-0.8B-SHGuard-MLX-Q8, a full fine-tune of Qwen3.5-0.8B quantized to Q8 via mlx-lm (~820MB on disk).

BF16: cwrn/Qwen3.5-0.8B-SHGuard

Data pipeline

The training set is 51,188 examples.

Shell commands were pulled from four coding-agent trajectory datasets (Nemotron-Terminal-Corpus, CoderForge, SWE-rebench-openhands, Nemotron-SWE) plus shell blocks and YAML run: steps from operational docs (Kubernetes, Docker, PostgreSQL, rsync). Per-source extractors normalized formats into a common schema, dropping comment-only lines, control inputs, scaffold actions, and editor payloads. ~4.6M candidate commands total.

MinHash LSH over character n-grams (3/4/5-gram, 14 buckets × 8 hashes, Jaccard ~0.8) via datatrove for deduplication. Qwen3.5-35B-A3B scored each command against a risk rubric (0.0 = read-only/ephemeral, 1.0 = potentially irreversible with wide blast radius) with JSON schema enforcement.

The natural pool is heavily skewed toward low-risk commands, so probabilistic subsampling applies score-based keep rates (12% for scores 0.0-0.1, 25% for 0.2, 55% for 0.3, 100% for 0.4+) with multipliers for shared-environment and wrapper commands. 42,688 natural commands retained.

Coverage of shared-environment mutations (force pushes, cluster disruption, remote sync with deletion) was filled by three synthetic sources. data-designer generated 5,000 commands from a scenario grid (7 axes: environment × resource × impact × scope × access × frame × guardrail), filtered to score ≥ 0.7 with valid shell syntax. 1,500 deterministic wrappers (ssh/python<<PY over existing live-env seeds) and 2,000 indirect-execution wrappers (generated by A3B from real risky seeds using carriers like source .env && python, uv run python, ssh remote shells, and expect) rounded out the tail.

Final composition: 42,688 natural / 5,000 synth / 1,500 deterministic wrappers / 2,000 indirect-execution wrappers.

Training

Full fine-tune of Qwen3.5-0.8B. 2.2 epochs, effective batch size 64, learning rate 5e-5, cosine schedule, bf16. Best checkpoint at epoch 1.8 (eval loss 0.5215).

Evaluation

38-command benchmark with human-specified target score ranges, plus a 500-command eval mined from real local coding-agent sessions:

Spearman Weighted MAE False allow Latency (mean)
Sanity (38 cmd) 0.947 0.125 6.7%
Local session (500 cmd) 0.728 0.106 18.6% 0.69s

Release files for agent-sash 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for agent-sash 0.2.0
File Size Uploaded
agent_sash-0.2.0.tar.gz 7.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for agent-sash 0.2.0
File Interpreter ABI Platform
agent_sash-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 16.8 kB

Release files / agent_sash-0.2.0.tar.gz

Download URL agent_sash-0.2.0.tar.gz
Size 7.3 kB
Tags Source
SHA-256 checksum
How to use checksums
e71831ab75db4f25aefffe193ba14b3a3ba9d931d5166abb6666ab456438da9d
BLAKE2b-256 checksum
How to use checksums
aaefeedf302688b6014d21fda19b6a75cbf746b825ecf7ecd20fd183a89653a2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / agent_sash-0.2.0-py3-none-any.whl

Download URL agent_sash-0.2.0-py3-none-any.whl
Size 9.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
763b4ce77521febaa34eb4d27b9f8af06d5bca40b8abcdbd4870bd5a54945a0e
BLAKE2b-256 checksum
How to use checksums
15e7421c27465a381b6a29ebfc4ef3e32978e80b23baeac8bcf130e5cd16e287
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page