Secure Nix sandbox for LLM agents. Run AI coding agents in isolated environments with controlled access.
jailed-agents provides a secure sandbox for running LLM coding agents using Nix and jail.nix (which is built on bubblewrap). It gives your AI agents the autonomy to be useful without giving them full access to your system.
- Zero-Trust Sandbox: By default, agents have no access to your home directory, SSH keys, or other sensitive files.
- Sensible Defaults: Comes with a curated set of 14 common packages and secure jail options enabled out-of-the-box.
- Composable: Reuse common configurations to create custom, sandboxed environments for your agents.
- Pre-configured Agents: Ready-to-use jails for popular agents like
crush,opencode, andpi. - Custom Agent Builder: Easily create secure jails for any agent with the
makeJailedAgentfunction. - Declarative Tooling: Explicitly define which commands, packages, and directories the agent can access.
- Seamless Nix Integration: Works perfectly with your existing Nix Flakes setup.
Add jailed-agents as an input to your flake.nix:
inputs.jailed-agents.url = "github:andersonjoseph/jailed-agents";You can use jailed-agents in two ways:
Build and run a pre-configured agent in one command:
nix run github:andersonjoseph/jailed-agents#jailed-opencodeOr add jailed-agents as an input and run:
nix run .#jailed-opencodeAdd a customized agent to your devShell:
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
jailed-agents.url = "github:andersonjoseph/jailed-agents";
};
outputs = { nixpkgs, jailed-agents, ... }:
let
system = "x86_64-linux";
pkgs = import nixpkgs { inherit system; };
in {
devShells.${system}.default = pkgs.mkShell {
packages = [
(jailed-agents.lib.${system}.makeJailedOpencode {
extraPkgs = [ pkgs.nodejs pkgs.python3 ];
})
];
};
};
}Run nix develop, and the jailed-opencode command will be available in your shell.
Note on Security: The
jailed-prefix (e.g.,jailed-crush) makes it clear that you are running a sandboxed version of the agent. If the agent attempts to access a file outside of its approved directories, you will see a "Permission denied" error. This is the sandbox correctly enforcing its security boundaries, not a bug.
jailed-agents provides pre-configured builders for the following agents:
| Agent | Builder Function | Default Command |
|---|---|---|
claude-code |
makeJailedClaudeCode |
jailed-claude-code |
crush |
makeJailedCrush |
jailed-crush |
gemini-cli |
makeJailedGeminiCli |
jailed-gemini-cli |
opencode |
makeJailedOpencode |
jailed-opencode |
pi |
makeJailedPi |
jailed-pi |
These builders come with sensible defaults and include the necessary config paths for the agent to function correctly out of the box.
You can customize agents by overriding the default options.
Override the agent's package or change the command name.
(jailed-agents.lib.${system}.makeJailedOpencode {
name = "secure-opencode";
pkg = pkgs.opencode_2_0;
})Include additional packages in the sandbox environment.
(jailed-agents.lib.${system}.makeJailedOpencode {
extraPkgs = [ pkgs.nodejs pkgs.python3 ];
})Provide read-write or read-only access to directories.
(jailed-agents.lib.${system}.makeJailedOpencode {
extraReadwriteDirs = ["~/projects"];
extraReadonlyDirs = ["~/readonly-cache"];
})If an agent is not pre-configured, you can easily create a jail for it using makeJailedAgent.
(jailed-agents.lib.${system}.makeJailedAgent {
name = "my-custom-agent";
pkg = pkgs.my-agent-package;
configPaths = [
"~/.config/my-agent"
"~/.local/share/my-agent"
];
extraPkgs = [
pkgs.pandoc
pkgs.ffmpeg
];
})Tip: Prefer using the pre-configured builders (
makeJailedCrush,makeJailedOpencode,makeJailedPi) when possible, as they provide simpler APIs and sensible defaults. UsemakeJailedAgentonly for unsupported agents or for full control.
For ultimate control, you can use the internals API to access the underlying jail.nix combinators. This allows you to modify base jail options, such as disabling network access.
let
jail = jailed-agents.lib.${system}.internals.jail;
combinators = jail.combinators;
in
{
# Example: Disable network access for opencode
packages.x86_64-linux.opencode-no-net = jailed-agents.lib.${system}.makeJailedOpencode {
baseJailOptions = [
combinators.time-zone
combinators.no-new-session
combinators.mount-cwd
];
};
}For a complete reference on available combinators, see the jail.nix combinators documentation.
Here is an example of how to set up a Go development environment with a jailed crush agent that has access to the Go toolchain.
{
description = "Go development environment";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
jailed-agents.url = "github:andersonjoseph/jailed-agents";
};
outputs = { nixpkgs, jailed-agents }:
let
system = "x86_64-linux";
pkgs = import nixpkgs {
inherit system;
config.allowUnfree = true;
};
in {
devShells.${system}.default = pkgs.mkShell {
hardeningDisable = [ "fortify" ];
packages = with pkgs; [
go
gopls
golangci-lint
go-task
# Provide the Go toolchain to the jailed agent
(jailed-agents.lib.${system}.makeJailedCrush {
extraPkgs = [
go
gopls
golangci-lint
go-task
libgcc
gcc
];
})
];
};
};
}makeJailed<AgentName> {
name ? "jailed-<agent-name>",
pkg ? /* default package from llm-agents.nix */,
extraPkgs ? [],
extraReadwriteDirs ? [],
extraReadonlyDirs ? [],
baseJailOptions ? commonJailOptions,
basePackages ? commonPkgs
}makeJailedAgent {
name,
pkg,
configPaths,
extraPkgs ? [],
extraReadwriteDirs ? [],
extraReadonlyDirs ? [],
baseJailOptions ? commonJailOptions,
basePackages ? commonPkgs
}name: (Required) The command name for the jailed agent.pkg: (Required) The agent package to sandbox.configPaths: (Required formakeJailedAgent) A list of essential configuration paths the agent needs read-write access to (e.g.,["~/.config/my-agent"]).extraPkgs: A list of additional packages to include in the sandbox.extraReadwriteDirs: A list of directories to mount with read-write access.extraReadonlyDirs: A list of directories to mount with read-only access.baseJailOptions: Overrides the default set of jail options.basePackages: Overrides the default set of base packages.
- Common Packages: All agents include
bash,curl,wget,jq,git,ripgrep,gnugrep,gawk,ps,findutils,gzip,unzip,gnutar, anddiffutils. - Common Jail Options: All jails include network access, system timezone propagation, prevention of new session creation, and mounting of the current working directory.
Docker is a heavy solution for this use case and would require you to duplicate your Nix environment inside a Dockerfile. jailed-agents is built on technologies that integrate seamlessly with a Nix-based workflow:
bubblewrap: The same lightweight sandboxing technology used by Flatpak.jail.nix: A declarative, Nix-native library for buildingbubblewrapsandboxes.- Nix Flakes: Integrates directly into your existing development environment without extra overhead.
Contributions are welcome! Please feel free to open a pull request for:
- New pre-configured agent setups
- Additional composable building blocks
- Bug fixes and general improvements
This project is built on the great work of others:
- jail.nix by Alex David
- llm-agents.nix by Numtide
- bubblewrap
This project is licensed under the MIT License - see the LICENSE file for details.