Skip to content

Configuration

jai uses line-based configuration files that live in $HOME/.jai/ (or $JAI_CONFIG_DIR if set).

Config file lookup

When you run jai cmd, jai looks for a configuration file in this order:

  1. $HOME/.jai/cmd.conf — if cmd contains no slashes and does not start with .
  2. $HOME/.jai/default.conf — fallback

You can override this with -C file or --conf file. If the path contains no /, it is relative to $HOME/.jai/.

The command-line arguments and the configuration file can specify a jail by name. Otherwise, the jail name will be default. After the .conf file is parsed, jai will parse the jail.jail file, which usually just specifies the mode of the jail, but can override other options set by the .conf file (other than the jail name itself). Command-line arguments override both the .conf and .jail files.

Syntax

Each line has the form:

option [value]

option is any long command-line option without the leading --. For example:

conf .defaults
mode casual
dir /local/build
mask Mail

Blank lines and comments (lines beginning with #) are ignored.

The conf directive

conf acts as an include directive. It logically replaces the conf line with the contents of the specified file at that exact point. Relative paths are relative to $HOME/.jai/.

conf .defaults
mode strict
dir /extra/path

This reads .defaults first, then the subsequent lines override anything set in .defaults. Because conf is processed inline (not at the end), the order matters: later lines override earlier ones.

The .defaults file

jai auto-generates a .defaults file with sensible defaults — blacklists for sensitive dotfiles (.ssh, .gnupg, etc.) and environment variables (tokens, keys, passwords). You should begin most configuration files with:

conf .defaults

If you changed your file and want to see the original version, you can print the default contents of the file with:

bash
jai --print-defaults

The command directive

jai executes jailed programs through bash. The command directive lets you wrap or modify command execution. The default in .defaults is:

command source "${JAI_SCRIPT:-/dev/null}"; "$0" "$@"

This sources any script files specified with --script, then runs the command ($0) with its arguments ($@). You can use command to set environment variables, activate virtual environments, or add flags.

Example: Python virtualenv

Create $HOME/.jai/python.conf:

conf .defaults
mode strict
dir venv
jail python
command source $HOME/venv/bin/activate; "$0" "$@"

Running jai python will now activate the virtualenv before executing the command.

The initjail directive

initjail runs a helper program when jai creates a jail home directory for the first time. This is most useful for strict and bare mode jails, where the home directory starts empty.

Important properties:

  • The helper runs outside the jail, but with its current working directory set to the new jail home.
  • It runs with the invoking user's real uid/gid, not as root and not as the unprivileged jai user.
  • In configuration files, the program path is resolved relative to $JAI_CONFIG_DIR (usually $HOME/.jai).
  • jai sets JAI_MODE, JAI_JAIL, and JAI_CONFIG_DIR in the helper's environment.

The helper runs once when jai creates the jail home for the first time. In strict and bare mode, that means when jai first creates the <name>.home directory. In casual mode, that means when jai first creates the overlay state for the jail, not when it later remounts an existing .changes directory.

initjail? is the optional form. It behaves the same way, but is silently ignored if the program does not exist.

Example: seed a new jail from a skeleton directory

Create $HOME/.jai/.initjail:

bash
#!/bin/sh
set -eu

if [ "$JAI_MODE" = strict ] || [ "$JAI_MODE" = bare ]; then
  cp -rL "$JAI_CONFIG_DIR/.skel/." .
fi

Then reference it from a config file:

conf .defaults
jail claude
initjail .initjail

Now the first time jai creates the claude home directory, it will copy in the contents of $HOME/.jai/.skel/.

CLI precedence

Command-line options are parsed both before and after the configuration file. This means command-line arguments always take precedence over config file directives.

Within a configuration file, the conf directive reads the included file at the exact point of the directive — it overrides previous lines and is subject to being overridden by subsequent lines.

Example: full config file

Here is an example ~/.jai/codex.conf:

conf .defaults
mode strict
jail codex
dir agents
dir .codex
setenv PREFIX=${HOME}/agents
setenv PATH=${PREFIX}/bin:${PATH}

This:

  1. Loads sensible defaults (blacklists, etc.)
  2. Ensures strict mode (the default unless the codex jail was previously created in casual mode)
  3. Names the jail codex
  4. Grants access to ~/agents and ~/.codex inside the jail
  5. Sets the PREFIX environment variable, where npm will install software, to ~/agents
  6. Prepends ~/agents/bin to PATH before running the any command in the jail

Now you can install or upgrade codex by running:

bash
jai -C codex npm i -g @openai/codex

And since codex.conf is the default for the codex command, you can invoke codex with:

bash
jai codex