# v0.8.0

## Lockdown becomes usable: TCP port allowlist, dotdir hiding, EAGAIN fix, pastel status bar

This release lands three community contributions that make lockdown mode practical on real developer machines, plus a small status-bar quality-of-life addition.

### Fix: lockdown no longer fails with `EAGAIN` on busy machines (#21, #22)

`ai-jail --lockdown` was failing on Ubuntu 24.04 (and any Linux box with a browser open) with:

```
✗ Failed to start sandbox: Resource temporarily unavailable (os error 11)
```

Root cause: `RLIMIT_NPROC` is enforced per real-UID system-wide. Setting it to 1024 on the outer `ai-jail` process before spawning bwrap caused EAGAIN inside bwrap's own `clone()` calls for namespace creation whenever the user already had more than 1024 processes running. Chrome alone is enough to trip this.

The fix moves NPROC application out of the parent and into the `--landlock-exec` re-entry point, so the limit is set inside the sandbox after bwrap has finished setting up namespaces. NOFILE and CORE remain on the parent (they're per-process, not per-UID). The hard limit is now also pinned to the soft limit, so the sandboxed process cannot raise it back up.

Thanks to @gmcbretas for the detailed reproduction and @mshlz for the fix.

### Feature: `--allow-tcp-port` for selective network access in lockdown (#12, #16)

Lockdown previously blocked all network traffic, which made tools like Serena/Opencode (which need to reach an MCP server on a fixed port) unusable. This release adds a port allowlist:

```bash
ai-jail --lockdown --allow-tcp-port 32000 opencode
```

Or persisted in `.ai-jail`:

```toml
lockdown = true
allow_tcp_ports = [32000]
```

When ports are configured, `--unshare-net` is skipped and Landlock V4 `NetPort` rules restrict outbound TCP to exactly the listed ports. Everything else stays kernel-level denied. The flag is repeatable, accepts any valid port, and works in lockdown mode only.

Hard-fails with a clear message if Landlock V4 is unavailable (kernel < 6.5) or not fully enforced — without V4 there would be no way to enforce the allowlist after dropping `--unshare-net`, and silently weakening lockdown is not an option.

Known limitation: Landlock V4 only covers TCP. UDP and ICMP traffic is unrestricted when an allowlist is active. seccomp still blocks raw and packet sockets. macOS prints a warning that the flag has no effect (seatbelt blocks all network unconditionally).

Thanks to @rldourado for the report and @EXboys for the implementation.

### Feature: `--hide-dotdir` to deny additional home dotdirs (#18)

In addition to the built-in deny list (`.ssh`, `.gnupg`, `.aws`, `.mozilla`, `.basilisk-dev`, `.sparrow`, etc.), users can now name extra dotdirs that should never be bind-mounted into the sandbox:

```bash
ai-jail --hide-dotdir .my_secrets --hide-dotdir .password-store claude
```

Or in `.ai-jail`:

```toml
hide_dotdirs = [".my_secrets", ".password-store"]
```

The flag is repeatable, leading dot is optional (`my_secrets` is normalized to `.my_secrets`), and CLI values are merged with config values and deduplicated. Wired into bwrap (Linux), Landlock (Linux), and seatbelt (macOS) — the hidden dotdirs disappear on all three platforms.

A safety check refuses to hide dotdirs required for sandboxed tools to function (`.cargo`, `.config`, `.cache`, `.npm`, `.docker`, etc.) — these emit a warning and stay visible. The full list lives in `sandbox::DOTDIR_RW`.

Thanks to @eduardonunesp for the contribution.

### Feature: pastel status bar theme

`-s pastel` (or `status_bar_style = "pastel"` in `~/.ai-jail`) picks a random pastel background palette at the start of every session, drawn from a curated set of eight `(background, foreground)` pairs in xterm-256 color space. Each palette pairs a soft pastel background with a deep same-hue foreground for readable contrast.

The selection rotates between sessions but stays stable for the duration of each run. Switch back to `-s dark` (default) or `-s light` to disable the rotation.

### Backward compatibility

All four changes preserve `.ai-jail` config compatibility per the project's invariant. New fields (`allow_tcp_ports`, `hide_dotdirs`, `status_bar_style = "pastel"`) all use `#[serde(default)]`, and regression tests for v0.6.0 and v0.7.0 config formats were added alongside the new functionality. Old configs continue to parse and run unchanged.

### Closed issues

- #12 — Setup AI-Jail to permit network traffic (Serena MCP)
- #21 — Failed to start sandbox: Resource temporarily unavailable (os error 11) on Ubuntu 24.04
