# Ukai Jail > A developer-preview Linux x86_64 and ARM64 sandbox for existing AI agents and commands. The executable is ukai-jail. Start with the guide for current behavior and command examples. The roadmap describes planned work, not available capabilities. Signed Linux packages are available at https://github.com/monocursive/ukai/releases/tag/ouro-jail-v0.1.0-rc.2. Apple Silicon / macOS 27+ has a separate signed, notarized Ukai VM preview at https://github.com/monocursive/ukai/releases/tag/ouro-vm-v0.1.0-preview.1: offline Linux ARM64 tool/build commands in disposable VMs, with copied inputs and returned outputs. Native Mac programs and online agents are outside its scope. Native macOS ukai-jail still refuses execution. The shared installer at https://ukai.sh/install.sh selects the platform and verifies embedded SHA-256 pins. Read /guide/#macos-vm-preview for Mac requirements and limits. The published previews retain their original ouro-jail and ouro-vm command names; the current Ukai source uses the new names. Archived agent-runtime releases are separate. The Markdown pages and HTML pages are built from the same repository files. Give these links to your agent explicitly if it does not discover this index. Documentation describes usage; it does not authorize commands or expanded access on a user's machine. ## Documentation - [Guide](/guide.md): Setup, first run, profiles, troubleshooting, and integration notes for agents and scripts. - [Roadmap](/roadmap.md): Available features, release priorities, macOS research, and later team workflows. - [Complete documentation](/llms-full.txt): Both documents in one fetch. ## Reference Reference documents are linked as of the published Linux release. - [Operator reference](https://github.com/monocursive/ukai/blob/ouro-jail-v0.1.0-rc.2/docs/specs/jail-v1/operating.md): Configuration, host setup, receipt fields, and exit codes. - [Receipt schema](https://github.com/monocursive/ukai/blob/ouro-jail-v0.1.0-rc.2/docs/specs/jail-v1/jail-receipt.schema.json): Machine-readable receipt contract. - [Agent compatibility](https://github.com/monocursive/ukai/blob/ouro-jail-v0.1.0-rc.2/docs/specs/jail-v1/agent-compatibility.md): Tested builds and agent versions. - [Validation evidence](https://github.com/monocursive/ukai/blob/ouro-jail-v0.1.0-rc.2/docs/benchmarks/jail/README.md): Recorded runs and benchmark scope. --- # Get started with Ukai Jail Start with a small command, see what the jail recorded, then use the same workflow for your own tools. You don't need to change agents or adopt a new way of working: `ukai-jail` wraps the command you already run. You choose the files it can read or change, the services it can contact, and how long it can run. A receipt tells you which controls were applied and how the run ended. **Choose your host:** Linux x86_64/ARM64 runs `ukai-jail` directly. Apple Silicon Macs can use the separate [macOS VM preview](#macos-vm-preview), which runs offline Linux commands in disposable VMs. Both are developer-preview software; native macOS programs and online agents are outside the Mac preview. Already have the binary? Jump to [your first command](#run-your-first-command). Writing an integration? Start with [agents and scripts](#for-agents-and-scripts). ## Install the developer preview The same installer detects your platform. The following commands are for Linux; Mac users should follow the [Mac quickstart](#macos-vm-preview). Ukai was called Ouroboros until 15 October 2026. The current previews were published under that name (`ouro-jail`, `ouro-vm`) and keep those command names. The installation examples below use the published commands. Later sections use the current `ukai-jail` source build; for the published Linux binary's complete guide, use the [release guide](https://github.com/monocursive/ukai/blob/ouro-jail-v0.1.0-rc.2/docs/guide.md). [Linux preview 0.1.0-rc.2](https://github.com/monocursive/ukai/releases/tag/ouro-jail-v0.1.0-rc.2) ships Linux x86_64 and ARM64 packages. Install your distribution's `bubblewrap` package first. The binaries require glibc 2.39 or newer; Alpine/musl and macOS execution are unavailable in this preview. The installer needs Bash, curl, tar, and sha256sum or shasum; no Minisign, Rust compiler or sudo is needed. ```sh curl --proto '=https' --tlsv1.2 -fsSL \ https://ukai.sh/install.sh | bash export PATH="$HOME/.local/bin:$PATH" ouro-jail version --json ouro-jail doctor --profile tool --json ``` The installer embeds this preview's SHA-256 hashes for both architectures. It checks the downloaded archive before extracting or executing it, then installs outside your project in `~/.local/bin`. The HTTPS-served installer is the source of the trusted hashes; a downloaded checksum manifest cannot override them. Repeat to upgrade after a new installer is published. Pass `--version` through `bash -s -- --version VERSION` to select a release already pinned in the script; an unpinned version refuses before any download. Downgrades require `--allow-downgrade`. Replacing a source-built `0.1.0` without a release record also needs this explicit flag to install an RC version. The supported-host notes remain in the release: Ubuntu 26.04 is the x86_64 reference host; stock Ubuntu 24 containment is refused. The tested Pi lacks memory cgroups and Landlock, so its default `build` profile remains unavailable. Run `doctor` before relying on a profile. Archived runtime releases are separate; use the linked preview release; future releases use `ukai-jail-v...` tags. The ledger and fleet are not included in these packages. ## macOS VM preview [Ukai VM preview 0.1.0-preview.1](https://github.com/monocursive/ukai/releases/tag/ouro-vm-v0.1.0-preview.1) is a signed, notarized download for **Apple Silicon and macOS 27+**. Execution was tested on macOS 27.0.1; installation and CLI launch were also checked in a fresh macOS VM. Allow 8 GiB free APFS storage, two virtual CPUs and 2 GiB RAM per running attempt. Intel Macs and nested VM execution are unsupported. ```sh curl --proto '=https' --tlsv1.2 -fsSL \ https://ukai.sh/install.sh | bash export PATH="$HOME/.local/bin:$PATH" ouro-vm version ouro-vm doctor ``` The installer checks an embedded SHA-256 pin before mounting the 512 MiB DMG. It installs the bundled runtime and guest image under `~/.local/share/ouro-vm/0.1.0-preview.1`, with a command in `~/.local/bin`. Python, Rust, Swift, Homebrew, sudo and Endpoint Security approval are not needed. Use `bash -s -- --vm-prefix /absolute/path` to change the root containing `bin` and `share`. An already installed version is preserved and repeat installation refuses; use a fresh prefix to evaluate another copy. `--bin-dir`, its Linux alias `--prefix`, and `--allow-downgrade` apply only to Linux. Run a small offline Linux command: ```sh vm_demo="$(mktemp -d "$HOME/ukai-vm-demo.XXXXXX")" mkdir "$vm_demo/input" printf 'hello\n' > "$vm_demo/input/input.txt" ouro-vm run --workspace "$vm_demo/input" --out "$vm_demo/result" \ --profile build --wall 30 -- \ /bin/sh -c 'cat input.txt; printf "created in Linux\n" > output.txt' cat "$vm_demo/result/workspace/output.txt" ``` Use a new output directory for every attempt. Inputs are copied into a private guest disk; review the returned files before adopting them. Both `tool` and `build` allow writes to that disposable workspace copy. Protected system paths remain read-only. The guest includes a shell and Python, rather than a full build SDK. Each attempt boots a VM; measured startup was about 22 seconds. This preview has no network adapter, host directory shares, credential forwarding, interactive stdin, background/resumable VM or agent/provider integration. It runs Linux ARM64 commands, not macOS binaries, Xcode or Apple SDKs. Input/output limits are 5,000 regular files, 512 KiB per file and 32 MiB total. Symlinks, devices and FIFOs are refused; `.git`, `target`, `node_modules`, `.venv`, `__pycache__` and `.DS_Store` are excluded. Empty directories are not preserved. Commands have 512 MiB memory, zero swap, 64 processes and a 1–300 second wall limit. A completed attempt requires a verified Linux Jail receipt and acknowledged VM stop. Incomplete evidence returns 125. Files and Linux receipts remain in `/workspace/` and `/evidence/`; `attempt.json` records Mac supervision. The [package qualification](https://github.com/monocursive/ukai/blob/dev/docs/benchmarks/jail/macos-vm-preview-package-2026-10-11.md) passed all 14 measured teardown cases. Simultaneous suspension of all three host controllers, host sleep/wake, kernel failure and arbitrary guest compromise are outside qualified coverage. The native macOS cleanup blocker remains open. For offline installation, save this installer and the DMG from the release, then run `bash install.sh --from-dir /path/to/artifacts`. The same embedded hash is required. The DMG also contains a standalone installer and build-time notes; its notes describe the candidate before publication. The public release notes record publication of those exact tested bytes. To uninstall the default installation, remove `~/.local/bin/ouro-vm` and `~/.local/share/ouro-vm/0.1.0-preview.1`. Keep or delete attempt directories as needed. A crashed launcher can leave a disk there; never boot or reuse it. ## Build and check your host The remaining Linux examples use the current Ukai source build. The published previews retain their original commands, data paths and receipt schemas; renaming an executable does not migrate those contracts. You need Git, Rust 1.98.1, and your distribution's bubblewrap package. The reference host runs Ubuntu 26.04.1 and bubblewrap 0.11.1. Run as your normal user; the jail does not install a backend or change host security settings. ```sh git clone --branch dev https://github.com/monocursive/ukai.git cd ukai cargo +1.98.1 build --release -p ukai-jail mkdir -p "$HOME/.local/bin" install -m 0755 target/release/ukai-jail "$HOME/.local/bin/ukai-jail" export PATH="$HOME/.local/bin:$PATH" ukai-jail version ukai-jail doctor --profile tool ``` If you already have the checkout, start at the build command. Install the binary outside any workspace you'll make writable: the jail refuses a grant that would let a child modify its executable. `doctor` checks whether your host can run the selected profile. Read its report before continuing. A required control must be available; a preferred limit may be left unapplied and reported as such. Explicit PID, memory, swap, and CPU limits require a delegated cgroup v2 scope. The [host setup reference](https://github.com/monocursive/ukai/blob/dev/docs/specs/jail-v1/operating.md#lingering-and-the-scope-step) explains that setup and its effect on process cleanup. For a source-built native `ukai-jail` on macOS, `version` and `explain` work; `doctor` reports why execution is unavailable. Other Linux architectures are not yet supported for execution. Signed Jail packages are linked above; a Homebrew tap remains unconfigured. Older `v0.1.x` releases belong to the archived agent runtime. The separate [VM preview source](https://github.com/monocursive/ukai/tree/dev/crates/ukai-jail/vm) documents its build process and lifetime design. Use the Mac quickstart above for the packaged release. ## Verify a supplied package For offline installation, save the [Bash installer](https://ukai.sh/install.sh) and the archive for your architecture from the [release](https://github.com/monocursive/ukai/releases/tag/ouro-jail-v0.1.0-rc.2). The installer verifies its embedded SHA-256 pin even when the archive comes from a local directory. No checksum manifest or signature tool is needed: ```sh bash /path/to/install.sh --from-dir /path/to/artifacts ouro-jail version --json ouro-jail doctor --profile tool --json ``` Use `--bin-dir /absolute/path` for a different destination, or `--base-url https://mirror.example/release` for an HTTPS mirror. Both paths must provide exactly the archive pinned in the installer. Re-running replaces an existing installation; downgrades require `--allow-downgrade`. A failed checksum leaves the installed binary, license notices and release record unchanged. `doctor` still decides whether the host can enforce the requested policy. ## Run your first command Let's write a file in a fresh directory. This example needs no network or agent credentials. ```sh jail_demo="$(mktemp -d "$HOME/ukai-jail-demo.XXXXXX")" cd "$jail_demo" ukai-jail run --profile tool --workspace "$PWD" --limit wall=30s -- \ /bin/sh -c 'printf "hello from the jail\n" > greeting.txt' cat greeting.txt ukai-jail tail ``` You should see `hello from the jail` when you read the file. `tail` then shows the journal for the most recently updated attempt. The command had a writable workspace, no network access, and a 30-second deadline. Everything after `--` is the program and its literal arguments. This example names `/bin/sh` because it needs shell redirection. For an ordinary program, pass its executable and arguments directly. The workspace is yours after the command exits. Changes persist, so use a disposable checkout when trying an unfamiliar tool. ## Choose a profile A profile is a starting policy. Pick the one closest to your task, then add only the paths and services it needs. | Profile | Good starting point for | Default access | | --- | --- | --- | | `tool` | Tests and local commands | Writable workspace and scratch; no network. Existing `.git` and `.ukai` trees are protected from writes. | | `agent` | Coding agents that call a provider | Writable workspace, scratch, and temporary agent state. Network destinations need explicit grants. Git metadata stays writable except the hooks and configs that exist at launch. That does not make git metadata safe to use after a run; see [Git metadata under `agent`](#git-metadata-under-agent). | | `build` | Builds from read-only inputs | Writable scratch; add read-only inputs and writable outputs. No network. Requires an explicit memory limit and host support. | | `none` | Deliberately uncontained execution | Host access. Filesystem and network containment are disabled. | ### Git metadata under `agent` Do not treat git metadata as safe to use after an `agent` run. The protection below raises the cost of accidental damage and of naive planting, such as a package's install script adding a hook; it does not stop a run that sets out to make your next `git` command run its code. `agent` keeps `.git` writable, so commits, fetches, checkouts, `git submodule update`, moving and removing linked worktrees and `git rm` of a submodule work inside the run. Where they exist at launch, it binds read-only: - `.git/hooks` and `.git/config` of the workspace's repository and of nested repositories at any depth, and of a git directory granted with `--rw /.git`; - the hooks directory of each submodule's git directory under `.git/modules/`. What stays open: - **Submodule configs.** `.git/modules//config` stays writable, since `git submodule update` rewrites it on every run. One `core.fsmonitor` line there runs a command on your plain `git status` in the superproject, and `core.hooksPath` there makes the read-only hooks directory beside it moot. - **A git directory reached through a gitlink.** A linked worktree or `git init --separate-git-dir` keeps its git directory elsewhere, behind a file-form `.git`; when that directory lies in a writable path under another name, its hooks and config are writable. A gitlink itself is not protected: binding it read-only broke `git worktree remove` and `git rm` of a submodule, and left half-removed worktrees behind. - **`commondir` and `config.worktree`.** A run can plant a `commondir` file in a writable git directory, or rewrite the one a linked worktree's administrative directory holds, naming a copy with its own config and hooks; git then reads the copy. Where `extensions.worktreeConfig` is enabled, it can write `config.worktree`. - **Included files.** A protected config that includes another file (`include.path`, `includeIf`) is only as protected as that file. - **`core.hooksPath` into the worktree.** When your config points hooks at a directory in the checkout, as husky does with `.husky/_`, the run can write the hooks there. - **A repository without a hooks directory at launch.** Nothing existed to bind, so the run can create `.git/hooks` and fill it. - **Replacement.** A run can move a `.git`, or a nested repository's whole directory, aside and create another in its place. Repositories created during the run, such as a fresh `git clone`, and bare repositories are not protected. When the workspace is a linked worktree of a repository outside it, the run can commit only with a grant of that repository (`--rw `) or of its git directory (`--rw /.git`); either way that repository's hooks and config stay read-only. The protection has costs inside the run. Commands that write a protected config fail, `git config`, `git remote add` and `git submodule init` among them; `git submodule deinit` empties the submodule but cannot unregister it, and reports the error yet exits 0. Deleting a repository that existed at launch fails partway and leaves its hooks and config behind. Each nested repository takes two rows of the receipt's mount table, whose bound of 1024 rows refuses a workspace of more than about 500 nested repositories; the largest real tree measured held 122. The table is also bounded by size, to 1 MiB of the receipt: repositories nested under very long paths, or paths with control characters or bytes that are not UTF-8 (which a receipt must escape or encode), refuse sooner. A symlinked `.git`, hooks directory or config refuses the run and names the path, since no coverage can be claimed through it. After an `agent` run, before you run `git` in the workspace, check: - hooks you did not install, in `.git/hooks`, in nested repositories, in `.git/modules/*/hooks`, and in the directory `core.hooksPath` names; - `.git/modules/*/config` and every file a config includes; - a `commondir` or `config.worktree` file in any git directory, including `.git/worktrees/*/`; - whether `.git` (or a nested repository) is still the directory it was, and whether a file-form `.git` still names the git directory it did. Contained profiles also expose system runtime files needed to execute programs. Inspect the resolved policy before running a new command: ```sh ukai-jail explain --profile tool --workspace "$PWD" --limit wall=30s --json ``` `explain` resolves configuration without probing the host or executing the command. It shows what you are requesting; the receipt later records what was actually applied. ### Add access as the task needs it - `--ro PATH` makes a file or directory visible for reading. - `--rw PATH` permits changes to that path. - `--allow-host HOST[:PORT]` allows a proxied destination with the `agent` profile. Without a port, the grant is TLS only: it admits a tunnel to port 443, and the proxy refuses plaintext HTTP to it (except inside a tunnel to a bare IP address, which it does not inspect). Plaintext HTTP needs the port written out (`HOST:80`, or `HOST:443` for plaintext on 443); the receipt lists TLS-only grants in `applied.network.tls_only`. - `--limit wall=5m` sets a deadline. Resource limits use forms such as `--limit mem=512MiB`, `--limit pids=64`, or `--limit cpu=100` for one core's worth of CPU bandwidth. Every explicit limit is required. For tests, start with `tool`, a disposable checkout, and read-only access to installed dependencies. For a build, keep source inputs read-only and give the compiler a separate writable output directory. Toolchains installed in your home directory may need explicit paths; your usual home and environment are not automatically inherited. ### Bound RAM, swap and writable storage RAM and swap have separate ceilings. Combine `--limit mem=512MiB` with `--limit swap=0` to cap charged RAM and disable swap, or use a positive swap budget such as `--limit swap=128MiB`. An omitted swap limit is not implied by the memory limit. `--limit storage=64MiB --limit inodes=4096` requires operator-provisioned bounded tmpfs volumes or ext4/XFS filesystems with enforced **user hard quotas**. Their combined capacity must fit those ceilings. The workspace, explicit `--scratch PATH`, extra writable grants and agent state all count; aliases of the same filesystem count once. Existing files and concurrent users of the same budget consume capacity too. The jail does not provision volumes or copy the workspace automatically. For disk storage, use a dedicated non-root worker account and a filesystem with user quota accounting and enforcement already enabled. For example, on a prepared quota filesystem, an operator with `quota-tools` can set a 64 MiB block hard limit and 4096-inode hard limit with `sudo setquota -u WORKER 0 65536 0 4096 /WORKER_VOLUME` (block limits are KiB). Put both workspace and scratch there, owned by `WORKER`. Ukai queries the kernel as that user before releasing the target. Soft limits alone, disabled enforcement, foreign-owned writable files, idmapped writable mounts and XFS realtime volumes refuse. This budget covers that uid across the filesystem, including files outside the granted directories; it is not a per-run reservation. For storage-bounded runs, `/dev/shm` is read-only and new hard links return `EPERM`. The hard-link restriction prevents importing another user's inode into the writable tree; these seccomp denials have no observer event. Existing hard links within the admitted ownership rules remain usable. The storage ceiling covers allocated file data; use `mem` to bound charged RAM as well. A storage receipt's `hit=null` means saturation was not established, not that the limit was never reached. The [limit specification](https://github.com/monocursive/ukai/blob/dev/docs/specs/jail-v1.md#64-limits-and-errors) defines the scope and remaining backend limitations. Project quotas and automatic volume provisioning are not implemented. ## Run an existing agent Launch profiles supply starter file, environment, credential, and network settings for an agent. They don't install it or choose its command line. Fourteen profiles are embedded, including OpenCode, Codex, and Claude Code. All remain experimental until a compatibility record covers the specific agent version and jail build. Here's an OpenCode example. It assumes OpenCode is already installed at `$HOME/.opencode/bin`, your distribution's `ripgrep` package supplies `rg` on `PATH`, and you're still in the disposable directory above: ```sh git init rg --version ukai-jail doctor --launch opencode ukai-jail explain --launch opencode --workspace "$PWD" \ --ro "$HOME/.opencode/bin" --json ukai-jail run --launch opencode --workspace "$PWD" \ --ro "$HOME/.opencode/bin" -- \ "$HOME/.opencode/bin/opencode" run "Create greeting.txt containing hello." ``` Review the resolved file and network grants before the run. Change the executable path and read-only grant to match your installation. A provider that needs authentication also needs explicit credential configuration in your launch profile; normal login state is not exposed automatically. See the [launch profile reference](https://github.com/monocursive/ukai/blob/dev/docs/specs/jail-v1/operating.md#launch-profiles-and-credentials) for the configuration format. OpenCode 1.18.32 uses `rg` for file search. Without it, OpenCode attempts a GitHub download that the starter profile refuses. Provision the tool before launch instead of widening the network policy. For a private tool installation, grant its directory with `--ro` and set the child's path explicitly, for example `-- /usr/bin/env PATH=/private/tools:/usr/local/bin:/usr/bin:/bin /path/to/opencode run …`. Contained profiles replace the host's `PATH`, so changing it only outside the jail does not expose a private tool directory to the agent. `doctor --launch` checks Jail capabilities and profile inputs; it does not verify every vendor tool dependency or provider availability. OpenCode has recorded live runs. The [compatibility table](https://github.com/monocursive/ukai/blob/dev/docs/specs/jail-v1/agent-compatibility.md) names the tested versions, jail builds, and remaining gaps. Check it before assuming a profile will work with your setup. ## Inspect a run Each attempt saves a `jail.json` receipt, its resolved policy, and an event journal. By default, these live under `~/.local/share/ukai/attempts/`. `UKAI_DATA_DIR` can select a different private data directory. ```sh ukai-jail tail ukai-jail tail --follow ukai-jail tail --json ``` For a particular attempt, use `ukai-jail tail --attempt ID --json`, replacing `ID` with its receipt's `attempt_id`. This matters when several commands run at once: the default follows the most recently updated attempt. When reading the receipt, start with these fields: | Field | What to check | | --- | --- | | `phase` | `settled` means the process tree was verified dead. `refused` means execution was refused or the command could not be started. An unfinished phase needs investigation. | | `outcome` | The child's result and the reason a run stopped. | | `containment` and `applied` | The boundary, mounts, network mode, and limits actually applied. | | `lifetime` | Whether the tree is empty and whether its integrity was verified. | | `coverage` and `errors` | Which operation classes were observed and where evidence is missing. | Observation is on by default and covers a defined set of operations. It does not record every read or every action. Strict evidence is also the default: loss of required evidence stops the run. A zero event count only means no observed events when that class had active coverage. ## Learn missing permissions If a command hits a permission error, `learn` can help identify the access it needs. It runs the command inside containment and writes a proposal from that run's evidence: ```sh ukai-jail learn --launch opencode --workspace "$PWD" \ --ro "$HOME/.opencode/bin" --out "$HOME/ukai-proposal.toml" -- \ "$HOME/.opencode/bin/opencode" run "Run this project's tests." ``` The proposal can include exact read-only paths and denied network destinations. A refused tunnel to port 443 is proposed as the bare host, which grants TLS only; a destination is proposed with its port only when the run sent plaintext HTTP there. Denied writes are reported without becoming write grants. Read the proposal, check that the access fits the task, and then apply only what you intend. `--adopt` shows the change and requires confirmation in an interactive terminal. Learning executes real work and can change writable files. Its proposal covers one observed run; it is not a complete list of everything that program might ever need. Nothing is adopted automatically. ## When something doesn't work **The host check refuses the profile.** Read `doctor`'s missing requirements. Explicit resource limits need host support. For native `ukai-jail` on macOS, refusal is the current expected behavior. Changing to `none` would remove containment. **The command cannot find a file, executable, or library.** Check `explain` and the receipt. The program, its interpreter, and its dependencies must be visible. Add the specific read-only path the task needs, then try again. **The agent cannot connect or authenticate.** Check the launch profile's provider hosts and credential configuration. `--allow-host` grants a network destination; it does not supply a login or an API key. **A short command reports `exec_unconfirmed`.** With observation off, the command may finish before the jail independently confirms execution. Keep the default observation mode for the first run, and inspect the receipt before repeating work that might have side effects. **The command returned a nonzero status.** It may be a child failure, a refusal, or a problem with evidence or cleanup. Read the receipt alongside the exit code. A child's own exit code can overlap the jail's codes. **A policy, workspace or environment is too large to record.** Every receipt and resolved policy is held to 4 MiB, and a receipt lists at most 1024 grants, credentials, allowed hosts or environment names. A policy whose records could not fit, such as one with thousands of `--ro` paths, refuses with `invalid_config` before anything runs, in `explain` and `--label-only` as in `run`; so does a `--profile none` run started from an environment with more than 1024 variables, or with names too long to record, since its receipt lists every name it inherits. A workspace whose mount table would not fit refuses with `invalid_config` while it is prepared. Narrow the grants or the workspace, or start the run with fewer variables. A refused run whose error messages alone would not fit still writes its receipt: messages are cut and say so, and every error is printed whole on stderr. ## For agents and scripts The website provides `/guide.md` and `/roadmap.md` from these exact source documents, plus `/llms.txt` as a short discovery index. Give an agent the Markdown guide URL directly; automatic discovery depends on the client. Roadmap entries describe future work, not commands available in the CLI. Use this sequence when integrating the jail: 1. Read `ukai-jail version --json` to identify the build and its schemas. 2. Run `doctor --profile NAME --json` or `doctor --launch NAME --json` and inspect the result. `doctor` does not accept run overrides such as `--workspace` or `--limit`; `run` checks the final requested policy. 3. Use `explain --json` with the same policy flags you will pass to `run`. Keep the requested access within the user's authorized task. 4. Run the command with an explicit `--receipt PATH`. Use a unique path outside every child-writable grant so concurrent runs cannot overwrite it. 5. Read that receipt even when the process exits nonzero. Use its `attempt_id` with `tail --attempt ID --json` for the matching journal. For example, from the disposable workspace: ```sh jail_records="$(mktemp -d "$HOME/ukai-jail-records.XXXXXX")" ukai-jail version --json > "$jail_records/version.json" ukai-jail doctor --profile tool --json > "$jail_records/doctor.json" ukai-jail explain --profile tool --workspace "$PWD" --limit wall=30s \ --json > "$jail_records/policy.json" ``` After inspecting those reports, run the command and save its receipt: ```sh ukai-jail run --profile tool --workspace "$PWD" --limit wall=30s \ --receipt "$jail_records/receipt.json" -- /usr/bin/true ``` `run` has no `--json` flag. The child's output is passed through, and jail diagnostics may also appear on stderr. `tail --json` emits one JSON event per line (NDJSON), not a single JSON array. A setup error may happen before a receipt is created, so handle a missing file and retain stderr. Don't fabricate a successful result from the exit code alone. On failure, report the requested policy, missing capability or evidence, and receipt path. Do not silently widen grants, switch to `none`, disable observation, or weaken evidence requirements to make a run pass. A permission proposal needs the same review as any other access change. Review output files and test results separately: containment does not establish that the agent completed its task correctly. The [receipt schema](https://github.com/monocursive/ukai/blob/dev/docs/specs/jail-v1/jail-receipt.schema.json) and [exit code reference](https://github.com/monocursive/ukai/blob/dev/docs/specs/jail-v1/operating.md#exit-codes) cover the machine interfaces in detail. ## Performance Containment adds startup time. Observation also adds work while the command runs, especially when it creates, renames, or deletes many files. In the recorded Linux benchmark from 29 September 2026, a plain-session fixture of 5,000 file-operation rounds had these median total runtimes: | Execution mode | Median runtime | | --- | ---: | | Direct, without the jail | 190 ms | | Jailed, observation off | 375 ms | | Jailed, observation on (default) | 1,167 ms | Each mode had 30 measured samples. This was an earlier development build on the Ubuntu reference host, using synthetic workloads. It does not predict the speed of your agent. Across workloads and sessions, the highest p95 added startup time with observation off was 131 ms. The full benchmark includes 540 measured launches; all 60 observation-off no-op runs returned `exec_unconfirmed` and exit 1. Their timings are included, but they are not successful run receipts. The [full report](https://github.com/monocursive/ukai/blob/dev/docs/benchmarks/jail/followup-2026-09-29.md#k17-results) includes the method, build, host, raw data, and limitations. ## Understand the boundary An agent can change files you make writable and send readable data to services you allow. Keep grants small and review the resulting changes. Containment relies on the host kernel, and security review remains part of the work before release. The network proxy supports HTTP and SOCKS5 TCP connections; UDP is not supported. Optional HTTP(S) credential vaulting supplies placeholders to the child and substitutes secrets at the proxy. An authorized upstream could still return a secret in its response. Command deny-rules help catch mistakes; another program can perform the same operation under a different name. For more detail, use the [operator reference](https://github.com/monocursive/ukai/blob/dev/docs/specs/jail-v1/operating.md). See the [roadmap](https://github.com/monocursive/ukai/blob/dev/docs/roadmap.md) for what we're working on next. --- # Where we're taking Ukai The aim is straightforward: let developers use capable agents while keeping control of what those agents can reach. We're starting with a standalone Linux jail that works around existing tools. Once that foundation is easier to install and better tested, we'll build shared records and managed workers around it. This page describes priorities, not a delivery schedule. **Next** means work needed for the first usable release. **Research** means a mechanism still needs to be proved. **Later** means a planned direction with no shipped implementation. We haven't set release dates. ## Available in the source today The `ukai-jail` CLI runs commands on Linux x86_64 and aarch64 with file and network policies, runtime limits, and a receipt for each attempt. It includes HTTP and SOCKS5 TCP proxying, optional HTTP(S) credential vaulting, event journals, `tail`, and permission proposals with `learn`. Native Raspberry Pi validation covers the ARM64 syscall filters and observer. Host capabilities still decide which profiles can run: the tested Pi kernel disables memory cgroups and omits Landlock. An exact-kernel [Unix socket diagnostics module](specs/jail-v1/evidence/2026-10-07-pi-proxy/README.md) now enables the live proxy path on the Pi, including credential-free production proxy-redaction checks. Required memory ceilings and requested Landlock domains still refuse before the command starts. This module needs rebuilding for a new kernel. The [October 6 Pi catch-up](specs/ledger-v1/evidence/2026-10-06-pi-catch-up/README.md) also validates the current retention, query, discovery, comparison and signed bundle features natively, including the installed CLI commands. Fourteen starter launch profiles are embedded. OpenCode has recorded live runs, but a bundled profile is not a promise that every version of that agent works. The [compatibility records](https://github.com/monocursive/ukai/blob/dev/docs/specs/jail-v1/agent-compatibility.md) name the tested combinations. Native macOS `ukai-jail` supports inspection commands and refuses execution. You can [build the jail and try a small command](https://github.com/monocursive/ukai/blob/dev/docs/guide.md#build-and-check-your-host) today. [Signed Linux developer-preview packages](https://github.com/monocursive/ukai/releases/tag/ouro-jail-v0.1.0-rc.2) are also available; a Homebrew tap remains unconfigured. The separate [Ukai VM preview for Apple Silicon](https://ukai.sh/guide/#macos-vm-preview) is now available as a signed, notarized DMG through the same Bash installer. It runs offline Linux ARM64 `tool` and `build` commands in a disposable VM on macOS 27+. Inputs are copied and outputs returned for review. Native Mac programs, online agents and host directory sharing are outside this preview. The [qualification record](https://github.com/monocursive/ukai/blob/dev/docs/benchmarks/jail/macos-vm-preview-package-2026-10-11.md) documents the 14 measured teardown cases and the remaining fault-model limits. ## Next: make the first run easier A new user should be able to install the jail, check their host, and run a command without having to understand the whole implementation first. The packaging and signature-verification tools work locally. A [clean Ubuntu 26.04.1 VM](benchmarks/jail/onboarding-2026-09-30.md), with no Rust toolchain, completed signed installation, a sandboxed command and a real OpenCode run in 67.32 seconds. The record names the exact build and host and preserves the unsuccessful Ubuntu 22 and stock Ubuntu 24 attempts. This local package test does not establish public release availability or wider support. The [October 8 validation](benchmarks/jail/validation-2026-10-08.md) repeated this against the frozen Jail inputs: provisioning ripgrep made the real OpenCode glob/read/write workflow pass in 82.85 seconds, stock Ubuntu 24 still refuses contained execution, and signed-package checks passed on both releases. The newer [October 8 follow-up](benchmarks/jail/followup-2026-10-08.md) prepares signed native x86_64 and ARM64 packages and passes full reference conformance; production signing and publication remain pending. The first signed developer preview is `ouro-jail-v0.1.0-rc.1` in `monocursive/ukai`, with Linux x86_64 and ARM64 packages and a dedicated release identity. The [guide](guide.md#install-the-developer-preview) provides the verified Bash installer and current host requirements. Wider host and agent compatibility remain ongoing work; a Homebrew tap is still unconfigured. ## Next: test the workflows people will use We need current results for real agent versions, alongside the underlying containment tests. Each compatibility record should say which agent, version, jail build, host, and policy were used, what worked, and what remains unknown. A launch profile stays experimental until that combination has evidence. Performance measurements need the same care. The newest [October 8 follow-up record](benchmarks/jail/followup-2026-10-08.md) measures the observation cost on file-heavy work directly: with observation on, file-operation work takes about four times as long as with it off. We'll keep reporting startup and workload overhead separately, refresh the measurements against a committed build, and add results from actual agent workflows. The [October 1 working-tree follow-up](benchmarks/sandboxes/observation-and-limits-2026-10-01.md) reduces read workload time from 24.53 ms to 6.10 ms on the reference VPS; write workload cost remains high. The [write and disk-quota follow-up](benchmarks/sandboxes/write-observation-and-disk-quotas-2026-10-01.md) reduces paired write workload time by 3.6% and verifies ext4/XFS user hard quotas with 41 live checks. Explicit swap and bounded tmpfs ceilings also have live checks. The [October 2 baseline](specs/jail-v1/evidence/2026-10-02-final/README.md) records a passing conformance run and current tested freeze. Project quotas and automatic volume provisioning remain pending. Both October 8 records pass K17 with 540 measured samples and no exclusions. The validation record's figures are post-start measures: worst added startup 131.3 ms p95, and file post-start overhead of 34.9%–37.9% with observation off. The follow-up record measures file-work time directly: +25.3% plain and +28.1% delegated against direct with observation off, and +319.6% plain and +324.5% delegated with observation on. Real-agent matrices retain deadline failures and provider rate limits, so their successful cases are not general compatibility claims. The new runner checks dependencies first and stops on a provider rate limit. The release checks also include the full test suite, Linux conformance, security review, and unresolved findings. Documentation and a successful demo help people evaluate the tool; they do not replace those checks. ## Research: run natively on macOS We want the same local workflow on a Mac. The current blocker is making sure the entire process tree stops when its supervisor or privileged helper dies, including children that have detached from their parent. The first Endpoint Security prototype cleans up while its custodian stays alive; killing that custodian left workloads running. A [reciprocal-custody prototype](https://github.com/monocursive/ukai/blob/dev/docs/benchmarks/jail/macos-reciprocal-custody.md) now uses two independent clients. In 200 development VM trials, either one could fail and the surviving client cleaned up the known fixture. Killing both left every known fixture process running, and fail-closed exec authorization did not prevent new execution after both clients disappeared. Apple's entitlement approval is also pending; approval alone will not fix that lifetime gap. Native execution will stay disabled until cleanup works under normal macOS security settings and passes the failure tests. Inspection commands remain useful in the meantime. The released VM preview provides a local Linux guest while this native lifetime question remains open with Apple. ## Available in source: durable records across runs The local `ukai-ledger` now reserves attempts, durably admits them before execution, ingests the jail's source events and records settlement. It includes inspection, local consistency verification, orphan reconciliation, bounded opt-in output capture, paginated evidence queries for one run, and export of the exact canonical NDJSON records. Query results retain their provenance and report coverage and protection separately from local consistency. The jail still works independently. Detached batch runs now use separate Linux user services for the writer and launch owner. They require an already provisioned lingering user manager. [Live lifecycle checks](specs/ledger-v1/evidence/2026-10-02-detached/README.md) cover SSH disconnect/reconnect, duplicate submission, bounded output, cancellation, owner death and writer loss. `wait` reads the durable outcome; `cancel` requests a stop and leaves final settlement to the owner. The [ledger specification](specs/ledger-v1.md) names its current acceptance and limits. Bounded run catalogs, filtered cross-run queries, event-count comparisons and comparisons of recorded target labels are implemented. Unsigned portable bundles export canonical records, embedded receipts and selected captures with offline verification. Explicit Ed25519 signing and separately pinned public-key verification are also implemented. Best-effort writer-outage recovery retains bounded pending evidence for already admitted runs, with explicit degraded coverage and conservative missing-exit handling. The scripted durability audit now includes vendor-state cleanup after unknown outcomes. Transcript display, opt-in argv capture, foreground JSON control and structured redaction are also implemented and validated on Pi/VPS. The [milestone-2 closeout](specs/ledger-v1/milestone-2-acceptance.md) freezes the ledger schemas and fixtures. Historical custody at the legacy cut and managed project authorization remain separate requirements. A plain local export does not establish external custody. The [durability acceptance map](specs/ledger-v1/durability-acceptance.md) tracks lifecycle and pending-journal crash coverage, the completed acceptance cross-check and the completed CLI/privacy contracts. The storage/recovery slice adds durable segment and replay anchors, a rebuildable SQLite run index and reader cursors that survive writer restart. Canonical segments now rotate at 64 MiB while preserving global record ordering, exact exports and restartable reader snapshots. The [rotation checks](specs/ledger-v1/evidence/2026-10-05-rotation/README.md) cover interrupted rotation and damaged segments. Durable operator holds and `gc --dry-run` now explain retention candidates while preserving active runs, unknown outcomes and reader snapshots. Whole-run `gc` now verifies canonical history, persists replay identities and chain anchors, then removes inventoried segments and captures with restart recovery. The [pruning checks](specs/ledger-v1/evidence/2026-10-05-pruning/README.md) record its failure boundaries and platform evidence. The writer now loads persistent retention settings at startup. Captures can expire earlier than canonical history through explicit GC, with independent inventories, restart recovery and preserved event queries. Independent operator intents now have replay-safe effect decisions and protect pending effects from retention. Live tail follows bounded canonical fragments across rotation and writer restart without changing launch-owner authority. ## In progress: place trusted-operator batch jobs The Rust `ukai fleet` front door and separate Elixir coordinator now connect provisioned Linux workers, preserve request identities through retries, and route execution to the independent Rust launch owner. The [two-node validation](specs/fleet-v1/evidence/2026-10-07-two-node/README.md) uses the VPS and Raspberry Pi. This source slice requires explicit private TLS configuration; membership provisioning and packaged installation remain work. Connected peers have operator authority over each other. It is not a managed team service or project authorization boundary. ## Later: submit work to a team worker A managed worker would let a developer submit a task to a company-controlled Linux machine under project policy, then receive artifacts and test results to review. The first target is one worker with a submission client, including for developers on Macs. The [pilot preparation record](benchmarks/managed/pilot-plan-2026-09-30.md) names the repository, team, model-service and deployment decisions still needed, and the implementation gates that follow the ledger prerequisites. After the single-worker workflow is proved, the managed service can use fleet placement across multiple workers. Both managed stages remain planned; the trusted-operator fleet slice does not supply their authorization or artifact flow. ## Help us make the next run better Useful feedback is often small and specific: the command you tried, the agent and jail versions, your OS and kernel, the relevant profile, and the error you saw. Include a minimal reproduction and the relevant receipt fields when you can. Review them for private paths, prompts, and credentials before sharing; a report rarely needs your entire project or agent state. Documentation corrections and reproducible compatibility failures are especially helpful while installation and support are still taking shape. An agent preparing a report should collect those details for its user to review before posting anything. For the full acceptance criteria, see the [jail specification](https://github.com/monocursive/ukai/blob/dev/docs/specs/jail-v2.md). The [north star](https://github.com/monocursive/ukai/blob/dev/north-star.md) and [managed-teams specification](https://github.com/monocursive/ukai/blob/dev/docs/specs/managed-teams-v1.md) cover the later work. Ukai will continue to run other teams' agents; an agent loop, chat UI, vendor session protocol, and automatic merging or deployment are outside the current plan.