pi-bash-confirm
Pi package for confirming bash commands before execution with Telegram notifications
Package details
Install pi-bash-confirm from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-bash-confirm- Package
pi-bash-confirm- Version
3.0.0- Published
- Jul 22, 2026
- Downloads
- 104/mo · 24/wk
- Author
- matteo.collina
- License
- MIT
- Types
- extension
- Size
- 101.7 KB
- Dependencies
- 0 dependencies · 3 peers
Pi manifest JSON
{
"extensions": [
"./extensions/bash-confirm.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-bash-confirm
A pi package that adds a confirmation dialog before executing bash commands in the TUI, with Telegram notification support for blocked and modified commands.
Features
- Confirmation Dialog: Interactively approve, edit, always accept (exact/generic), or block bash commands before execution
- Interactive Settings: Use
/bash-confirmto configure confirmation and auto-accept from one compact panel - Command Patterns: Configure safe commands (auto-allow) and blocked commands (auto-block) using regex
- Per-Project Whitelist: Commands added as exact or regex-pattern entries won't prompt again in that project
- Edit Mode: Modify commands before approval using pi's built-in editor
- Telegram Notifications: Get notified when commands are blocked or modified
- Optional auto-accept Mode: Let a configurable fast model auto-allow or route to manual review
- Non-Interactive Safety: Blocks commands when UI is unavailable unless they match safe patterns (or auto-accept explicitly allows)
- Easy Configuration: All settings configurable via
settings.jsonor environment variables
Installation
Requires pi / @earendil-works/pi-coding-agent 0.80.x.
pi install npm:pi-bash-confirm
Quick Start
After installation, the extension automatically loads and will ask for confirmation before any bash command execution.
Basic Configuration
Create or edit ~/.pi/agent/settings.json (global) or .pi/settings.json (project):
{
"bashConfirm": {
"enabled": true,
"safeCommands": [
"^ls"
],
"blockedCommands": [
"rm -rf",
"sudo .* rm",
":>.*",
"^dd "
],
"autoAccept": {
"enabled": false,
"model": "openrouter/google/gemini-2.0-flash-001",
"timeoutMs": 5000,
"strictness": "permissive"
}
}
}
Telegram Notifications
To enable Telegram notifications for blocked and modified commands:
{
"bashConfirm": {
"notifications": {
"enabled": true,
"onShown": false,
"onBlocked": true,
"onModified": true,
"onAllowed": false,
"telegram": {
"enabled": true,
"token": "YOUR_BOT_TOKEN",
"chatId": "YOUR_CHAT_ID",
"timeoutMs": 5000,
"forceIpv4": true
}
}
}
}
Alternatively, use environment variables:
export TELEGRAM_BOT_TOKEN="your_bot_token"
export TELEGRAM_CHAT_ID="your_chat_id"
# or
export PI_TELEGRAM_TOKEN="your_bot_token"
export PI_TELEGRAM_CHAT_ID="your_chat_id"
Interactive Settings
Run one command—without arguments or subcommands:
/bash-confirm
The panel controls bash confirmation, auto-accept, and auto-accept policy for the current session. Persistent defaults remain in settings.json. Disabling bash confirmation also bypasses configured blocked-command checks for that session.
To show debug notifications explaining why commands were allowed or blocked, set bashConfirm.debug to true in settings.json.
Configuration
Global Options
| Setting | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | true |
Enable/disable the extension |
debug |
boolean | false |
Show debug notifications explaining why a command was allowed/blocked |
safeCommands |
string[] | [] |
Regex patterns for auto-allowed commands |
blockedCommands |
string[] | [] |
Regex patterns for always-blocked commands |
autoAccept.enabled |
boolean | false |
Enable optional model-based auto-accept decision flow |
autoAccept.model |
string | "" |
Model reference (provider/modelId) used for auto-accept; falls back to current model when empty |
autoAccept.timeoutMs |
number | 5000 |
Timeout for auto-accept model request (clamped to 1000-20000 ms) |
autoAccept.strictness |
string | "permissive" |
Auto-accept policy mode: strict (narrow) or permissive (broader local dev writes allowed) |
autoAccept.neverAllowPatterns |
string[] | [] |
Regex patterns that must always require manual confirmation (auto-accept is skipped) |
Notification Options
| Setting | Type | Default | Description |
|---|---|---|---|
notifications.enabled |
boolean | false |
Enable notification system |
notifications.onShown |
boolean | false |
Send notifications when confirmation dialog is displayed |
notifications.onBlocked |
boolean | true |
Send notifications for blocked commands |
notifications.onModified |
boolean | true |
Send notifications for modified commands |
notifications.onAllowed |
boolean | false |
Send notifications for allowed commands |
Telegram Options
| Setting | Type | Default | Description |
|---|---|---|---|
notifications.telegram.enabled |
boolean | false |
Enable Telegram notifications |
notifications.telegram.token |
string | - | Telegram bot token (or use env var) |
notifications.telegram.chatId |
string | - | Telegram chat ID (or use env var) |
notifications.telegram.timeoutMs |
number | 5000 |
Request timeout in milliseconds |
notifications.telegram.forceIpv4 |
boolean | true |
Force IPv4 for Telegram API |
Telegram Bot Setup
1. Create a Bot
- Open Telegram and search for @BotFather
- Send
/newbotand follow the prompts - Copy the bot token (looks like
123456789:ABCdefGHIjklMNOpqrsTUVwxyz)
2. Get Your Chat ID
Method 1: Using curl
curl https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates
Send a message to your bot first, then run the command. Look for "chat":{"id":123456789} in the response.
Method 2: Direct message
- Send
/startto your bot - Use the curl method above to get your chat ID
3. Configure
Add to your settings.json:
{
"bashConfirm": {
"notifications": {
"enabled": true,
"telegram": {
"enabled": true,
"token": "123456789:ABCdefGHIjklMNOpqrsTUVwxyz",
"chatId": "123456789"
}
}
}
}
See docs/telegram-setup.md for detailed instructions.
Usage Examples
Safe Commands
Configure safe commands to bypass confirmation:
{
"bashConfirm": {
"enabled": true,
"debug": false,
"safeCommands": [
"^ls",
"^pwd",
"^cd",
"^rg",
"^grep",
"^find(?!.*-(exec|ok|delete|execdir))",
"^cat",
"^echo",
"^head",
"^tail",
"^wc",
"^sort",
"^uniq",
"^cut",
"^tr",
"^awk",
"^file",
"^stat",
"^diff",
"^cmp",
"^basename",
"^dirname",
"^realpath",
"^readlink",
"^which",
"^whereis",
"^whatis",
"^type",
"^id",
"^whoami",
"^who",
"^uname",
"^hostname",
"^date",
"^cal",
"^env",
"^ps",
"^pgrep",
"^top",
"^htop",
"^df",
"^du",
"^free",
"^uptime",
"^lscpu",
"^lsmem",
"^lsusb",
"^lspci",
"^lsblk",
"^mount$",
"^ifconfig",
"^ip addr",
"^ip link",
"^ip route",
"^netstat",
"^ss",
"^ping",
"^curl(?!.*-[Oo])",
"^git (status|log|diff|show|branch|remote|config|stash list)",
"^cat .+\\.md$",
"^gh issue view .*$",
"^gh pr view .*$",
"^gh pr diff .*$",
"^gh run .*$",
"^gh repo view .*$"
]
}
}
Blocked Commands
Block dangerous patterns:
{
"bashConfirm": {
"blockedCommands": [
"rm -rf /", # Prevent root deletion
"rm -rf .*\\.git", # Protect .git directories
"sudo .* rm", # Block sudo + rm
":>", # Prevent file truncation
"^dd if=", # Block dd commands
"mkfs\\.", # Block filesystem creation
"> /dev/sda" # Block disk writes
]
}
}
Project-Specific Settings
Create .pi/settings.json in your project directory:
{
"bashConfirm": {
"safeCommands": [
"^npm (install|test|run)",
"^node .+\\.js$"
],
"blockedCommands": [
"rm -rf node_modules"
]
}
}
Confirmation Dialog
When a bash command is intercepted, you'll see:
⚠️ Bash Command Confirmation
Command:
git push origin main
Working directory: /home/user/project
> 1. Allow
Execute the command as-is
2. Always Accept (Exact)
Whitelist this exact command and execute
3. Always Accept (Generic)
Generate a regex pattern whitelist entry
4. Edit
Modify the command before execution
5. Block
Cancel this command
↑↓ navigate • enter select • 1-5 quick pick • esc cancel
Options:
- Allow (1): Execute the command as-is
- Always Accept (Exact) (2): Add an exact-match command whitelist entry
- Always Accept (Generic) (3): The dialog always shows the generated regex preview; selecting this lets you review/edit and whitelist it
- Edit (4): Open an editor to modify the command before approval
- Block (5): Cancel the command execution
- Cancel (ESC): Dismiss the dialog and cancel the command execution
You can quickly select an option by pressing its number (1-5) on your keyboard, or use arrow keys and Enter.
Always Accept & Whitelist
The dialog supports two whitelist modes:
- Always Accept (Exact): stores the exact command string
- Always Accept (Generic): generates a regex pattern, lets you edit it, then stores it
How It Works
- Entry types: whitelist entries are either
exactorpattern - Per-project storage: the whitelist is stored in
.pi/bash-confirm-whitelist.jsonrelative to your project root - Match order:
blockedCommands→ exact whitelist → pattern whitelist →safeCommands - Survives restarts: the whitelist persists across pi sessions
Example Flow
1. User runs: git push origin feature/my-branch
2. Confirmation dialog appears
3. User selects: "Always Accept (Generic)" (option 3)
4. Extension proposes a pattern like: ^git\s+push\s+origin\s+[\w./-]+$
5. User confirms/edits the pattern and command executes
6. Future matching push commands execute without prompt
Managing the Whitelist
Add entries directly from the confirmation dialog with Always Accept (Exact) or Always Accept (Generic). To inspect, remove, or share entries, edit .pi/bash-confirm-whitelist.json.
Whitelist File Format
{
"entries": [
{
"type": "exact",
"value": "git push origin main",
"addedAt": "2026-01-26T16:51:49.123Z",
"note": "Always accept exact",
"source": "user"
},
{
"type": "pattern",
"value": "^git\\s+push\\s+origin\\s+[\\w./-]+$",
"addedAt": "2026-01-26T16:52:12.000Z",
"note": "Always accept generic",
"source": "ai"
}
],
"version": 2
}
The whitelist file can be committed to version control if you want to share whitelisted commands with your team.
Optional auto-accept Mode (Fast Model)
When bashConfirm.autoAccept.enabled is true, commands that would normally open the confirmation dialog are first reviewed by a fast model.
The model must return one of:
allow→ command executes immediatelyreview→ fallback to the normal confirmation dialog (or block in non-interactive mode)
If the model returns block, the extension downgrades that to review and asks a human.
Example:
{
"bashConfirm": {
"autoAccept": {
"enabled": true,
"model": "openrouter/google/gemini-2.0-flash-001",
"timeoutMs": 4000,
"strictness": "permissive",
"neverAllowPatterns": [
"^git\\s+push(?:\\s|$)",
"^npm\\s+publish(?:\\s|$)"
]
}
}
}
Notes:
- This mode is optional and off by default.
- Use
autoAccept.strictnessto tune policy:strictfavors check-only commands, whilepermissivecan allow bounded local dev write workflows (for examplegit commit,eslint --fix, orprettier --write). - High-risk operations (for example rebase/reset/push, publish/deploy, destructive deletes, privilege escalation) should fall back to manual review.
- Use
autoAccept.neverAllowPatternsto force manual review for command families you never want auto-approved. - Use
/bash-confirmto override auto-accept and strictness for the current session. - Use a low-latency model to keep shell flow responsive.
- The command text is sent to the configured model for evaluation.
Notification Examples
Dialog Shown Notification
⏳ Command Confirmation Requested
Session: abc12345
Directory: /home/user/project
Command
ls -la /home/user/project
2026-01-26T16:51:49.123Z
Blocked Command Notification
⛔ Command Blocked
Session: abc12345
Directory: /home/user/project
Command
rm -rf /path/to/directory
Reason
User rejected via confirmation dialog
2026-01-26T16:51:49.123Z
Modified Command Notification
✏️ Command Modified
Session: abc12345
Directory: /home/user/project
Original
rm -rf ./old-dir
Modified
rm -rf ./old-dir-backup
2026-01-26T16:52:10.456Z
Command
| Command | Description |
|---|---|
/bash-confirm |
Open the interactive session settings panel |
Configuration Priority
Settings are loaded in this order (later overrides earlier):
- Extension defaults
- Global settings (
~/.pi/agent/settings.json) - Project settings (
.pi/settings.json) - Environment variables (
TELEGRAM_BOT_TOKEN,TELEGRAM_CHAT_ID)
Non-Interactive Mode
When pi is running in non-interactive mode (print, JSON, RPC), the extension will:
- Block all bash commands unless they match a
safeCommandspattern - If
auto-acceptis enabled, run model review first (allow/review) - Block when manual confirmation is required but no UI is available
- Send blocked command notifications (if configured)
To allow commands in non-interactive mode, add them to safeCommands or enable auto-accept with a conservative fast model.
Troubleshooting
Notifications Not Working
- Verify bot token and chat ID are correct
- Make sure notifications are enabled:
bashConfirm.notifications.enabled: true - Set
bashConfirm.debugtotrueand retry a command - Check Telegram bot is running (send it a message)
- Verify bot token hasn't expired
All Commands Blocked
If commands are being blocked unexpectedly:
- Open
/bash-confirmand check that bash confirmation is enabled - Verify commands don't match
blockedCommandspatterns - Set
bashConfirm.debugtotruefor decision notifications - Add safe patterns to
safeCommandsif needed
Invalid Regex Patterns
If a regex pattern is invalid, it will be silently skipped. Test your patterns:
new RegExp("your-pattern").test("test-string")
License
MIT
Contributing
Contributions welcome! Please open an issue or submit a pull request.
Local Development
For local development and testing, pi does not support installing packages from local directories via pi install. Instead, use one of these methods:
Method 1: Copy Extension File (Recommended)
Global installation (applies to all projects):
cp extensions/bash-confirm.ts ~/.pi/agent/extensions/
Project installation (applies to current project only):
mkdir -p .pi/extensions
cp extensions/bash-confirm.ts .pi/extensions/
Method 2: Add to Settings.json
Global settings (~/.pi/agent/settings.json):
{
"packages": [
"/absolute/path/to/pi-permission"
]
}
Project settings (.pi/settings.json):
{
"packages": [
"./extensions/bash-confirm.ts"
]
}
Method 3: Use as Single Extension
You can also load the extension file directly:
{
"packages": [
"/absolute/path/to/pi-permission/extensions/bash-confirm.ts"
]
}
Testing
After installing locally:
- Restart pi
- Run
/bash-confirmto verify the settings panel opens - Try running a bash command to see the confirmation dialog
Development Workflow
- Make changes to
extensions/bash-confirm.ts - For Method 1: Re-copy the file to the extensions directory
- For Methods 2 & 3: Restart pi to reload changes
- Test with
/bash-confirmand bash commands
Related
- pi - AI coding agent
- pi packages documentation
- pi extensions documentation