Useful Pluginsshell_approval
DocsUseful Pluginsshell_approval

shell_approval

Require user approval before executing shell commands

What it does

Before executing shell commands, this plugin:

Auto-approves safe commands

Read-only commands like ls, cat, git status execute without prompts.

Asks approval for other commands

Commands that modify files, install packages, or have side effects require user confirmation.

Quick Start

main.py
from connectonion import Agent from connectonion.useful_plugins import shell_approval def run_command(command: str) -> str: """Execute a shell command.""" import subprocess return subprocess.check_output(command, shell=True).decode() agent = Agent("devops", tools=[run_command], plugins=[shell_approval]) agent.input("List files then delete test.txt")
output
[Tool: run_command("ls")] # Auto-approved (safe)
file1.txt test.txt readme.md
 
┌─ Shell Command ────────────────────┐
│ rm test.txt │
└────────────────────────────────────┘
Execute this command?
> Yes, execute
> Auto approve 'rm' in this session
> Skip, let agent figure it out
> Stop, tell agent what I want

Want to customize? Run co copy shell_approval to get an editable copy.

Safe Commands (Auto-Approved)

These read-only commands are automatically approved:

File Operations

  • ls, ll
  • cat, head, tail
  • less, more
  • find, fd
  • grep, rg
  • tree, wc

Git (Read-Only)

  • git status
  • git log
  • git diff
  • git show
  • git branch
  • git remote

System Info

  • pwd, whoami
  • env, printenv
  • uname, hostname
  • df, du, free
  • ps, top
  • which, file

Approval Options

When prompted for approval, you can:

1.
Yes, execute

Execute this specific command

2.
Auto approve '{cmd}'

Auto-approve all commands starting with this (e.g., all rm commands for this session)

3.
Skip, let agent figure it out

Soft reject — this tool call is skipped, the loop continues, and the agent is nudged to ask what you'd prefer

4.
Stop, tell agent what I want

Hard reject — prompts you for feedback right away and halts the current tool batch

How it works

main.py
@before_each_tool def _check_approval(agent): pending = agent.current_session.get('pending_tool') if not pending: return # Only check bash/shell tools if pending['name'] not in ('bash', 'shell', 'run', 'run_in_dir'): return command = pending['arguments'].get('command', '') base_cmd = command.strip().split()[0] if command.strip() else '' # Skip if this command type was auto-approved approved_cmds = agent.current_session.get('shell_approved_cmds', set()) if base_cmd in approved_cmds: return # Skip if safe read-only command if _is_safe(command): return # Show command and ask for approval choice = pick("Execute this command?", [ "Yes, execute", f"Auto approve '{base_cmd}' in this session", "Skip, let agent figure it out", "Stop, tell agent what I want", ]) if choice == "Yes, execute": return elif choice.startswith("Auto approve"): agent.current_session.setdefault('shell_approved_cmds', set()).add(base_cmd) return elif choice.startswith("Skip"): raise ValueError(f"User rejected command '{base_cmd}'.") # soft reject, loop continues else: feedback = input("What do you want the agent to do instead? ") raise ValueError(f"User feedback: {feedback}")

Events Used

EventHandlerPurpose
before_each_tool_check_approvalCheck and prompt before shell commands

Source

connectonion/useful_plugins/shell_approval.py

main.py
# The plugin is just a list with one event handler shell_approval = [before_each_tool(_check_approval)]

Star us on GitHub

If ConnectOnion saves you time, a ⭐ goes a long way — and earns you a coffee chat with our founder.