# v1.0.0

## What changed across 0.9 and 0.10

ai-jail 1.0 finalizes the sandbox model built during the 0.9 and 0.10 releases. Since v0.9.0, the main additions are browser isolation profiles (Chromium, Brave, Firefox, LibreWolf), private-home mode, Gemini support, Claude `--claude-dir`, soulforge support, linked git worktrees, macOS Claude-login fixes, and better terminal behavior.

This release does not add a feature on top of v0.10.3. It marks the current behavior as 1.0 and keeps the config-compatibility promise the project has followed since v0.6.x.

### Browser isolation profiles (since 0.10.0)

```bash
ai-jail chromium                # auto-detected hard profile
ai-jail --browser chromium      # explicit
ai-jail --browser=soft firefox  # persistent under ~/.local/share/ai-jail
ai-jail --no-browser chromium   # opt out
```

- **Hard profile**: config, cache, history, cookies, sessions all live in sandbox tmpfs and disappear on exit.
- **Soft profile**: state persists only under `~/.local/share/ai-jail/browsers/<browser>`, so re-logins are not required across sessions while the host `~/.config/chromium` and `~/.mozilla` are untouched.

Both profiles use a private `$HOME`, mount the project read-only, disable mise/config-auto-save/status-bar integration, ignore extra maps, and keep SSH, Pictures, Docker, linked worktree metadata, and normal dotdirs out of the browser sandbox. Display and network stay enabled.

Chromium-family browsers run with the in-browser zygote/setuid sandbox disabled because it does not work reliably inside bwrap's user-namespace layout. The containment boundary is ai-jail's namespace + Landlock + seccomp, not Chromium's internal sandbox. GPU acceleration is off by default in browser profiles to avoid probing unmapped DRM devices; pass `--gpu` to re-enable.

### Private-home mode (since 0.10.0)

```bash
ai-jail --private-home claude
ai-jail --private-home --rw-map ~/Downloads/test-data bash
```

A middle ground between the default and `--lockdown`: the project is writable and explicit maps still apply, but host dotdirs (`~/.config`, `~/.cache`, `~/.local`, AI tool state) are not exposed. On Linux this is a tmpfs `$HOME`; on macOS it is enforced via seatbelt allowlists because `sandbox-exec` cannot create a replacement home mount. Use it when you want normal project access with a clean home.

### Gemini CLI support (since 0.10.0)

- `ai-jail gemini` is a built-in preset.
- `~/.gemini` is mounted rw alongside `~/.claude`, `~/.codex`, etc.
- `ai-jail --bootstrap` writes a Gemini policy file to `~/.gemini/policies/ai-jail.toml`. The policy mirrors ai-jail's existing bootstrap philosophy — read/search/edit allowed, risky shell prefixes denied or marked ask. Claude-style wildcard patterns that have no Gemini `commandPrefix` equivalent are skipped rather than written as dead globs.

### `--claude-dir` for multiple Claude profiles (since 0.10.x)

```bash
ai-jail --claude-dir ~/.claude-work --init claude
ai-jail claude   # subsequent runs reuse ~/.claude-work
```

Sets `CLAUDE_CONFIG_DIR` and bind-mounts the directory rw, so you can keep separate Claude Code profiles per project (work vs personal account, isolated MCP setups, etc.). Tilde paths in the config are expanded against `$HOME`. The bootstrap helper writes `settings.json` into the chosen dir.

### Soulforge profile (v0.10.3)

`ai-jail soulforge` works out of the box. `~/.soulforge`, `~/.agents`, and `~/.local/share/soulforge` are auto-mounted rw, and `soulforge` is listed alongside `claude`, `codex`, `crush`, `opencode`, `gemini` in `--help`.

### Linked git worktrees (since v0.9.x, in 0.10 fully)

Running `ai-jail` from a linked git worktree now works without extra flags. The validator reads the `.git` gitfile, parses the `gitdir:` reference, checks both the reverse `gitdir` and `commondir` round-trip, and bind-mounts the resolved worktree git dir + common dir into the sandbox so `git status`, `git diff`, `git commit`, etc. work. Read-only in lockdown, read-write otherwise. Opt out with `--no-worktree`.

### Terminal correctness fixes (v0.10.x)

