Sandbox

Run any task's terminals and hooks inside a sandbox. Two backends: a Lima VM that mounts only the task's work, or nono's kernel-level access limits in place on the host.

Choose a backend

Sandboxing is a per-terminal choice. Right-click a task and use Open in → Lima VM sandbox or Open in → nono sandbox; an entry appears for each backend installed on your system. Plain Open in → Terminal runs on the host, unsandboxed. Every terminal and hook opened for that task then runs under the chosen backend. A sandboxed terminal carries an outlined status dot and a backend suffix on its label.

Each backend has its own configuration under Project Settings → Sandbox.

Lima VM

Lima-sandboxed terminals run inside a Linux VM, on a parallel git branch, in a worktree that contains only tracked files.

What it does

For a Lima-sandboxed task, Ouijit creates a second git worktree at ~/Ouijit/sandbox-views/<project>/T-N-sandbox on a child branch s/<your-branch>. Because it is a plain git worktree add, only tracked files exist there: no .env, node_modules, build caches, or anything else gitignored. That sandbox-view directory is what gets mounted into a Lima VM as the agent's working directory. Your real worktree is never mounted.

When the agent commits inside the VM, the commit lands on s/<your-branch>. A host-side watcher fast-forwards your branch to match. If you committed in parallel on the host, the fast-forward fails and Ouijit surfaces the divergence.

How it works

  1. Open a Lima sandbox terminal from a task's Open in menu. Every terminal and hook for that task then runs in the VM.
  2. First terminal. Ouijit lazily creates an Ubuntu 24.04 VM via Lima on the first sandboxed spawn for a project. One VM per project, reused across that project's sandboxed tasks.
  3. Spawn progress. The dialog shows each step: checking VM status, creating or starting, SSH connection, provisioning, launching the shell. First boot takes 1-2 minutes; later spawns reuse the running VM.
  4. Shell sessions run inside the VM via limactl shell, with the working directory set to the sandbox-view path.
  5. VM lifecycle and resources. Manage the VM from Project Settings → Sandbox → Lima VM: see status, create, start, stop, recreate, open a console, and edit the merged Lima YAML config (memory, CPU, disk, mounts). Resource changes prompt a recreate.

Mount surface

Only two host paths are exposed to the VM:

Host pathIn guestWhy
~/Ouijit/sandbox-views/<proj>/Read/writeThe agent's tracked-files-only worktree.
<project>/.git/Read-only base, with read/write overlays at objects/, refs/, logs/, worktrees/Commits need to write packs, refs, and reflogs. hooks/, config, and packed-refs stay read-only.

Your home directory, source tree, system binaries, and any other host paths are not mounted at all.

Isolation properties

  • Gitignored content is not in the mount. .env, .npmrc, secrets/, node_modules, and build artifacts never leave the host.
  • Host toolchains stay separate. darwin-arm64 node_modules, Rust target/, and Python .venv don't collide with the Linux guest.
  • Parallel sandboxed tasks on the same project share the VM but work in separate sandbox-view directories.
  • .git/hooks/ and .git/config are read-only in the mount, so writes from the VM that would land there fail with EROFS.
  • No ouijit CLI in the VM. The binary isn't installed; the /api/* routes return 403 for sandbox-scoped tokens. Only the /hook endpoint accepts them.

Caveats

  • Committed files are always visible. The sandbox view is populated from the index, so anything you committed lives there regardless of .gitignore. To remove: git rm --cached <file> and rotate the secret.
  • Commits round-trip through fast-forward. Parallel commits on the host make the fast-forward fail; Ouijit surfaces the divergence.
  • The VM has no git credentials. Pushes happen from the host. Commits made inside the VM ride the next host-side push.
  • The VM's home directory is out of scope. The isolation above applies to mounts. Files copied into the VM's home (~/.netrc, ~/.git-credentials) aren't covered.

Customize the VM

VMs start from a clean Ubuntu 24.04 image with bash, git, curl, wget, nodejs, npm, python3, and build-essential pre-installed. Defaults are 4 GiB memory, 2 CPUs, 10 GiB disk.

Resource limits, extra packages, additional mounts, and provisioning scripts are controlled by the Lima YAML config in Project Settings → Sandbox → Lima VM. The editor shows the merged effective config and lets you write overrides; Ouijit prompts you to recreate the VM when changes require it. See the Lima configuration reference for the available keys.

Requirements

Ouijit bundles limactl; there is nothing extra to install.

  • macOS. Apple's Virtualization.framework (vz) with vzNAT networking.
  • Linux. QEMU with user-mode networking.

Limitations

  • First boot downloads an Ubuntu cloud image and provisions packages. It needs internet and takes 1-2 minutes.
  • GPU passthrough is not supported.
  • macOS-specific tooling (Xcode, Swift) is not available inside the Linux VM.
  • Docker-in-VM requires additional Lima configuration.
  • The VM home directory is ephemeral. Anything outside the mounted sandbox-views and .git overlays is lost on recreate.

nono

nono runs a task's commands in place on the host worktree under kernel-level access limits (Seatbelt on macOS, Landlock on Linux). There is no VM and no file sync, so it starts instantly. Compared to the Lima VM it is a lighter boundary: a kernel access policy on a host process rather than a separate machine.

nono is experimental. Turn it on under Project Settings → Experimental; the nono sandbox entry then appears in a task's Open in menu.

What it does

Terminals and hooks run on the real worktree, wrapped by nono. Filesystem access is limited to the worktree and the repository's git data, with the same read/write overlays at objects/, refs/, logs/, worktrees/, so commits land while hooks/ and config stay read-only. Ouijit derives these grants from the task's worktree path at spawn time. Network is allowed by default; the local hook-server port stays reachable so agent status still reports back.

Configuration

Under Project Settings → Sandbox → nono:

  • Additional folders. Extra paths granted read/write beyond the worktree and git data, e.g. a shared cache or a monorepo sibling.
  • Block outbound network. Deny outbound connections. The hook-server port stays open so agent status keeps working.
  • Allowed ports. Extra localhost ports to keep reachable, e.g. a dev server on 3000.

Requirements

Ouijit bundles the nono binary and the agent packs it uses; there is nothing extra to install.

  • macOS. Seatbelt (sandbox-exec).
  • Linux. Landlock, which needs kernel 5.13 or newer.