Skip to content
 
 

Repository files navigation

🐤 Dippy

Because ls shouldn't need approval


🍴 Fork Enhancements (vs upstream)

  • File Edit/Read Approvalallow-edit/read, ask-edit/read, deny-edit/read rules
  • Include directiveinclude <path-or-glob> for composable config files
  • Exclusive configDIPPY_CONFIG_ONLY and --config-only isolate role-specific processes from user and project configuration
  • Context-aware rules[flags] syntax with @subshell, @compound, negation (!)
  • Scoped handler delegationdelegate [flags] command * sends a matched command through its native safety handler instead of approving it outright, including per-target SSH context
  • Environment context flagsset context-env VAR exposes an environment variable as the flag [$VAR=value], so one config can hold per-agent rules across commands, file edit/read operations, and web requests
  • Custom wrapperswrapper <name> for project-specific tools (ssh, docker exec, etc.), including literal quoted-heredoc script analysis with --script-stdin
  • Option rulesallow-opt, ask-opt, deny-opt for subcommand/flag control
  • WebSearch support — auto-approval for WebSearch tool (by tony)
  • Tk Approval Provider (dippy-askpass-gui) — standalone Tk GUI approval dialog with operation classification (Read File, Edit File, Command, Web Request, MCP Tool), single-key keyboard shortcuts (y/Y/Enter = allow, n/N/Esc = deny), and multi-monitor geometric centering via xrandr
  • Gemini CLI support — integrated hook support for Gemini CLI tools
  • Pure Dippy Control (Gemini & AGY) — YOLO mode automation via dippy hooks setup-gemini-yolo and AGY --dangerously-skip-permissions binary enforcement with askpass GUI resolution
  • Antigravity CLI (AGY) support — native lifecycle hook integration for Antigravity CLI with named-hook format in ~/.gemini/config/hooks.json and .agents/hooks.json, plus multi-workspace session resolution (workspacePaths)
  • Codex CLI support — native hooks.json integration for Codex PreToolUse/PermissionRequest/PostToolUse on Bash
  • Codex enforcement modelallow auto-approves via PermissionRequest; deny hard-blocks via exit 2; ask falls back to Codex approval UI
  • Structured JSON output — for PostToolUse hooks (by tony)
  • SSH/sudo handlers — remote context support for ssh and sudo commands
  • cp/mv through redirect rules — destinations (and mv sources, which get removed) are checked against allow-redirect/ask-redirect/deny-redirect, so deny-redirect **/.dippy also stops mv .dippy /tmp/saved
  • DuckDB writes through redirect rules — writes to the main database follow allow-redirect, while writable attachments and external file operations still require approval
  • Log rotationset log-rotate-max-days N for automatic cleanup
  • Notifier (Sidekick)set notifier-command "CMD" for external notifications (mail check). Supports long-polling via --idle in stop hooks. Use set notifier-include "tool1, tool2" to limit when it triggers.
  • Idle Prompt Notificationsset idle-notifier-command "notify-send {title} {message}" for notifications when Claude is waiting for input
  • Hook approvals log controlset log-hook-approvals off to disable hook-approvals.log
  • Hybrid modeset default pass to let Claude decide unmatched commands
  • Audit logcwd, agent, and suggestion fields for better context
  • CLI mode — standalone command validation with --cmd, --stdin, --json, --remote
  • Approved executiondippy run and allowlisted dippy run-on-server commands classify a quoted argument or literal quoted-heredoc script before local, SSH, tmux, or Herdr execution; uncertain remote results stay blocked until recovery
  • Optional project SSH profiles — SSH, tmux and Herdr share explicit SSH config/agent selection with no user-authentication fallback, private control sockets, and project-scoped recovery; ordinary user SSH settings remain the default
  • Multi-Agent Support — dedicated modes for Claude, Gemini, Antigravity CLI (AGY), pi-mono, Moltbot, Codex, Windsurf, PearAI
  • pi-mono extension — TypeScript extension for pi-mono AI assistant
  • Python -c AST analysispython -c 'code' is statically analyzed for safety instead of always requiring confirmation. Safe code (no I/O, no dangerous imports) is auto-approved (design by nickdaview)
  • Configurable Python modulespython-allow-module and python-deny-module directives to customize which modules are safe or dangerous during -c analysis, plus python-allow-symbol sys.stdin to allow a single name from a module that is otherwise too broad to trust (design by nickdaview)
  • CLI managementdippy hooks install/uninstall/list and dippy doctor diagnostics

