Open source, MIT. Your agent gets a copy of the repo, fake credentials, a throwaway database and a container. You get an audit trail and a diff to sign off.
ln -s $PWD/panic.py ~/.local/bin/panic
cd ~/code/myapp
panic run --db -c "claude -p 'refactor the billing module'"
panic shot <id> http://localhost:3000 --serve "npm run dev"
panic report <id> # files, commands, sql, egress, screenshots
panic diff <id>
panic approve <id> # applies to the real repo, unstaged
panic rm <id>
First run builds a panicroom:base image (node 22, git, chromium, psql, claude-code). After that a
sandbox costs a git clone.
Files. The repo is cloned to ~/.panicroom/<id>/repo, your uncommitted work is carried over and
committed as a baseline, so every later diff is the agent's doing and not yours. panic diff is a
plain git diff; approve is a plain git apply, left unstaged for you to read before committing.
No filesystem watcher, git already knows.
Commands. $HOME/.claude/settings.json in the sandbox carries a PreToolUse hook that appends
every tool call to /panic/audit.jsonl. That is the agent's real actions, not scraped terminal
output, and it lives outside the repo so it never shows up in the diff.
Database. --db starts a throwaway postgres beside the sandbox with log_statement=all and
points every SQL-shaped env var at it. On exit the log is kept and panic report shows the writes,
reads filtered out. --db-schema dump.sql seeds it so the agent works against your real shape.
Network. A proxy bound to the docker gateway, never the LAN. Every host the sandbox connects to
is logged, and every host that appears in your real .env is refused with a 403. If the agent tries
to reach prod, it fails and the attempt is on the record. Hosts and ports, no TLS interception.
Screenshots. panic shot starts your dev server inside the sandbox, waits, and drives headless
chromium at it. PNGs land in the sandbox audit dir.
Every .env* in the source is read for its keys, never its values. URLs keep their scheme and point
at localhost, connection strings become panic:panic@localhost, everything else becomes
panic-dummy-<key>. The generated .env is git-excluded, so it can never ride along into approve,
and it is passed to the container as --env-file so shell tools see it too. Only your agent API key
crosses the boundary from your own environment.
Check: python3 test_panic.py (round trip, proxy allow and block, sql filtering, no creds in the patch).
Teams, billing, a web dashboard, a hosted control plane. One founder, one repo, one terminal.
Issues and pull requests are welcome. Keep it to one Python file with no dependencies outside the
stdlib, and make python3 test_panic.py pass.
MIT, see LICENSE.