Usage Guide¶
Complete guide to using Shannot for safe, sandboxed script execution.
Quick Start¶
# Install PyPy runtime (one-time)
shannot setup
# Run a script in the sandbox
shannot run script.py
# Review and approve pending operations
shannot approve
# Check system status
shannot status
CLI Commands¶
shannot setup¶
Install PyPy stdlib for sandboxing.
shannot setup # Install runtime
shannot setup --force # Force reinstall
shannot setup --status # Check if installed
shannot setup --remove # Remove installed runtime
shannot setup --quiet # Suppress progress output
shannot run¶
Execute a Python script in the PyPy sandbox.
shannot run script.py # Basic execution
shannot run script.py --tmp=/tmp/work # Map real directory to /tmp
shannot run script.py --dry-run # Queue operations without executing
shannot run script.py --target prod # Execute on remote target
Options:
| Option | Description |
|---|---|
--pypy-sandbox PATH |
Path to pypy-sandbox executable |
--lib-path PATH |
Path to lib-python and lib_pypy |
--tmp DIR |
Real directory mapped to virtual /tmp |
--dry-run |
Log commands without executing |
--script-name NAME |
Human-readable session name |
--analysis DESC |
Description of script purpose |
--target NAME |
SSH target for remote execution |
--nocolor |
Disable ANSI coloring |
--raw-stdout |
Disable output sanitization |
--debug |
Enable debug mode |
shannot approve¶
Interactive TUI for reviewing and approving pending sessions.
shannot approve # Launch TUI
shannot approve list # List pending sessions
shannot approve show SESSION_ID # Show session details
shannot approve history # Show recent sessions
TUI Controls:
| Key | Action |
|---|---|
j/k or ↑/↓ |
Navigate up/down |
Enter |
View details / Execute |
Space |
Toggle selection |
x |
Execute selected sessions |
r |
Reject selected sessions |
a |
Select all |
n |
Deselect all |
q / Esc |
Quit / Go back |
shannot execute¶
Execute a previously created session directly.
This is primarily used by the remote execution protocol.
shannot remote¶
Manage SSH remote targets.
shannot remote add NAME [USER@]HOST # Add remote target
shannot remote list # List configured targets
shannot remote test NAME # Test connection
shannot remote remove NAME # Remove target
Add options:
shannot status¶
Show system health and configuration status.
shannot status # Full status
shannot status --runtime # Runtime status only
shannot status --targets # Remote targets only
Session Workflow¶
Shannot uses a session-based approval workflow for subprocess execution:
1. Dry-Run Phase¶
When a script runs in the sandbox, subprocess calls are captured but not executed:
# script.py
import subprocess
subprocess.call(['df', '-h']) # Captured, not executed
subprocess.call(['rm', '-rf', '/']) # Captured, blocked by profile
2. Review Phase¶
Use the interactive TUI to review captured operations:
The TUI shows: - Pending subprocess commands - Which commands match auto_approve (will execute immediately) - Which commands match always_deny (will be blocked) - Which commands require manual approval
3. Execute Phase¶
After approval, operations execute on the host system:
# From TUI: press 'x' to execute selected sessions
# Or directly:
shannot approve show SESSION_ID # Review details
# Then press 'x' in TUI
Approval Profiles¶
Profiles control which commands execute automatically vs. require approval.
Profile Structure¶
{
"auto_approve": [
"cat", "ls", "find", "grep", "head", "tail", "df", "free"
],
"always_deny": [
"rm -rf /",
"dd if=/dev/zero",
":(){ :|:& };:"
]
}
Profile Locations¶
.shannot/profile.json(project-local, highest priority)~/.config/shannot/profile.json(global)- Built-in default profile
Command Matching¶
Commands are matched by their base name (path stripped):
subprocess.call(['/usr/bin/cat', '/etc/passwd']) # Matches "cat"
subprocess.call(['cat', '/etc/passwd']) # Matches "cat"
See Profile Configuration for details.
Remote Execution¶
Execute sandboxed scripts on remote Linux hosts via SSH.
Setup Remote Target¶
# Add remote
shannot remote add prod user@prod.example.com
# Test connection
shannot remote test prod
Run on Remote¶
# Execute script on remote
shannot run script.py --target prod
# The workflow is the same:
# 1. Script runs in sandbox on remote
# 2. Operations captured in session
# 3. Review with `shannot approve`
# 4. Execute approved operations
Auto-Deployment¶
When executing on a remote for the first time, Shannot automatically:
1. Deploys itself to the remote (/tmp/shannot-v{version}/)
2. Sets up the PyPy runtime
3. Executes the sandboxed script
No manual installation on remotes is required.
Python 3.6 Compatibility¶
Important: Sandboxed scripts run in PyPy's Python 3.6 environment.
Supported Syntax¶
# OK: f-strings (Python 3.6+)
print(f"Value: {x}")
# OK: Basic type annotations
def greet(name: str) -> str:
return f"Hello, {name}"
Not Supported¶
# NOT OK: Match statements (Python 3.10+)
match value:
case 1: print("one")
# NOT OK: Union type syntax (Python 3.10+)
def process(x: int | str): pass
# NOT OK: Walrus operator (Python 3.8+)
if (n := len(items)) > 10: pass
# NOT OK: dataclasses (Python 3.7+)
from dataclasses import dataclass
Workarounds¶
# Instead of dataclasses, use namedtuple
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
# Instead of union types, use comments
def process(x): # type: (Union[int, str]) -> None
pass
Common Use Cases¶
System Diagnostics¶
# diagnostics.py
import subprocess
print("=== Disk Usage ===")
subprocess.call(['df', '-h'])
print("\n=== Memory ===")
with open('/proc/meminfo') as f:
for line in f.readlines()[:5]:
print(line.strip())
print("\n=== Processes ===")
subprocess.call(['ps', 'aux', '--sort=-pcpu'])
Log Analysis¶
# analyze_logs.py
import subprocess
# These commands are typically auto-approved
subprocess.call(['grep', 'ERROR', '/var/log/app.log'])
subprocess.call(['tail', '-n', '100', '/var/log/syslog'])
Configuration Inspection¶
# check_config.py
import os
# Read system configuration
with open('/etc/os-release') as f:
print(f.read())
# Check environment
for key, value in sorted(os.environ.items()):
print(f"{key}={value}")
Limitations¶
What Sandboxed Code CAN Do¶
- Read files from virtual filesystem
- Execute subprocess calls (captured for approval)
- Write to virtual /tmp (mapped to real directory if configured)
- Access virtual /proc for system information
What Sandboxed Code CANNOT Do¶
- Modify the host filesystem directly
- Access the network (sockets disabled)
- Execute code outside the sandbox
- Bypass the approval workflow for subprocess calls
Known Constraints¶
- Python 3.6 syntax only - PyPy sandbox limitation
- 1-hour session TTL - Pending sessions expire after 1 hour
- No interactive input - stdin is not passed through by default
Next Steps¶
- Profile Configuration - Customize command approval
- Configuration Guide - Remote targets and MCP
- Deployment Guide - Production deployment
- Troubleshooting - Common issues