{"id":47035771,"url":"https://github.com/ldayton/Dippy","last_synced_at":"2026-03-13T23:01:45.569Z","repository":{"id":332398034,"uuid":"1129778461","full_name":"ldayton/Dippy","owner":"ldayton","description":"🐤 Less permission fatigue, more momentum. Dippy knows what’s safe to run and keeps Claude on track when plans change.","archived":false,"fork":false,"pushed_at":"2026-03-09T10:50:14.000Z","size":1649,"stargazers_count":54,"open_issues_count":7,"forks_count":6,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-09T15:23:54.436Z","etag":null,"topics":["bash","claude-code","cli","hook","permissions","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ldayton.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":null,"dco":null,"cla":null}},"created_at":"2026-01-07T15:14:10.000Z","updated_at":"2026-03-09T10:50:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ldayton/Dippy","commit_stats":null,"previous_names":["ldayton/dippy"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/ldayton/Dippy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ldayton%2FDippy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ldayton%2FDippy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ldayton%2FDippy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ldayton%2FDippy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ldayton","download_url":"https://codeload.github.com/ldayton/Dippy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ldayton%2FDippy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30478929,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-13T20:45:58.186Z","status":"ssl_error","status_checked_at":"2026-03-13T20:45:20.133Z","response_time":60,"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":["bash","claude-code","cli","hook","permissions","python"],"created_at":"2026-03-12T01:00:17.134Z","updated_at":"2026-03-13T23:01:45.557Z","avatar_url":"https://github.com/ldayton.png","language":"Python","funding_links":[],"categories":["Hooks 🪝","Code \u0026 Developer Tools"],"sub_categories":["General"],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"images/dippy.gif\" width=\"200\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003e🐤 Dippy\u003c/h1\u003e\n\u003cp align=\"center\"\u003e\u003cem\u003eBecause \u003ccode\u003els\u003c/code\u003e shouldn't need approval\u003c/em\u003e\u003c/p\u003e\n\n---\n\n\u003e **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.\n\nDippy 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.\n\nBuilt on [Parable](https://github.com/ldayton/Parable), our own hand-written bash parser—no external dependencies, just pure Python. 14,000+ tests between the two.\n\n***Example: rejecting unsafe operation in a chain***\n\n![Screenshot](images/terraform-apply.png)\n\n***Example: rejecting a command with advice, so Claude can keep going***\n\n![Deny with message](images/deny-with-message.png)\n\n## ✅ What gets approved\n\n- **Complex pipelines**: `ps aux | grep python | awk '{print $2}' | head -10`\n- **Chained reads**: `git status \u0026\u0026 git log --oneline -5 \u0026\u0026 git diff --stat`\n- **Cloud inspection**: `aws ec2 describe-instances --filters \"Name=tag:Environment,Values=prod\"`\n- **Container debugging**: `docker logs --tail 100 api-server 2\u003e\u00261 | grep ERROR`\n- **Safe redirects**: `grep -r \"TODO\" src/ 2\u003e/dev/null`, `ls \u0026\u003e/dev/null`\n- **Command substitution**: `ls $(pwd)`, `git diff foo-$(date).txt`\n\n![Safe command substitution](images/safe-cmd-sub.png)\n\n## 🚫 What gets blocked\n\n- **Subshell injection**: `git $(echo rm) foo.txt`, `echo $(rm -rf /)`\n- **Subtle file writes**: `curl https://example.com \u003e script.sh`, `tee output.log`\n- **Hidden mutations**: `git stash drop`, `npm unpublish`, `brew unlink`\n- **Cloud danger**: `aws s3 rm s3://bucket --recursive`, `kubectl delete pod`\n- **Destructive chains**: `rm -rf node_modules \u0026\u0026 npm install` (blocks the whole thing)\n\n![Redirect blocked](images/redirect.png)\n\n---\n\n## Installation\n\n### Homebrew (recommended)\n\n```bash\nbrew tap ldayton/dippy\nbrew install dippy\n```\n\n### Manual\n\n```bash\ngit clone https://github.com/ldayton/Dippy.git\n```\n\n### Configure\n\nAdd to `~/.claude/settings.json` (or use `/hooks` interactively):\n\n```json\n{\n  \"hooks\": {\n    \"PreToolUse\": [\n      {\n        \"matcher\": \"Bash\",\n        \"hooks\": [{ \"type\": \"command\", \"command\": \"dippy\" }]\n      }\n    ]\n  }\n}\n```\n\nIf you installed manually, use the full path instead: `/path/to/Dippy/bin/dippy-hook`\n\n---\n\n## Configuration\n\nDippy is highly customizable. Beyond simple allow/deny rules, you can attach messages that steer the AI back on track when it goes astray—no wasted turns.\n\n```\ndeny python \"Use uv run python, which runs in project environment\"\ndeny rm -rf \"Use trash instead\"\ndeny-redirect **/.env* \"Never write secrets, ask me to do it\"\n```\n\nDippy reads config from `~/.dippy/config` (global) and `.dippy` in your project root.\n\n**Full documentation:** [Dippy Wiki](https://github.com/ldayton/Dippy/wiki)\n\n---\n\n## Extensions\n\nDippy can do more than filter shell commands. See the [wiki](https://github.com/ldayton/Dippy/wiki) for additional capabilities.\n\n---\n\n## Uninstall\n\nRemove the hook entry from `~/.claude/settings.json`, then:\n\n```bash\nbrew uninstall dippy  # if installed via Homebrew\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fldayton%2FDippy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fldayton%2FDippy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fldayton%2FDippy/lists"}