- **`--new-session` is always on in lockdown** — matching what the README has always promised. Previously only enforced for non-interactive stdin (#30, #31).
- **Resize blank-flash on maximize fixed** — primary screen resize preserves visible content instead of clearing.
- **Codex resize redraw** — when the child is codex, ai-jail injects a `ctrl-shift-l` after window resize so the agent repaints at the new size. Configurable via `resize_redraw_key`.
- **Auto-disable in tmux/zellij** — `ai-jail` detects `$TMUX` / `$ZELLIJ` and skips its vt100 PTY proxy by default. The multiplexer owns the status line and resize handling; nesting both layers caused dropped keyboard-protocol sequences and "blank screen" symptoms. Pass `-s` or set `no_status_bar = false` to force the bar on inside a multiplexer.
- **Defensive terminal reset on exit** (v0.10.3, #40) — when the child crashes or fails to clean up, ai-jail now emits the full mouse-tracking-off / bracketed-paste-off / alt-screen-exit / kitty-keyboard-pop / SGR-reset / scroll-region-reset sequence before returning control to the user's shell. Symptom this fixes: "after I close opencode, moving my mouse types random characters." Applied in both the PTY proxy path and the direct-spawn path (`--no-status-bar`, multiplexer, crush).
- **Pastel is the default status-bar theme** — random pastel palette per session, with `=dark` / `=light` as opt-outs. The seed mixes seconds XOR nanos so repeated launches do not all pick the same color.

### macOS Claude login fixes (#38, #44)

`~/.claude.json` is updated by Claude Code using a write-atomic-file pattern: it writes `.claude.json.tmp.{pid}.{hex}`, takes a `.claude.json.lock` directory mutex, fsyncs, renames, releases the lock. The original SBPL `(allow file-write* (literal ...))` only permitted writing the final path, blocking the temp + lock siblings — silent auth failures, repeated login prompts.

The seatbelt profile now emits a literal rule for `~/.claude.json` and a **bounded** regex for the atomic siblings: `^...(\.tmp\.[0-9]+\.[0-9a-f]+|\.lock)$`. Bounded with `$` at both ends so the rule doesn't accidentally grant access to `.claude.json.bak` or anything else with the same prefix. Updated in v0.10.x to recognize the hexadecimal timestamp Claude switched to (#44).

### Config / UX improvements

- **Tilde in config paths** — `rw_maps = ["~/.bashrc"]` and `mask = ["~/.env"]` now expand to `$HOME` at merge time. CLI args already worked via the shell.
- **Auto-mask `.ai-jail`** (#41) — by default, the project's own `.ai-jail` file is masked inside the sandbox so the agent can't read its policy and craft workarounds. Opt-out with `--no-hide-config`.
- **`--no-save-config`** — ephemeral runs that don't update the project's `.ai-jail`.
- **Stored command preserved across agents** — `ai-jail codex` after `ai-jail claude` no longer rewrites the project's stored default. Use `--init <command>` to explicitly change it.
- **rw-maps applied after ro-maps** — so `--map ~/Projects --rw-map ~/Projects/special-dir` does what you'd expect (the rw subdirectory overlays the ro parent).
- **Ubuntu 24.04+ AppArmor docs** — README now documents the `kernel.apparmor_restrict_unprivileged_userns=0` sysctl or per-bwrap profile that distros with restricted user namespaces need.

### Documentation hardening

The README now warns up front that writes outside the project directory go to tmpfs and are lost on exit (#43). The agent cannot detect this from inside the sandbox; the warning is for users planning multi-directory work.

### Closed since v0.9.0

`#20`, `#23`, `#24`, `#26`, `#27`, `#28`, `#29`, `#30`, `#31`, `#32`, `#33`, `#34`, `#35`, `#37`, `#38`, `#39`, `#40`, `#41`, `#42`, `#43`, `#44`, `#45`.

### Backward compatibility

All `.ai-jail` formats from v0.6.x onward continue to parse. Every new field added during the 0.9/0.10 cycle (`mask`, `ssh`, `pictures`, `no_save_config`, `no_worktree`, `claude_dir`, `private_home`, `browser_profile`, `resize_redraw_key`, `no_hide_config`) uses `#[serde(default)]` and the regression test corpus has snapshots for v0.6, v0.7, v0.8, v0.9, and v0.10 formats.

No CLI flag has been removed or had its semantics changed.
