https://github.com/camjac251/bash-gates
Intelligent bash command permission gates for Claude Code using tree-sitter AST parsing
https://github.com/camjac251/bash-gates
bash claude-code cli hooks rust security tree-sitter
Last synced: 4 months ago
JSON representation
Intelligent bash command permission gates for Claude Code using tree-sitter AST parsing
- Host: GitHub
- URL: https://github.com/camjac251/bash-gates
- Owner: camjac251
- Created: 2025-12-15T01:53:24.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2026-02-24T10:46:49.000Z (4 months ago)
- Last Synced: 2026-02-24T13:48:37.480Z (4 months ago)
- Topics: bash, claude-code, cli, hooks, rust, security, tree-sitter
- Language: Rust
- Size: 656 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Agents: AGENTS.md
Awesome Lists containing this project
README
# bash-gates
**Intelligent permission gates for bash commands in Claude Code**
[](https://github.com/camjac251/bash-gates/actions/workflows/ci.yml)
[](https://github.com/camjac251/bash-gates/actions/workflows/release.yml)
[](https://www.rust-lang.org/)
[](LICENSE)
A Claude Code [PreToolUse hook](https://code.claude.com/docs/en/hooks#pretooluse) that analyzes bash commands using AST parsing and determines whether to allow, ask, or block based on potential impact.
[Installation](#installation) · [Permission Gates](#permission-gates) · [Security](#security-features) · [Testing](#testing)
---
## Features
| Feature | Description |
| ------------------------ | ------------------------------------------------------------------------------------------------------ |
| **Approval Learning** | Tracks approved commands and saves patterns to settings.json via TUI or CLI |
| **Settings Integration** | Respects your `settings.json` allow/deny/ask rules - won't bypass your explicit permissions |
| **Accept Edits Mode** | Auto-allows file-editing commands (`sd`, `prettier --write`, etc.) when in acceptEdits mode |
| **Modern CLI Hints** | Suggests modern alternatives (`bat`, `rg`, `fd`, etc.) via `additionalContext` for Claude to learn |
| **AST Parsing** | Uses [tree-sitter-bash](https://github.com/tree-sitter/tree-sitter-bash) for accurate command analysis |
| **Compound Commands** | Handles `&&`, `\|\|`, `\|`, `;` chains correctly |
| **Security First** | Catches pipe-to-shell, eval, command injection patterns |
| **Unknown Protection** | Unrecognized commands require approval |
| **Claude Code Plugin** | Install as a plugin with the `/bash-gates:review` skill for interactive approval management |
| **300+ Commands** | 13 specialized gates with comprehensive coverage |
| **Fast** | Static native binary, no interpreter overhead |
---
## How It Works
```mermaid
flowchart TD
CC[Claude Code] --> CMD[Bash Command]
subgraph PTU [PreToolUse Hook]
direction TB
PTU_CHECK[bash-gates check] --> PTU_DEC{Decision}
PTU_DEC -->|dangerous| PTU_DENY[deny]
PTU_DEC -->|risky| PTU_ASK[ask + track]
PTU_DEC -->|safe| PTU_CTX{Context?}
PTU_CTX -->|main session| PTU_ALLOW[allow ✓]
PTU_CTX -->|subagent| PTU_IGNORED[ignored by Claude]
end
CMD --> PTU
PTU_IGNORED --> INTERNAL[Claude internal checks]
INTERNAL -->|path outside cwd| PR_HOOK
subgraph PR_HOOK [PermissionRequest Hook]
direction TB
PR_CHECK[bash-gates re-check] --> PR_DEC{Decision}
PR_DEC -->|safe| PR_ALLOW[allow ✓]
PR_DEC -->|dangerous| PR_DENY[deny]
PR_DEC -->|risky| PR_PROMPT[show prompt]
end
PTU_ASK --> EXEC[Command Executes]
PR_PROMPT --> USER_APPROVE[User Approves] --> EXEC
subgraph POST [PostToolUse Hook]
direction TB
POST_CHECK[check tracking] --> POST_DEC{Tracked + Success?}
POST_DEC -->|yes| PENDING[add to pending queue]
POST_DEC -->|no| POST_SKIP[skip]
end
EXEC --> POST
PENDING --> REVIEW[bash-gates review]
REVIEW --> SETTINGS[settings.json]
```
**Why three hooks?**
- **PreToolUse**: Gates commands for main session, tracks "ask" decisions
- **PermissionRequest**: Gates commands for subagents (where PreToolUse's `allow` is ignored)
- **PostToolUse**: Detects successful execution, queues for permanent approval
> `PermissionRequest` metadata like `blocked_path` and `decision_reason` is optional in Claude Code payloads. bash-gates treats those fields as best-effort context, not required inputs.
**Decision Priority:** `BLOCK > ASK > ALLOW > SKIP`
| Decision | Effect |
| :-------: | --------------------------- |
| **deny** | Command blocked with reason |
| **ask** | User prompted for approval |
| **allow** | Auto-approved |
> Unknown commands always require approval.
### Settings.json Integration
bash-gates reads your Claude Code settings from `~/.claude/settings.json` and `.claude/settings.json` (project) to respect your explicit permission rules:
| settings.json | bash-gates | Result |
| ------------- | ---------- | -------------------------------------------- |
| `deny` rule | (any) | Defers to Claude Code (respects your deny) |
| `ask` rule | (any) | Defers to Claude Code (respects your ask) |
| `allow` rule | dangerous | **deny** (bash-gates still blocks dangerous) |
| `allow`/none | safe | **allow** |
| none | unknown | **ask** |
This ensures bash-gates won't accidentally bypass your explicit deny rules while still providing security against dangerous commands.
**Settings file priority** (highest wins):
| Priority | Location | Description |
| ----------- | ---------------------------------------- | ----------------------------- |
| 1 (highest) | `/etc/claude-code/managed-settings.json` | Enterprise managed |
| 2 | `.claude/settings.local.json` | Local project (not committed) |
| 3 | `.claude/settings.json` | Shared project (committed) |
| 4 (lowest) | `~/.claude/settings.json` | User settings |
### Accept Edits Mode
When Claude Code is in `acceptEdits` mode, bash-gates auto-allows file-editing commands:
```bash
# In acceptEdits mode - auto-allowed
sd 'old' 'new' file.txt # Text replacement
prettier --write src/ # Code formatting
ast-grep -p 'old' -r 'new' -U . # Code refactoring
sed -i 's/foo/bar/g' file.txt # In-place sed
black src/ # Python formatting
eslint --fix src/ # Linting with fix
```
**Still requires approval (even in acceptEdits):**
- Package managers: `npm install`, `cargo add`
- Git operations: `git push`, `git commit`
- Deletions: `rm`, `mv`
- Blocked commands: `rm -rf /` still denied
### Modern CLI Hints
_Requires Claude Code 1.0.20+_
When Claude uses legacy commands, bash-gates suggests modern alternatives via `additionalContext`. This helps Claude learn better patterns over time without modifying the command.
```bash
# Claude runs: cat README.md
# bash-gates returns:
{
"hookSpecificOutput": {
"permissionDecision": "allow",
"additionalContext": "Tip: Use 'bat README.md' for syntax highlighting and line numbers (Markdown rendering)"
}
}
```
| Legacy Command | Modern Alternative | When triggered |
| ----------------------------- | ------------------ | ------------------------------------ |
| `cat`, `head`, `tail`, `less` | `bat` | Always (`tail -f` excluded) |
| `grep` (code patterns) | `sg` | AST-aware code search |
| `grep` (text/log/config) | `rg` | Any grep usage |
| `find` | `fd` | Always |
| `ls` | `eza` | With `-l` or `-a` flags |
| `sed` | `sd` | Substitution patterns (`s/.../.../`) |
| `awk` | `choose` | Field extraction (`print $`) |
| `du` | `dust` | Always |
| `ps` | `procs` | With `aux`, `-e`, `-A` flags |
| `curl`, `wget` | `xh` | JSON APIs or verbose mode |
| `diff` | `delta` | Two-file comparisons |
| `xxd`, `hexdump` | `hexyl` | Always |
| `cloc` | `tokei` | Always |
| `tree` | `eza -T` | Always |
| `man` | `tldr` | Always |
| `wc -l` | `rg -c` | Line counting |
**Only suggests installed tools.** Hints are cached (7-day TTL) to avoid repeated `which` calls.
```bash
# Refresh tool detection cache
bash-gates --refresh-tools
# Check which tools are detected
bash-gates --tools-status
```
### Approval Learning
When you approve commands (via Claude Code's permission prompt), bash-gates tracks them and lets you permanently save patterns to settings.json.
```bash
# After approving some commands, review pending approvals
bash-gates pending list
# Interactive TUI dashboard
bash-gates review # current project only
bash-gates review --all # all projects
# Or approve directly via CLI
bash-gates approve 'npm install*' -s local
bash-gates approve 'cargo*' -s user
# Manage existing rules
bash-gates rules list
bash-gates rules remove 'pattern' -s local
```
**Scopes:**
| Scope | File | Use case |
|-------|------|----------|
| `local` | `.claude/settings.local.json` | Personal project overrides (not committed) |
| `user` | `~/.claude/settings.json` | Global personal use |
| `project` | `.claude/settings.json` | Share with team |
**Review TUI** (`bash-gates review`):
Three-panel dashboard -- project sidebar, command list, and detail panel.
- **Sidebar**: Lists projects with pending counts, auto-selects current project. Click or arrow to switch.
- **Command list**: Full commands with color-coded segments (green=allowed, yellow=ask, red=blocked). Multi-select with Space for batch operations.
- **Detail panel**: Shows segment breakdown, pattern (cycle with Left/Right), scope (cycle with Left/Right), and action buttons.
Compound commands (`&&`, `||`, `|`) show per-segment patterns so you can approve individual parts.
| Key | Action |
| --- | ------ |
| `Tab` | Cycle panel focus (Sidebar -> Commands -> Detail) |
| `Up`/`Down` or `j`/`k` | Navigate within focused panel |
| `Left`/`Right` or `h`/`l` | Cycle pattern or scope (in detail panel) |
| `Space` | Toggle multi-select on command |
| `Enter` | Approve selected command(s) |
| `d` | Skip (remove from pending) |
| `D` | Deny (add to settings.json deny list) |
| `q` or `Esc` | Quit |
---
## Installation
### Download Binary
```bash
# Linux x64
curl -Lo ~/.local/bin/bash-gates \
https://github.com/camjac251/bash-gates/releases/latest/download/bash-gates-linux-amd64
chmod +x ~/.local/bin/bash-gates
# Linux ARM64
curl -Lo ~/.local/bin/bash-gates \
https://github.com/camjac251/bash-gates/releases/latest/download/bash-gates-linux-arm64
chmod +x ~/.local/bin/bash-gates
# macOS Apple Silicon
curl -Lo ~/.local/bin/bash-gates \
https://github.com/camjac251/bash-gates/releases/latest/download/bash-gates-darwin-arm64
chmod +x ~/.local/bin/bash-gates
# macOS Intel
curl -Lo ~/.local/bin/bash-gates \
https://github.com/camjac251/bash-gates/releases/latest/download/bash-gates-darwin-amd64
chmod +x ~/.local/bin/bash-gates
```
### Build from Source
```bash
# Requires Rust 1.85+
cargo build --release
# Binary: ./target/x86_64-unknown-linux-musl/release/bash-gates
```
### Configure Claude Code
Use the `hooks` subcommand to configure Claude Code:
```bash
# Install to user settings (recommended)
bash-gates hooks add -s user
# Install to project settings (shared with team)
bash-gates hooks add -s project
# Install to local project settings (not committed)
bash-gates hooks add -s local
# Preview changes without writing
bash-gates hooks add -s user --dry-run
# Check installation status
bash-gates hooks status
# Output hooks JSON for manual config
bash-gates hooks json
```
**Scopes:**
| Scope | File | Use case |
|-------|------|----------|
| `user` | `~/.claude/settings.json` | Personal use (recommended) |
| `project` | `.claude/settings.json` | Share with team |
| `local` | `.claude/settings.local.json` | Personal project overrides |
**All three hooks are installed:**
- `PreToolUse` - Gates commands for main session, tracks "ask" decisions
- `PermissionRequest` - Gates commands for subagents (where PreToolUse's allow is ignored)
- `PostToolUse` - Detects successful execution, queues for permanent approval
Manual installation
Add to `~/.claude/settings.json`:
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.local/bin/bash-gates",
"timeout": 10
}
]
}
],
"PermissionRequest": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.local/bin/bash-gates",
"timeout": 10
}
]
}
],
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.local/bin/bash-gates",
"timeout": 10
}
]
}
]
}
}
```
### Claude Code Plugin (Optional)
bash-gates ships as a [Claude Code plugin](https://code.claude.com/docs/en/plugins) with the `/bash-gates:review` skill for interactive approval management. The plugin provides the skill only -- hook installation is handled by the binary (see [Configure Claude Code](#configure-claude-code) above).
**Prerequisites:** The `bash-gates` binary must be installed and hooks configured before using the plugin.
**Install from marketplace:**
```bash
# In Claude Code, add the marketplace
/plugin marketplace add camjac251/bash-gates
# Install the plugin
/plugin install bash-gates@camjac251-bash-gates
```
**Install from local clone:**
```bash
# Launch Claude Code with the plugin loaded
claude --plugin-dir /path/to/bash-gates
```
**Using the review skill:**
```bash
# Review all pending approvals
/bash-gates:review
# Review only current project
/bash-gates:review --project
```
The skill lists commands you've been manually approving, shows counts and suggested patterns, and lets you multi-select which to make permanent at your chosen scope (local, project, or user).
| Step | What happens | Permission |
| ---------------------- | ------------------------------------------- | -------------------------- |
| List pending approvals | `bash-gates pending list` | Auto-approved (read-only) |
| Show current rules | `bash-gates rules list` | Auto-approved (read-only) |
| Approve a pattern | `bash-gates approve '' -s ` | Requires your confirmation |
---
## Permission Gates
### Bash Gates (Self)
bash-gates recognizes its own CLI commands:
| Allow | Ask |
| ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `pending list`, `pending count`, `rules list`, `hooks status`, `--help`, `--version`, `--tools-status`, `--export-toml` | `approve`, `rules remove`, `pending clear`, `hooks add`, `review`, `--refresh-tools` |
### Basics
~130+ safe read-only commands: `echo`, `cat`, `ls`, `grep`, `rg`, `awk`, `sed` (no -i), `ps`, `whoami`, `date`, `jq`, `yq`, `bat`, `fd`, `tokei`, `hexdump`, and more. Custom handlers for `xargs` (safe only with known-safe targets) and `bash -c`/`sh -c` (parses inner script).
### Beads Issue Tracker
[Beads](https://github.com/steveyegge/beads) - Git-native issue tracking
| Allow | Ask |
| ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------- |
| `list`, `show`, `ready`, `blocked`, `search`, `stats`, `doctor`, `dep tree`, `prime` | `create`, `update`, `close`, `delete`, `sync`, `init`, `dep add`, `comments add` |
### MCP CLI
`mcp-cli` - Claude Code's [experimental token-efficient MCP interface](https://github.com/anthropics/claude-code/issues/12836#issuecomment-3629052941)
Instead of loading full MCP tool definitions into the system prompt, Claude discovers tools on-demand via `mcp-cli` and executes them through Bash. Enable with `ENABLE_EXPERIMENTAL_MCP_CLI=true`.
| Allow | Ask |
| --------------------------------------------------------------- | -------------------------- |
| `servers`, `tools`, `info`, `grep`, `resources`, `read`, `help` | `call` (invokes MCP tools) |
Pre-approve trusted servers in settings.json to avoid repeated prompts:
```json
{
"permissions": {
"allow": ["mcp__perplexity", "mcp__context7__*"],
"deny": ["mcp__firecrawl__firecrawl_crawl"]
}
}
```
Patterns: `mcp__` (entire server), `mcp____` (specific tool), `mcp____*` (wildcard)
### GitHub CLI
| Allow | Ask | Block |
| ----------------------------------------------------------- | ---------------------------------------------------- | ---------------------------- |
| `pr list`, `issue view`, `repo view`, `search`, `api` (GET) | `pr create`, `pr merge`, `issue create`, `repo fork` | `repo delete`, `auth logout` |
### Git
| Allow | Ask | Ask (warning) |
| -------------------------------------------- | ---------------------------------------- | ------------------------------------------- |
| `status`, `log`, `diff`, `show`, `branch -a` | `add`, `commit`, `push`, `pull`, `merge` | `push --force`, `reset --hard`, `clean -fd` |
### Shortcut CLI
[shortcut-cli](https://github.com/shortcut-cli/shortcut-cli) - Community CLI for Shortcut
| Allow | Ask |
| ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `search`, `find`, `story` (view), `members`, `epics`, `workflows`, `projects`, `help` | `create`, `install`, `story` (with update flags), `search --save`, `api` (POST/PUT/DELETE) |
### Cloud CLIs
AWS, gcloud, terraform, kubectl, docker, podman, az, helm, pulumi
| Allow | Ask | Block |
| --------------------------------------------- | ------------------------------------------ | ------------------------------------------ |
| `describe-*`, `list-*`, `get`, `show`, `plan` | `create`, `delete`, `apply`, `run`, `exec` | `iam delete-user`, `delete ns kube-system` |
### Network
| Allow | Ask | Block |
| ----------------------------- | -------------------------------------- | ----------------------- |
| `curl` (GET), `wget --spider` | `curl -X POST`, `wget`, `ssh`, `rsync` | `nc -e` (reverse shell) |
### Filesystem
| Allow | Ask | Block |
| --------------------- | ----------------------------------- | ---------------------- |
| `tar -tf`, `unzip -l` | `rm`, `mv`, `cp`, `chmod`, `sed -i` | `rm -rf /`, `rm -rf ~` |
### Developer Tools
~50+ tools with write-flag detection: `jq`, `shellcheck`, `hadolint`, `vite`, `vitest`, `jest`, `tsc`, `esbuild`, `turbo`, `nx`
| Safe by default | Ask with flags |
| ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
| `ast-grep`, `yq`, `semgrep`, `sad`, `prettier`, `eslint`, `biome`, `ruff`, `black`, `gofmt`, `rustfmt`, `golangci-lint` | `-U`, `-i`, `--fix`, `--write`, `--commit`, `--autofix` |
| `sd` (pipe mode safe, ask with file args), always ask: `watchexec` (runs commands), `dos2unix` | |
### Package Managers
npm, pnpm, yarn, pip, uv, cargo, go, bun, conda, poetry, pipx, mise
| Allow | Ask |
| -------------------------------------- | -------------------------------------------- |
| `list`, `show`, `test`, `build`, `dev` | `install`, `add`, `remove`, `publish`, `run` |
### System
**Database CLIs:** psql, mysql, sqlite3, mongosh, redis-cli
**Build tools:** make, cmake, ninja, just, gradle, maven, bazel
**OS Package managers:** apt, brew, pacman, nix, dnf, zypper, flatpak, snap
**Other:** sudo, systemctl, crontab, kill
| Allow | Ask | Block |
| ----------------------------------------------- | --------------------------------- | ----------------------------------------------------------------- |
| `psql -l`, `make test`, `sudo -l`, `apt search` | `make deploy`, `sudo apt install` | `shutdown`, `reboot`, `mkfs`, `dd`, `fdisk`, `iptables`, `passwd` |
---
## Security Features
### Pre-AST Security Checks
Comments are stripped before checking (quote-aware, respects bash word-boundary rules for `#`) so patterns inside comments don't trigger false positives.
```bash
curl https://example.com | bash # ask - pipe to shell
eval "rm -rf /" # ask - arbitrary execution
source ~/.bashrc # ask - sourcing script
echo $(rm -rf /tmp/*) # ask - dangerous substitution
find . | xargs rm # ask - xargs to rm
echo "data" > /etc/passwd # ask - output redirection
```
### Compound Command Handling
Strictest decision wins:
```bash
git status && rm -rf / # deny (rm -rf / blocked)
git status && npm install # ask (npm install needs approval)
git status && git log # allow (both read-only)
```
### Smart sudo Handling
```bash
sudo apt install vim # ask - "sudo: Installing packages (apt)"
sudo systemctl restart nginx # ask - "sudo: systemctl restart"
```
---
## Testing
```bash
cargo test # Full suite
cargo test gates::git # Specific gate
cargo test -- --nocapture # With output
```
### Manual Testing
```bash
# Allow
echo '{"tool_name":"Bash","tool_input":{"command":"git status"}}' | bash-gates
# -> {"hookSpecificOutput":{"permissionDecision":"allow"}}
# Ask
echo '{"tool_name":"Bash","tool_input":{"command":"npm install"}}' | bash-gates
# -> {"hookSpecificOutput":{"permissionDecision":"ask","permissionDecisionReason":"npm: Installing packages"}}
# Deny
echo '{"tool_name":"Bash","tool_input":{"command":"rm -rf /"}}' | bash-gates
# -> {"hookSpecificOutput":{"permissionDecision":"deny"}}
```
---
## Architecture
```
src/
├── main.rs # Entry point, CLI commands
├── models.rs # Types (HookInput, HookOutput, Decision)
├── parser.rs # tree-sitter-bash AST parsing
├── router.rs # Security checks + gate routing
├── settings.rs # settings.json parsing and pattern matching
├── hints.rs # Modern CLI hints (cat→bat, grep→rg, etc.)
├── tool_cache.rs # Tool availability cache for hints
├── mise.rs # Mise task file parsing and command extraction
├── package_json.rs # package.json script parsing and command extraction
├── tracking.rs # PreToolUse→PostToolUse correlation (15min TTL)
├── pending.rs # Pending approval queue (JSONL format)
├── patterns.rs # Pattern suggestion algorithm
├── post_tool_use.rs # PostToolUse handler
├── permission_request.rs # PermissionRequest hook handler
├── settings_writer.rs # Write rules to Claude settings files
├── toml_export.rs # TOML policy export for Gemini CLI
├── generated/ # Auto-generated by build.rs (DO NOT EDIT)
│ ├── rules.rs # Rust gate functions from rules/*.toml
│ └── toml_policy.rs # Gemini CLI TOML policy string
├── tui/ # Interactive review TUI (three-panel dashboard)
└── gates/ # 13 specialized permission gates
├── mod.rs # Gate registry (ordered by priority)
├── helpers.rs # Common gate helper functions
├── bash_gates.rs # bash-gates CLI itself
├── basics.rs # Safe commands (~130+)
├── beads.rs # Beads issue tracker (bd) - github.com/steveyegge/beads
├── mcp.rs # MCP CLI (mcp-cli) - Model Context Protocol
├── gh.rs # GitHub CLI
├── git.rs # Git
├── shortcut.rs # Shortcut CLI (short) - github.com/shortcut-cli/shortcut-cli
├── cloud.rs # AWS, gcloud, terraform, kubectl, docker, podman, az, helm, pulumi
├── network.rs # curl, wget, ssh, rsync, netcat, HTTPie
├── filesystem.rs # rm, mv, cp, chmod, tar, zip
├── devtools.rs # sd, ast-grep, yq, semgrep, biome, prettier, eslint, ruff, black
├── package_managers.rs # npm, pnpm, yarn, pip, uv, cargo, go, bun, conda, poetry, pipx, mise
└── system.rs # psql, mysql, make, sudo, systemctl, OS pkg managers, build tools
```
---
## Gemini CLI Integration
Gemini CLI's hook system cannot prompt users (only allow/block). Use the policy engine instead:
```bash
bash-gates --export-toml > ~/.gemini/policies/bash-gates.toml
```
This exports 700+ policy rules derived from the gate definitions:
| Priority | Action | Examples |
| -------- | ---------- | ------------------------------------- |
| 900+ | `deny` | `rm -rf /`, `gh repo delete` |
| 200-299 | `ask_user` | `npm install`, `git push` |
| 100-199 | `allow` | `git status`, `ls`, `cat` |
| 1 | `ask_user` | Default fallback for unknown commands |
---
## Links
- [Claude Code Hooks Documentation](https://code.claude.com/docs/en/hooks)
- [Claude Code MCP-CLI (experimental)](https://github.com/anthropics/claude-code/issues/12836#issuecomment-3629052941)
- [tree-sitter-bash](https://github.com/tree-sitter/tree-sitter-bash)
- [Beads Issue Tracker](https://github.com/steveyegge/beads)
- [Shortcut CLI](https://github.com/shortcut-cli/shortcut-cli)