Aperion Shield · v0.3.0 · Developer One-Pager

Local guardrails for AI coding agents,
in 60 seconds.

A 1.2 MB binary that sits between Cursor / Claude Code and the real MCP servers your agent talks to (Postgres, GitHub, shell, filesystem...). Inspects every tools/call against 45 adaptive rules, blocks the destructive ones, prompts you for the high-risk ones, and lets the other 98% through. No cloud, no telemetry, Apache 2.0.

 Apache 2.0  45 rules · 8 surfaces  macOS · Linux · Windows  95 tests · 0 dependencies on the call path
Validated against 12,912 real Cursor commands
98.42%
Allow
0.02%
Warn
1.48%
Approval
0.08%
Block
Install (pick one)
 Homebrew
brew install \
  AperionAI/tap/aperion-shield
 Docker
docker pull \
  ghcr.io/aperionai/shield:shield-v0.3.0
 Cargo / Pre-built
cargo install aperion-shield
# or grab a binary tarball from
# github.com/AperionAI/shield/releases
60-second integration
01
Wrap any MCP server with Shield in ~/.cursor/mcp.json
Cursor
Shield speaks MCP over stdio. Put it as the program, push the real MCP server after --:
// ~/.cursor/mcp.json { "mcpServers": { "postgres": { "command": "aperion-shield", "args": [ "--rules", "~/.shield/shieldset.yaml", // optional; bundled defaults are used otherwise "--", "npx", "@modelcontextprotocol/server-postgres", "postgres://user:pass@host:5432/db" ] } } }
Same shape works for Claude Code (~/.claude/config.json). On the first run from a clean shell, drop --shadow in args to observe-only for a week, then remove it to enforce.
How it sees the traffic
Cursor / Claude Code JSON-RPC over stdio ┌────────────────────────────────────────────────────────────┐ aperion-shield ← shieldset.yaml (45 rules) intercepts tools/call ┌──────────────────────────────────────────────────────┐ rules → matches → composite score + workspace_is_prod bump severity + fingerprint_recent_deny bump severity + burst_in_progress bump severity - fingerprint_repeated_ok demote severity → final severity → Allow │ Warn │ Approval │ Block └──────────────────────────────────────────────────────┘ └────────────────────────────────────────────────────────────┘ real upstream MCP server (postgres, github, shell, fs, …)
What it catches
02
Tool-call surface
tools/call
SQL (9): DROP DATABASE, DROP TABLE, TRUNCATE, ALTER … DROP COLUMN, unscoped UPDATE/DELETE, GRANT ALL, REVOKE FROM PUBLIC, Postgres COPY FROM PROGRAM, MySQL LOAD DATA INFILE.
Git (5): force-push to protected branches, history rewrites, push --mirror --force, branch -D, checkout ..
Filesystem (6): rm -rf /, writes/deletes inside sensitive paths (/etc, ~/.ssh, ~/.aws, /usr/local/bin, …), dd to a block device, find … -delete sweeps, world-writable chmod, recursive chown root.
Secrets exfil (3): read-secret + post-to-network in one chain, raw SSH/AWS key reads, kubectl get secret … | base64 -d dumps.
Supply chain (2): curl | sh and family, untrusted npm/pip/cargo registries.
Shells / Privilege (3): reverse-shell incantations across bash/nc/python/perl/ruby/openssl/socat/PowerShell, sudo-prefixed destruction, setuid grants.
Cloud / k8s / Docker (11): aws s3 rm --recursive, RDS deletes without snapshot, terraform destroy -auto-approve, kubectl delete namespace, helm uninstall, docker system prune --volumes.
Anomaly (1): destructive-burst detector across the sliding window.
03
LLM-response surface
assistant plan
A second pair of eyes on the assistant's plan text before any tool is invoked, catching cases where the agent describes a destructive step in prose:
  • llm.suggests_drop_database — assistant proposes a DROP DATABASE.
  • llm.suggests_force_push — assistant proposes a force-push to a protected branch.
  • llm.suggests_rm_rf — assistant proposes a recursive delete at root scope.
  • llm.suggests_curl_pipe_sh — assistant proposes a fetch-and-execute one-liner.
  • llm.suggests_secret_exfil — assistant describes reading a secret file and piping it to a network endpoint.
Why both surfaces? Because the assistant often writes the plan in plain text before the destructive tool call lands, and a clean catch there is cheaper than catching it at tools/call time.
Adaptive layer (the v0.2 / v0.3 difference)
04
Composite scoring
Every matching rule contributes points. The sum decides the final tier — so three medium signals can stack into a critical, and a single weak match never blocks on its own.
05
Workspace probe
Shield checks for 12 prod-shaped signals (.env.production, kubeconfig, terraform.tfstate, …) at startup. If matched, every decision gets a +1 severity bump for the session.
06
Decision memory
Per-fingerprint append-only log under .aperion-shield/decisions.jsonl. After 3 approvals of the same (rule, argv) shape, demote silently. After a recent deny, escalate.
07
Burst detector
Sliding window across the current process: 5 destructive matches inside 300 s ⇒ workspace marked "burst-in-progress" and every subsequent match gets bumped one tier until the window clears.
CLI cheat-sheet
FlagWhat it does
--rules PATH Custom shieldset YAML. Bundled defaults if omitted.
--shadow Observe-only — log everything, block nothing. Mirrors enterprise SHIELD_MODE=shadow.
--auto-deny-high Auto-deny High-severity instead of prompting. CI / unattended scripts.
--no-workspace-probeDisable the prod-signal bump.
--no-memory · --no-burstDisable decision-memory or burst-detector adjustments.
--check One-shot evaluation mode. Reads JSON-Lines from stdin, prints decisions to stdout. No MCP / IDE needed.
--workspace PATH Override the probe root (check-mode only). Useful for batch testing.
Test against your own command history
08
Mine your Cursor transcripts, run them through Shield
wide-scale test
Cursor stores every conversation as JSON-Lines under ~/.cursor/projects/**/*.jsonl. The bundled scripts/extract-cursor-corpus.py walks them, pulls every shell command and assistant-text turn, redacts AKIA / sk- / ghp_ / JWT-shaped secrets, dedupes, and emits the --check schema directly:
# Mine your history, evaluate every command, surface non-allow decisions. python3 scripts/extract-cursor-corpus.py --shell-only \ | aperion-shield --check --no-memory --no-burst \ | jq -c 'select(.decision != "allow")' # Save the corpus for re-use; run again later after editing rules. python3 scripts/extract-cursor-corpus.py --shell-only --out my-history.jsonl aperion-shield --check --rules my-shieldset.yaml < my-history.jsonl > decisions.jsonl
The 13k-command corpus that drove the v0.3 rule-quality pass was harvested with this exact tool. No data leaves the machine.
Free vs Enterprise

 aperion-shield (this)

  • 45 rules across 8 destructive surfaces
  • Composite scoring + workspace probe + decision memory + burst detector
  • YAML shieldset — bring your own rules
  • Local audit log (JSON-Lines to stderr)
  • Drop-in for Cursor and Claude Code over stdio
  • Apache 2.0 — no account, no telemetry, no cloud
Build from source · references
09
From a fresh checkout
build
Rust 1.75+ stable. No system dependencies, no native libraries on the call path.
git clone https://github.com/AperionAI/shield.git cd shield cargo build --release ./target/release/aperion-shield --version # aperion-shield 0.3.0 cargo test --release # 44 unit + 51 integration = 95 tests, all green
Repo: github.com/AperionAI/shield  ·  Releases: /releases  ·  Container: ghcr.io/aperionai/shield  ·  Crate: crates.io/crates/aperion-shield  ·  Full reference: docs.aperion.ai/aperion-shield  ·  v0.2 release notes: /aperion-shield-0.2.0-release