Stop the permission fatigue. Claude Code asks for approval on every ls, git status, and cat - destroying your flow state. You check Slack, come back, and your assistant's just sitting there waiting.

Dippy is a shell command hook that auto-approves safe commands while still prompting for anything destructive. When it blocks, your custom deny messages can steer Claude back on track—no wasted turns. Get up to 40% faster development without disabling permissions entirely.

Built on Parable, our own hand-written bash parser—no external dependencies, just pure Python. 14,000+ tests between the two.

Example: rejecting unsafe operation in a chain

Screenshot

Example: rejecting a command with advice, so Claude can keep going

Deny with message

✅ What gets approved

  • Complex pipelines: ps aux | grep python | awk '{print $2}' | head -10
  • Chained reads: git status && git log --oneline -5 && git diff --stat
  • Cloud inspection: aws ec2 describe-instances --filters "Name=tag:Environment,Values=prod"
  • Container debugging: docker logs --tail 100 api-server 2>&1 | grep ERROR
  • Safe redirects: grep -r "TODO" src/ 2>/dev/null, ls &>/dev/null
  • Command substitution: ls $(pwd), git diff foo-$(date).txt

Safe command substitution

🚫 What gets blocked

  • Subshell injection: git $(echo rm) foo.txt, echo $(rm -rf /)
  • Subtle file writes: curl https://example.com > script.sh, tee output.log
  • Hidden mutations: git stash drop, npm unpublish, brew unlink
  • Cloud danger: aws s3 rm s3://bucket --recursive, kubectl delete pod
  • Destructive chains: rm -rf node_modules && npm install (blocks the whole thing)

Redirect blocked


⚠️ Known Limitations

Subagents ignore PreToolUse hook decisions - Claude Code subagents (spawned via Task tool) do not respect allow/deny decisions from PreToolUse hooks. Even when Dippy returns "permissionDecision": "allow", subagents will still prompt for approval.

  • Cause: Known bug in Claude Code (#4740, #4669)
  • Status: Closed as "not planned" by Anthropic (January 2026)
  • Impact: Hooks work correctly in main sessions but are ignored in subagents
  • Workaround: Use explicit config rules instead of relying on hook decisions

See docs/subagent-hook-issues.md for detailed analysis.


Installation

Quick Install (from source)

# Clone the repository
git clone https://github.com/orgoj/Dippy.git
cd Dippy

# Install via uv tool (recommended)
uv tool install .

# Verify installation
dippy --version

Note: Make sure ~/.local/bin is on your PATH.

Development Mode

uv pip install -e .

Quick Start

The easiest way to configure Dippy is using the CLI commands:

1. Install Hooks

# Install for Claude Code (global)
dippy hooks install claude --global

# Install for Gemini CLI (global)
dippy hooks install gemini --global

# Install for Cursor IDE (global)
dippy hooks install cursor --global

# Install for Windsurf (global)
dippy hooks install windsurf --global

# Install for Codex CLI (global, requires hooks feature flag)
dippy hooks install codex --global

2. Verify Installation

# Check hook status
dippy hooks list

# Run diagnostics
dippy doctor

That's it! Dippy is now configured and will auto-approve safe commands.

Manual Configuration (Advanced)

If you prefer manual configuration or need project-specific settings:

Claude Code - add to ~/.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash|Write|Edit|MultiEdit|Read|LS|Glob|Grep|Search|WebSearch|mcp__.*",
        "hooks": [{ "type": "command", "command": "dippy" }]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Bash|WebSearch|mcp__.*",
        "hooks": [{ "type": "command", "command": "dippy" }]
      }
    ]
  }
}

Gemini CLI - add to ~/.gemini/settings.json:

{
  "hooks": {
    "BeforeTool": [
      {
        "matcher": "run_shell_command|write_file|replace|read_file|google_web_search",
        "hooks": [{ "type": "command", "command": "dippy --gemini" }]
      }
    ],
    "AfterTool": [
      {
        "matcher": "run_shell_command|google_web_search",
        "hooks": [{ "type": "command", "command": "dippy --gemini" }]
      }
    ]
  }
}

