Metadata-Version: 2.1
Name: yolo-jail
Version: 0.7.1
Summary: Secure container jail for AI coding agents — run Claude Code, Copilot, Gemini, opencode, or pi in YOLO mode safely
Author: Matt Schulkind
License: Apache-2.0
Home-page: https://github.com/mschulkind-oss/yolo-jail
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# YOLO Jail

[![CI](https://github.com/mschulkind-oss/yolo-jail/actions/workflows/ci.yml/badge.svg)](https://github.com/mschulkind-oss/yolo-jail/actions/workflows/ci.yml)
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)

A secure, isolated container environment for AI coding agents (Claude Code, Copilot, Gemini CLI, opencode, pi, Codex) to safely modify codebases without compromising host security or identity. Pick which agents to install per project with the [`agents` config](#agents). Runs on **Linux and macOS** (Apple Silicon and Intel) with Podman or Apple Container.

## Why?

AI coding agents like Claude Code, GitHub Copilot, and Google Gemini CLI have a `--yolo` mode that lets them run shell commands without confirmation. This is powerful but dangerous — agents can access your SSH keys, cloud credentials, git identity, and anything else on your machine.

**YOLO Jail** lets you run agents in YOLO mode safely by isolating them in a container with:
- ❌ No access to `~/.ssh/`, `~/.gitconfig`, or cloud credentials
- ✅ Separate auth (`gh auth login`, `gemini login`, etc. inside the jail)
- ✅ Your codebase mounted read-write at `/workspace`
- ✅ Persistent tool state across restarts
- ✅ Pre-configured MCP servers, LSP servers, and modern CLI tools

## Features

- **Isolated:** Runs in a podman or Apple Container container with no access to host credentials
- **Optimized:** Pre-installed with modern, fast tools (`rg`, `fd`, `bat`, `eza`, `jq`, `delta`, `fzf`)
- **Restricted:** Blocked tools return clear errors with suggestions (e.g., `rg` instead of `grep`)
- **Reproducible:** Defined entirely via Nix Flakes
- **Agent-Ready:** MCP presets (Chrome DevTools, Sequential Thinking) and LSP servers (Pyright, TypeScript) — enable by name
- **Configurable:** Per-project config via `yolo-jail.jsonc`, user defaults via `~/.config/yolo-jail/config.jsonc`
- **Container Reuse:** Same workspace reuses the same container via `exec`
- **Runtime Flexible:** Works with podman (Linux/macOS) and Apple Container (macOS native)
- **Cross-Platform:** Full support for Linux and macOS (Apple Silicon and Intel)

## Prerequisites

Core requirements (both platforms):

- **[Nix](https://nixos.org/download/)** (with flakes enabled)
- A container runtime — one of:
  - **[Podman](https://podman.io/)** (preferred on Linux; Podman Machine on macOS)
  - **[Apple Container](https://github.com/apple/container)** (native macOS, `brew install container`)

Additionally, to [install from source](#from-source):

- **[Go](https://go.dev/dl/)** (see `go.mod` for the required version)
- **[just](https://github.com/casey/just)**

Platform specifics (in priority order):

- **Linux / x86_64** — any modern distribution with Podman. No extra setup. The primary target.
- **macOS / Apple Silicon** — via a native **arm64** Linux container (Apple Container or Podman Machine); no emulation. See [docs/guides/macos.md](docs/guides/macos.md).
- **Linux / arm64 (aarch64-linux)** — supported and CI-tested (image built + integration-tested natively on `ubuntu-24.04-arm`); same nix image as x86_64, no arch switch.
- **macOS / Intel** — also supported (x86_64 Linux container).

A remote Nix Linux builder is **optional** on macOS — the standard image builds entirely from the NixOS binary cache.

## Install

Four channels, all shipping the same single `yolo` binary. Pick whichever fits.

### Homebrew (easiest, macOS and Linux)

```bash
brew tap mschulkind-oss/tap
brew install mschulkind-oss/tap/yolo-jail
```

Works on macOS and Linuxbrew. Single command, auto-upgrades with `brew upgrade`. No source checkout, no `just` required.

### Go

```bash
go install github.com/mschulkind-oss/yolo-jail/cmd/yolo@latest
```

Builds straight from the module. Needs Go on the host; puts `yolo` in `$GOBIN` (or `$(go env GOPATH)/bin`).

### pipx / uvx

```bash
pipx install yolo-jail
# or, to run without installing:
uvx yolo-jail
```

The PyPI distribution is per-platform wheels wrapping the same prebuilt Go binary — there is no Python code and no Python runtime dependency beyond the installer itself. It exists so the pre-Go audience keeps a working upgrade path.

### From source

For hacking on yolo-jail itself, or running an unreleased working tree. Identical on Linux and macOS:

```bash
git clone https://github.com/mschulkind-oss/yolo-jail.git
cd yolo-jail
just setup             # pinned toolchain (mise) + Go module deps
just deploy            # builds + installs the yolo CLI
```

To upgrade later: `cd yolo-jail && git pull && just deploy`

#### Upgrading from the Python version

yolo-jail used to ship as a Python package installed with `uv tool install`. `just deploy` retires that install for you — it uninstalls the `yolo-jail` uv tool and clears the console scripts it left in `$GOBIN` (`yolo`, `yolo-ps`, `yolo-host-processes`, `yolo-claude-oauth-broker-host`), which otherwise make `go install` fail with `build output "…/yolo" already exists and is not an object file`.

Nothing is deleted that cannot be positively identified as part of that old install. If something unrecognized is sitting at `$GOBIN/yolo`, the migration stops and asks you to look at it rather than guessing. `uv` itself is no longer a prerequisite.

### Optional — User-level defaults

```bash
yolo init-user-config
# Edit: ~/.config/yolo-jail/config.jsonc
```

**Platform-specific runtime setup** (one-time, needed for both install options):

```bash
# Linux — Podman
sudo pacman -S podman                   # or apt/dnf/pacman for your distro

# macOS — Apple Container (native, recommended)
brew install container skopeo
container system start

# macOS — Podman Machine
brew install podman
podman machine init --cpus 4 --memory 8192 --disk-size 50
podman machine start
```

On macOS, image builds use the NixOS binary cache by default — no remote Linux builder required. See [docs/guides/macos.md](docs/guides/macos.md) if you need to add packages that aren't in the cache (or want to build offline).

For development, see [CONTRIBUTING.md](https://github.com/mschulkind-oss/.github/blob/main/CONTRIBUTING.md).

## Quick Start

Works identically on Linux and macOS:

```bash
# Navigate to any repository
cd ~/code/my-project

# Start an interactive shell in the jail
yolo

# Or run a command directly (only agents in your `agents` config are installed)
yolo -- claude           # Claude Code in YOLO mode
yolo -- copilot          # Copilot with --yolo auto-injected
yolo -- gemini           # Gemini with --yolo auto-injected
yolo -- opencode         # opencode.ai agent (auto-approve)
yolo -- pi               # pi.dev coding agent (auto-approve)
yolo -- codex            # OpenAI Codex CLI (auto-approve, sandbox off)

# Force a new container
yolo --new -- bash

# ALWAYS run this after every yolo-jail.jsonc edit, before restarting
yolo check

# Check your setup
yolo doctor

# List running jails
yolo ps

# Show full configuration reference
yolo config-ref
```

On macOS, `yolo doctor` additionally checks the VM backend (Podman Machine or Apple Container `system status`) and (if configured) the Nix remote Linux builder.

### First Run

On first run, YOLO Jail will:
1. Build the Linux container image via `nix build` (takes a few minutes — both Linux and macOS download from the NixOS binary cache; macOS only needs a remote Linux builder if you've added non-cached packages)
2. Load the image into your container runtime
3. Install MCP servers, LSP servers, and utilities
4. Start your command

Subsequent runs are fast — tools are cached in persistent storage on both platforms.

### Auth Setup (One-Time)

Inside the jail, authenticate with your tools:

```bash
gh auth login          # GitHub CLI
gemini login           # Google Gemini CLI
# Claude Code authenticates via /login on first run
# codex login / opencode auth login / pi's /login work the same way
```

Each coding agent authenticates itself inside the jail — see the per-agent
auth column in [Agents](#agents). Agents that take a provider API key
(opencode, pi, codex) can instead read it from [`env_sources`](#configuration).

These tokens are stored in `~/.local/share/yolo-jail/home/` (same path on Linux and macOS) and persist across jail restarts. On both platforms, a host-side systemd timer (installed by `just deploy`) periodically refreshes the shared Claude OAuth token so jails never race the refresh flow.

## Configuration

Create a per-project config in `yolo-jail.jsonc`:

```jsonc
{
  "runtime": "podman",              // or "container" (Apple Container)
  "agents": ["claude", "codex"],    // which coding agents to install (see below)
  "packages": ["strace", "htop"],   // extra nix packages
  "mounts": ["/path/to/ref-repo"],  // extra read-only mounts
  "network": {
    "mode": "bridge",               // or "host" for host networking
    "ports": ["8000:8000"]          // publish ports in bridge mode
  },
  "security": {
    "blocked_tools": ["curl", "wget"]
  }
}
```

Workspace config merges over user defaults (`~/.config/yolo-jail/config.jsonc`), and a sibling `yolo-jail.local.jsonc` — meant to be gitignored for per-machine overrides — auto-merges over the workspace config. Lists merge and dedupe, scalars override.

Run `yolo check` after **every** edit to `yolo-jail.jsonc` to validate the merged config, dry-run the generated jail agent configs, and preflight the image build before restarting into the jail. Inside a running jail, `yolo check --no-build` is the fast way to validate config changes mid-session before asking for a restart.

Run `yolo config-ref` for the full configuration reference.

## Agents

YOLO Jail is a **library of coding agents** — you choose which to install per
project with the `agents` field. Only the selected agents are installed and
configured, so a jail stays lean and boots faster. The default is Claude Code.

```jsonc
// yolo-jail.jsonc — install just the agents this project uses
{ "agents": ["claude", "codex"] }
```

- **Default:** `["claude"]` when `agents` is omitted.
- **Merge:** unlike other list fields, `agents` **replaces** (does not union)
  across the user→workspace hierarchy, so a workspace can *narrow* your
  user-level default (e.g. user `["claude","gemini"]`, but a claude-only
  workspace `["claude"]`).
- **No rebuild:** agents install lazily on first use, so changing the list
  never rebuilds the image — just restart the jail.

Each agent is launched with its autonomous/YOLO mode auto-enabled (the jail
container is the security boundary), and authenticates itself **inside the
jail** — host credentials never cross the boundary.

| Agent | `agents` value | Run | Install | Auth (inside the jail) |
|---|---|---|---|---|
| **Claude Code** | `claude` | `yolo -- claude` | native installer | `/login` on first run |
| **GitHub Copilot** | `copilot` | `yolo -- copilot` | npm `@github/copilot` | `/login` (GitHub OAuth) |
| **Gemini CLI** | `gemini` | `yolo -- gemini` | npm `@google/gemini-cli` | `gemini login`, or `GEMINI_API_KEY` |
| **opencode** | `opencode` | `yolo -- opencode` | npm `opencode-ai` | `opencode auth login`, or a provider key (e.g. `ANTHROPIC_API_KEY`/`OPENAI_API_KEY`) |
| **pi** ([pi.dev](https://pi.dev)) | `pi` | `yolo -- pi` | npm `@earendil-works/pi-coding-agent` | `pi` `/login`, or a provider key |
| **OpenAI Codex** | `codex` | `yolo -- codex` | npm `@openai/codex` | `codex login` (ChatGPT), or `OPENAI_API_KEY` |

Provider API keys are easiest to supply via [`env_sources`](#configuration)
(a gitignored dotenv file) so they reach the agent inside the jail without
living in your committed config. MCP servers you configure (`mcp_presets` /
`mcp_servers`) are wired into every selected agent that supports MCP —
claude, copilot, gemini, opencode, and codex (pi has no native MCP).

## Isolation backends

The `runtime` config picks how the agent is isolated:

- **`podman`** (Linux, default) / **`container`** (macOS, Apple Container) —
  the agent runs in a Linux container. Strongest boundary (kernel/VM
  isolation, resource caps). On macOS this means a lightweight Linux VM —
  **native arm64 on Apple Silicon (no emulation)**; see [docs/guides/macos.md](docs/guides/macos.md).

## Security

- **Strict Isolation**: No access to host `~/.ssh/`, `~/.gitconfig`, or cloud credentials
- **Separate Auth**: Run `gh auth login`, `gemini login`, etc. inside the jail once
- **User Mapping**: Files created in the jail are owned by your host user (matching UID/GID)
- **Blocked Tools**: Configurable list of tools that return clear error messages
- **Config Safety**: Changes to `yolo-jail.jsonc` require human confirmation at next startup — agents cannot silently modify the jail environment. See [docs/design/config-safety.md](docs/design/config-safety.md).
- **Read-Only Mounts**: Extra mounts are read-only by default

## Troubleshooting

Run `yolo doctor` to diagnose common setup issues:

```bash
yolo doctor
```

This checks your container runtime, Nix installation, configuration files, image status, and running containers.

Run `yolo check` after **every** config edit, especially when handing work from an outside agent into the jail or when an in-jail agent edits `yolo-jail.jsonc` mid-session and needs to verify the restart will succeed.

## Contributing

See [CONTRIBUTING.md](https://github.com/mschulkind-oss/.github/blob/main/CONTRIBUTING.md) for development setup and guidelines.

## Documentation

- [User Guide](docs/guides/USER_GUIDE.md) — Detailed setup, configuration, and troubleshooting
- [macOS Setup](docs/guides/macos.md) — macOS-specific installation and setup guide
- [Platform Comparison](docs/research/platform-comparison.md) — Feature matrix: Linux vs macOS
- [Config Safety](docs/design/config-safety.md) — How config change approval works
- [Storage & Config](docs/design/storage-and-config.md) — Storage hierarchy and mount layout
- [Happy-path principle](docs/design/happy-path-principle.md) — fill the matrix, support one tool per capability

## License

[Apache License 2.0](LICENSE)

