Sandbox orchestration for Claude Code. Launches an interactive Claude Code session inside a Podman container, with a credential gateway that strips and re-injects API keys outbound, scopes secrets per binary, and applies a YAML policy that controls egress and package trust.
Status: experimental. macOS (Apple Silicon) and Linux.
macOS host Linux host
├── openlock CLI (Bun) ├── openlock CLI (Bun)
├── openshell-gateway (port 18081) ├── openshell-gateway (port 18081)
└── Podman Machine (Apple HV) └── podman (rootless)
└── sandbox container └── sandbox container
Each openlock sandbox <path> call:
- Detects capabilities (js / py) from the project, picks an image and policy.
- Builds the supervisor + sandbox images via
podman buildif missing. - Starts the gateway (
cargo buildfirst run, ~1–2 min). - Bundles your repo with
git bundle, uploads it, pre-trusts/sandbox/repo. - Injects host git identity (
user.name/user.emailfromgit config --global). - Launches Claude Code inside the sandbox; outbound traffic flows through the gateway with credentials injected from your
openlock logintoken. - On exit, fetches sandbox commits back into your repo under
refs/sandbox/<session>/*. - Container persists (entrypoint is
sleep infinity) so you can resume the same session later. Re-runningopenlock sandbox <path>reattaches. - Stops the gateway when no other
openshell-sandbox-*containers remain.
curl -fsSL https://raw.githubusercontent.com/vessux/openlock/main/install.sh | shDrops openlock into ~/.local/bin. Set OPENLOCK_INSTALL_DIR to override. The fork binaries (gateway, supervisor, openshell CLI) are fetched lazily on first run into ~/.cache/openlock/bin/.
- podman —
podman machinestarted on macOS, or a reachable rootless socket on Linux (systemctl --user enable --now podman.socket) gitclaudeCLI inside the sandbox is bundled into the container image — no host install needed
Verify with openlock doctor.
The golden path is install → doctor → init → validate → sandbox:
# Linux only: enable the podman API socket once
systemctl --user enable --now podman.socket
openlock doctor # check prerequisites, get actionable fixes
openlock init /path/to/your/repo # scaffold .openlock/ (interactive)
openlock validate /path/to/your/repo # lint the manifest + policy
openlock sandbox /path/to/your/repo # launch (path defaults to cwd)sandbox requires an .openlock/ (run openlock init first, or it errors). The first
sandbox run prompts for claude setup-token if you have no credentials, runs git init
if the path isn't a git repo yet, and (re)attaches the session.
# launch (or resume) a sandbox for a project
openlock sandbox /path/to/your/repo
# rebuild sandbox images
openlock update-images
# manage the gateway directly (start keeps it running across cleanups)
openlock gateway start|stop|statusAfter the session exits, sandbox commits are in your repo under refs/sandbox/<session>/*. Inspect with git log refs/sandbox/<session>/main and merge or cherry-pick as needed.
| Command | Purpose |
|---|---|
doctor |
Check system health and prerequisites |
setup |
Configure machine defaults (runtime, harness, provider) |
login |
Authenticate with the gateway |
logout |
Remove stored provider credentials |
providers |
List configured providers |
init [path] |
Scaffold .openlock/ for a project (interactive) |
validate [path] |
Validate .openlock/ config + policy |
sandbox [path] |
Create or resume a sandbox session |
list |
List all sessions |
status [name] |
Show session metadata + container state |
stop [name] |
Stop session containers (preserves state) |
clean [name] |
Tear down session (rm container + state + host refs) |
reap |
Stop idle sessions (no removal) |
shell [name] |
Open bash inside the session container |
exec [name] -- <cmd> |
Run a command inside the session container |
refs |
Inspect and promote sandbox commits to real branches |
report |
Collect diagnostic bundle for bug reports |
gateway start|stop|status |
Manage the gateway |
update-images [--no-cache] |
Rebuild sandbox container images |
complete <bash|zsh|fish> |
Print shell completion script |
cred-refresh |
Start the credential refresh service |
Sandbox boundary. Always reach into a session via
openlock shell/openlock exec— neverpodman execdirectly, which bypasses the supervisor (egress policy,cred_inject, and the per-binary credential gate stop applying). See Security & runtime.
- Installation & shell completion
- Sessions: picker & lifecycle
- Mounts, args & env
- Policies
- Security & runtime
- Agent config reference — for AI agents configuring openlock
containers/ Containerfiles for the four sandbox images
policies/ YAML egress + trust policies
providers/ Credential refresh config
src/cli.ts Entry point
src/sandbox/ Sandbox orchestration
src/cred-refresh/ Credential refresh service
src/validate-policy/ Policy linter
For working on openlock itself, clone the openshell-fork sibling at ./openshell-fork and run from source:
git clone -b main https://github.com/vessux/OpenShell.git openshell-fork
bun install
bun run src/cli.ts <subcommand>When ./openshell-fork/.git exists, openlock auto-detects dev mode and builds the gateway / supervisor / openshell CLI from source instead of fetching the pinned release. Dev mode also requires bun, cargo, and on macOS cargo-zigbuild.
Apache-2.0. See LICENSE.