Codex CLI - add to ~/.codex/hooks.json and enable hooks = true in ~/.codex/config.toml:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "^Bash$",
        "hooks": [{ "type": "command", "command": "dippy --codex" }]
      }
    ],
    "PermissionRequest": [
      {
        "matcher": "^Bash$",
        "hooks": [{ "type": "command", "command": "dippy --codex" }]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "^Bash$",
        "hooks": [{ "type": "command", "command": "dippy --codex" }]
      }
    ]
  }
}

Current Codex behavior: Dippy auto-approves allowed shell commands in the PermissionRequest hook, but Codex only emits that event when its own policy already requires approval. PreToolUse cannot force a prompt: an ask there is advisory and otherwise fails open. For an external wrapper that can change state outside the sandbox, add a Codex execpolicy prompt rule so every wrapper invocation reaches PermissionRequest:

prefix_rule(
    pattern = ["cca-tmux-cli"],
    decision = "prompt",
    justification = "Let Dippy decide whether this remote command requires user approval.",
)

Put global rules in ~/.codex/rules/*.rules or project rules in .codex/rules/*.rules, then restart Codex. Prefer Dippy's own stable execution surface for external commands: prompt dippy run and dippy run-on-server in the agent policy, then let the inner Dippy invocation enforce the command rules. See Codex CLI hooks.

Current Gemini behavior: Gemini CLI 0.42 treats BeforeTool hook allow as "continue to normal policy" by default. To enable Pure Dippy Control and avoid double prompts, use:

dippy hooks setup-gemini-yolo

This enables Gemini's native YOLO mode, trusting Dippy as the primary authority.

Codex sandbox gotcha: During Codex workspace-write tool execution on Linux, .codex can appear inside the sandbox as a synthetic read-only file-like path even when the host workspace does not contain a normal .codex file. That artifact comes from Codex sandbox path protection, not from Dippy.

Hooks installed:

  • PreToolUse: Validates tools BEFORE execution (Bash, file ops, WebSearch, MCP)
  • PostToolUse: Shows feedback messages AFTER execution (for after directive)

Changing hook config requires restarting the agent session. For Codex, both hooks.json and config.toml are loaded at session start.


CLI Commands

Approved Execution

dippy run 'CMD'
dippy run-on-server SERVER 'CMD'
dippy run <<'DIPPY'               # literal multiline local script
CMD
DIPPY
dippy run-on-server SERVER <<'DIPPY'
CMD
DIPPY
dippy recover SERVER               # check an uncertain persistent run
dippy recover SERVER --clear       # release after manual inspection

run-on-server accepts only aliases declared with server SERVER. Its transport comes from configuration and cannot be overridden at invocation. By default it uses your ordinary SSH settings. Projects can opt into an isolated SSH profile with their own configuration, keys and authentication socket, shared by all three backends. See the configuration reference for SSH, tmux, Herdr, askpass, config-management setup, and the interaction between approval and agent CLI timeouts. Projects with a supervising agent or a custom user channel can set approval-wait-message without exposing the underlying enforcement mechanism.

Hooks Management

dippy hooks list                    # Show hook status for all agents
dippy hooks install <agent>         # Install hooks (project-local)
dippy hooks install <agent> --global  # Install hooks (global)
dippy hooks uninstall <agent>       # Remove hooks (project-local)
dippy hooks uninstall <agent> --global  # Remove hooks (global)

Supported agents: claude, gemini, cursor, windsurf, codex

Status indicators:

  • + = installed
  • ? = legacy (old dippy-hook detected)
  • = not installed

Scopes:

  • Project-local (default): .claude/settings.json, .cursor/hooks.json, .gemini/settings.json, .codex/hooks.json
  • Global (--global): ~/.claude/settings.json, ~/.cursor/hooks.json, ~/.gemini/settings.json, ~/.codex/hooks.json

Diagnostics

dippy doctor                        # Run all health checks
dippy doctor --agent claude         # Check specific agent
dippy doctor --verbose              # Show detailed diagnostics

Health checks:

  • ✓ Installation (on PATH, version check)
  • ✓ Hook status per agent (Claude, Gemini, Cursor, Windsurf, Codex, pi-mono)
  • ✓ Codex hooks feature flag validation
  • ✓ Legacy hook detection with full path
  • ✓ pi_wrapper check for pi-mono/moltbot
  • ✓ Configuration validation (syntax errors)
  • ✓ Log health (writable directories, file size warnings)

Exit codes: 0 (OK), 1 (warnings), 2 (critical issues)

CLI Mode

Validate commands without running as a hook:

dippy --cmd 'rm -rf /'              # validate a command
dippy --cmd 'ls -la' --json         # JSON output
dippy --cmd 'git status' --cwd /path
echo 'ls -la' | dippy --stdin       # read command from stdin

Options:

  • --cmd COMMAND — command to validate
  • --stdin — read command from stdin
  • --cwd PATH — working directory
  • --json — output as JSON
  • --config PATH — custom config file
  • --config-only PATH — load only this config, skipping user and project config
  • --agent NAME — force agent name in audit log
  • --remote — skip local path checks
  • --version — show version

Supported Agents

Dippy adapts its output format and behavior based on the agent:

Agent Flag Env Var Hook Support
Claude Code --claude DIPPY_CLAUDE=1
Gemini CLI --gemini DIPPY_GEMINI=1
Cursor IDE --cursor DIPPY_CURSOR=1 preToolUse
Windsurf --windsurf DIPPY_WINDSURF=1
pi-mono --pi DIPPY_PI=1 extension
Moltbot --moltbot DIPPY_MOLTBOT=1 extension
OpenAI Codex --codex DIPPY_CODEX=1
PearAI --pearai DIPPY_PEARAI=1 partial

Each agent mode maintains its own approval log (e.g., ~/.claude/hook-approvals.log).


Configuration

Dippy reads config from ~/.dippy/config (global) and .dippy (project).

Basic Rules

# Allow safe commands
allow git status
allow ls *
allow cat *

# Block dangerous commands
deny rm -rf *
deny docker rm *

# Prompt with message
deny pip install "Use uv pip install instead"
deny python "Use uv run python"

File Operations

Auto-approve file operations using the same config:

allow-read src/**
allow-edit src/**
deny-read **/.env*
deny-edit **/.env*
ask-edit **/config.*

