omamori
Pre-1.0 — Breaking changes may occur between minor versions.
AI Agent's Omamori — protect your system from dangerous commands executed via AI CLI tools.
Support Tiers
| Tier | Tools | What it means |
|---|---|---|
| Supported | Claude Code, Codex CLI, Cursor | E2E tested every release. Issues investigated and fixed. |
| Community | Gemini CLI, Cline, others | Env var detection included but not tested. No guaranteed support. |
| Fallback | Any tool setting AI_GUARD=1 |
Generic detection. No tool-specific integration. |
Detection Details
| Tool | Environment Variable | Value |
|---|---|---|
| Claude Code | CLAUDECODE |
1 |
| Codex CLI | CODEX_CI |
1 |
| Cursor | CURSOR_AGENT |
1 |
| Gemini CLI | GEMINI_CLI |
1 |
| Cline | CLINE_ACTIVE |
true |
| Fallback | AI_GUARD |
1 |
Detection uses exact value matching (e.g. CLAUDECODE=1 only, not CLAUDECODE=true).
Protection Coverage (Supported Tools)
| Protection | Claude Code | Codex CLI | Cursor |
|---|---|---|---|
| Layer 1 — PATH shim (all rules) | ✅ | ✅ | ✅ |
| Layer 2 — Hooks (full-path bypass) | ✅ PreToolUse | ❌ | ✅ beforeShellExecution |
| Layer 2 — Hooks (interpreter warnings) | ✅ warn | ❌ | ✅ ask |
| Config guard (disable/uninstall blocked) | ✅ env var + hooks | ✅ env var | ✅ env var + hooks |
| config.toml direct edit guard | ✅ PreToolUse | ❌ | Bash only |
- Layer 1 (PATH shim): Blocks dangerous commands when AI sets its env var. Bypassable via
/bin/rmfull-path execution. - Layer 2 (Hooks): Catches full-path bypass, env var unset, interpreter commands, and
config disable/uninstall. Available for Claude Code and Cursor only. - Config guard (v0.3.2+):
config disable,config enable,uninstall, andinit --forceare blocked when AI detector env vars are present. Works for all detected tools. - config.toml edit guard: PreToolUse hook blocks direct file editing (Claude Code only). Cursor blocks Bash-based edits.
- See SECURITY.md for full details and known limitations.
What It Does
When an AI CLI tool (Claude Code, Codex, Cursor, etc.) runs a shell command, omamori intercepts dangerous operations and replaces them with safe alternatives. Terminal direct execution is not affected.
[AI CLI Tool] → CLAUDECODE=1 → rm -rf target/
↓
[omamori shim]
↓
moved to Trash instead
[Terminal] → → rm -rf target/
↓
[/usr/bin/rm]
↓
deleted normally
Quick Start
Install via Homebrew (macOS)
Or build from source
Setup
# 1. Install shims + hooks + config (all in one command)
# 2. Add shim directory to PATH (add to .zshrc / .bashrc)
That's it. install --hooks auto-generates config.toml, runs verification, and shows a checklist:
omamori setup complete:
Shims:
[done] rm, git, chmod, find, rsync
Hooks:
[done] Claude Code hook script
[done] Cursor hook snippet
Config:
[done] Created: ~/.config/omamori/config.toml
[done] 7 rules verified, 12 detection tests passed
Next steps:
[todo] Add to your shell profile:
export PATH="$HOME/.omamori/shim:$PATH"
[todo] Merge Cursor hook into .cursor/hooks.json
How It Works
Layer 1 — PATH shim: Symlinks for rm, git, chmod, find, rsync point to the omamori binary. When invoked, omamori checks for AI tool environment variables (e.g. CLAUDECODE=1) and applies rules only if an AI tool is detected.
Layer 2 — Hooks (optional):
- Claude Code: A
PreToolUsehook script catches bypass attempts like/bin/rmdirect paths,unset CLAUDECODE, and warns on interpreter commands (python -c "shutil.rmtree(...)"). - Cursor: A Rust-native
beforeShellExecutionhandler (omamori cursor-hook) provides the same protection via Cursor's hook protocol.
Default Rules
| Command | Pattern | Action |
|---|---|---|
rm |
-r, -rf, -fr, --recursive |
trash — move to macOS Trash |
git |
reset --hard |
stash-then-exec — git stash first, then execute |
git |
push --force, push -f |
block |
git |
clean -fd, clean -fdx |
block |
chmod |
777 |
block |
find |
-delete, --delete |
block |
rsync |
--delete and 7 variants |
block |
Combined short flags are normalized: rm -rfv expands to match -r and -rf rules. The POSIX -- separator is respected for target extraction.
rsync variants blocked: --delete, --del, --delete-before, --delete-during, --delete-after, --delete-excluded, --delete-delay, --remove-source-files.
Configuration (v0.2+)
Built-in rules are always inherited. Config is auto-created by install --hooks. To regenerate manually:
Disable a rule via CLI (v0.3+):
Or edit config.toml directly:
[[]]
= "git-push-force-block"
= false
Move files to a custom directory instead of Trash:
[[]]
= "rm-to-backup"
= "rm"
= "move-to"
= "/tmp/omamori-quarantine/"
= ["-r", "-rf", "-fr", "--recursive"]
= "omamori moved targets to quarantine instead of deleting"
Override an existing rule's action:
[[]]
= "rm-recursive-to-trash"
= "move-to"
= "/tmp/omamori-quarantine/"
After editing, run omamori test to verify. Disabled rules show as SKIP:
Rules:
PASS rm-recursive-to-trash rm -r|-rf|-fr|--recursive -> trash
SKIP git-push-force-block (disabled by user config)
...
Summary: 7 rules (6 active, 1 disabled), 12 detection tests passed
Configuration notes
- Config file requires
chmod 600(permissions check enforced) - Only write rules you want to change — everything else is inherited
destinationmust be an absolute path on the same volume- System directories (
/usr,/etc,/System,/Library,/bin,/sbin,/var,/private) are blocked as destinations - Symlinks are rejected as destinations
destinationdirectory must exist before use (omamori will not create it)
Context-Aware Evaluation (v0.4.0+)
omamori can adjust protection actions based on command target paths and git status. This reduces false positives (e.g., rm -rf target/ in a Rust project) while strengthening defense for critical paths.
Opt-in: Add [context] to your config.toml to enable. Without it, behavior is identical to v0.3.
Quick setup
# Add to ~/.config/omamori/config.toml
[]
# Built-in defaults activate:
# - regenerable: target/, node_modules/, .next/, dist/, build/, __pycache__/, .cache/
# - protected: src/, lib/, .git/, .env, .ssh/
Custom paths
[]
= ["my-cache/"] # Added to built-in list
= ["secrets/"] # Added to built-in list
[]
= true # Check git status before acting (default: false)
= 100 # Git status timeout in ms (default: 100)
How it works
| Command | Without context | With context |
|---|---|---|
rm -rf target/ |
trash | log-only (regenerable) |
rm -rf src/ |
trash | block (protected) |
rm -rf data/ |
trash | trash (unchanged) |
git reset --hard (no changes) |
stash-then-exec | log-only (git-aware, opt-in) |
Security features
- Symlink defense:
canonicalize()resolves symlinks before matching —ln -sf src/ target && rm -rf targetis caught - Traversal defense:
target/../src/is normalized tosrc/before matching - NEVER_REGENERABLE:
src/,.git/,.envetc. cannot be made regenerable even by misconfiguration - Fail-close: canonicalize failure or git timeout → original action preserved
Available Actions
| Action | Behavior |
|---|---|
trash |
Move targets to macOS Trash |
move-to |
Move targets to a user-specified directory (requires destination) |
stash-then-exec |
Run git stash first, then execute the original command |
block |
Refuse to execute |
log-only |
Log the event, then execute normally |
Safe Defaults
| Scenario | Behavior |
|---|---|
| No AI env var detected | Pass through to real command (no interference) |
| Config file missing | Fail-close: built-in default rules apply |
| Config file broken | Fail-close: built-in default rules apply + warning |
| Trash / move-to fails | Fail-close: refuse to run the original command |
sudo detected |
Block the command |
| Blocked destination | Fail-close: rule is disabled at config load time |
| Shim binary crashes | Fail-open: real command runs |
CLI
omamori test [--config PATH] # Verify policy rules
omamori exec [--config PATH] -- <command> [args...] # Run through policy engine
omamori install [--base-dir PATH] [--hooks] # Create shims + hooks + config
omamori uninstall [--base-dir PATH] # Remove shims + hook files
omamori init [--force] [--stdout] # Create/reset config file
omamori config list # Show all rules with status
omamori config disable <rule> # Disable a rule (blocked by AI tools)
omamori config enable <rule> # Re-enable a rule (blocked by AI tools)
omamori cursor-hook # Cursor beforeShellExecution handler
Structural Limitations
These are inherent to the PATH shim approach and documented honestly:
- Full-path execution (
/bin/rm,/usr/bin/git) bypasses the shim — mitigated by Layer 2 hooks (Claude Code + Cursor). Tools without hooks (Codex, Gemini) are vulnerable. sudochanges PATH before the shim runs — omamori blocks when it detects elevated execution in-process- Interpreter commands (
python -c "shutil.rmtree(...)") — Layer 2 hooks warn on known destructive patterns, but obfuscated code (base64, heredoc, variable indirection) cannot be detected find -exec /bin/rmbypasses the find shim because rm is invoked via absolute path — partially mitigated by Layer 2 hooks- AI self-bypass:
config disable,uninstall, andinit --forceare blocked when AI env vars are detected (v0.3.2+). AI agents may still attempt directconfig.tomlfile editing — blocked by PreToolUse hooks in Claude Code only. See #22 - Cross-device moves are not supported for
move-to(use a destination on the same volume)
For the full security model, see SECURITY.md.
Related
- nanika — explains what AI commands will do (detect + translate). Complementary to omamori (detect + replace).
License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.