Advanced Features

# Include external config files
include ~/.dippy/shared-rules
include .dippy-local-*

# Log settings
set log ~/.dippy/audit.log
set log-full
set log-rotate-max-days 30
set log-hook-approvals off

# Default behavior
set default ask                    # prompt (default)
# set default pass                 # let Claude decide
# set default allow                # auto-approve

# Context-aware rules
deny [!@subshell] cd *              # deny cd outside subshell
allow [@subshell] cd *              # allow (cd x && y)

# Custom wrappers
wrapper docker-exec
allow [docker-exec,prod] read *

# Option rules
allow-opt git status fetch log diff
deny-opt "git push" --force "Use --force-with-lease"

# MCP tools
allow-mcp mcp__github__get_*
deny-mcp mcp__*__delete_*

# After hook
after git commit * "Check project-tasks.md"

Full documentation: docs/config.md


Troubleshooting

Not working?

# Run diagnostics
dippy doctor

# Check hook status
dippy hooks list

# Reinstall hooks
dippy hooks uninstall claude --global
dippy hooks install claude --global

Check logs

  • Claude Code: ~/.claude/hook-approvals.log
  • Gemini CLI: ~/.gemini/hook-approvals.log
  • Dippy audit: ~/.dippy/audit.log

Common Issues

  • Hook not triggering → Run dippy doctor to diagnose
  • JSON syntax errors → Check config with dippy doctor
  • Legacy hook detected → Run dippy hooks install <agent> --global

Uninstall

# Remove hooks
dippy hooks uninstall claude --global
dippy hooks uninstall gemini --global

# Uninstall tool
uv tool uninstall dippy

pi-mono Extension

Dippy includes a TypeScript extension for pi-mono:

# Link the extension
ln -s /path/to/dippy/pi-extension/dippy-extension.ts \
      ~/.pi/agent/extensions/dippy-extension.ts

Uses your existing ~/.dippy/config and .dippy files.


Development

# Install in development mode
uv pip install -e .

# Run tests
uv run python -m pytest

# Run specific test
uv run python -m pytest tests/test_agents.py -v

Full documentation: docs/config.md Upstream repository: ldayton/Dippy

About

🐤 Less permission fatigue, more momentum. Dippy knows what’s safe to run and keeps Claude on track when plans change.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages