{ description = "Reusable jailed LLM agents (opencode)"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; jail-nix.url = "sourcehut:~alexdavid/jail.nix"; llm-agents.url = "github:numtide/llm-agents.nix"; flake-utils.url = "github:numtide/flake-utils"; }; outputs = { self, nixpkgs, flake-utils, jail-nix, llm-agents, ... }: flake-utils.lib.eachDefaultSystem ( system: let pkgs = nixpkgs.legacyPackages.${system}; jail = jail-nix.lib.init pkgs; defaultPackages = with pkgs; [ bashInteractive curl wget jq git which ripgrep gnugrep gawkInteractive ps findutils gzip unzip gnutar diffutils ]; makeJailedConfig = { name, jail, pkgs, extraPkgs ? [ ], extraCombinators ? [ ] }: with jail.combinators; ( [ network time-zone no-new-session mount-cwd (readwrite (noescape "~/.config/${name}")) (readwrite (noescape "~/.local/share/${name}")) (readwrite (noescape "~/.local/state/${name}")) (add-pkg-deps defaultPackages) (add-pkg-deps extraPkgs) ] ++ extraCombinators ); makeJailedAgent = { name, pkg, extraPkgs ? [ ], extraCombinators ? [ ] }: jail name pkg (makeJailedConfig { inherit name jail pkgs extraPkgs extraCombinators; }); opencode-jailed = makeJailedAgent { name = "opencode"; pkg = llm-agents.packages.${system}.opencode; }; claude-jailed = makeJailedAgent { name = "claude-code"; pkg = llm-agents.packages.${system}.claude-code; }; lib = { # Call as: inputs.jailed-agents.lib.makeJailed system { agentTool = "opencode"; extraPkgs = [...]; } makeJailed = system': { agentTool, extraPkgs ? [ ], extraCombinators ? [ ], }: let pkgs' = nixpkgs.legacyPackages.${system'}; jail' = jail-nix.lib.init pkgs'; pkg' = llm-agents.packages.${system'}.opencode; defaultPackages' = with pkgs'; [ bashInteractive curl wget jq git which ripgrep gnugrep gawkInteractive ps findutils gzip unzip gnutar diffutils ]; makeJailedConfig' = { name, jail, pkgs, extraPkgs ? [ ], extraCombinators ? [ ] }: with jail.combinators; ( [ network time-zone no-new-session mount-cwd (readwrite (noescape "~/.config/${name}")) (readwrite (noescape "~/.local/share/${name}")) (readwrite (noescape "~/.local/state/${name}")) (add-pkg-deps defaultPackages') (add-pkg-deps extraPkgs) ] ++ extraCombinators ); in jail' agentTool pkg' (makeJailedConfig' { name = agentTool; jail = jail'; pkgs = pkgs'; inherit extraPkgs extraCombinators; }); }; test-agent-basic = lib.makeJailed system { agentTool = "test-agent"; }; test-agent-extra = lib.makeJailed system { agentTool = "test-agent-extra"; extraPkgs = [ pkgs.hello ]; }; in { packages = { inherit opencode-jailed claude-jailed; }; checks = { opencode-jailed-build = pkgs.runCommand "test-opencode-jailed" { buildInputs = [ opencode-jailed ]; } '' test -f ${opencode-jailed}/bin/opencode touch $out ''; claude-jailed-build = pkgs.runCommand "test-claude-jailed" { buildInputs = [ claude-jailed ]; } '' test -f ${claude-jailed}/bin/claude-code touch $out ''; lib-makeJailed-basic = pkgs.runCommand "test-lib-makeJailed-basic" { buildInputs = [ test-agent-basic ]; } '' test -f ${test-agent-basic}/bin/test-agent touch $out ''; lib-makeJailed-with-extraPkgs = pkgs.runCommand "test-lib-makeJailed-extraPkgs" { buildInputs = [ test-agent-extra ]; } '' test -f ${test-agent-extra}/bin/test-agent-extra test -d ${pkgs.hello} touch $out ''; test-opencode-tools = pkgs.runCommand "test-opencode-tools" { buildInputs = [ opencode-jailed ]; } '' test -f ${opencode-jailed}/bin/opencode touch $out ''; test-claude-tools = pkgs.runCommand "test-claude-tools" { buildInputs = [ claude-jailed ]; } '' test -f ${claude-jailed}/bin/claude-code touch $out ''; }; lib = { # Call as: inputs.jailed-agents.lib.makeJailed system { agentTool = "opencode"; extraPkgs = [...]; } makeJailed = system': { agentTool, extraPkgs ? [ ], extraCombinators ? [ ], }: let pkgs' = nixpkgs.legacyPackages.${system'}; jail' = jail-nix.lib.init pkgs'; pkg' = llm-agents.packages.${system'}.opencode; defaultPackages' = with pkgs'; [ bashInteractive curl wget jq git which ripgrep gnugrep gawkInteractive ps findutils gzip unzip gnutar diffutils ]; makeJailedConfig' = { name, jail, pkgs, extraPkgs ? [ ], extraCombinators ? [ ] }: with jail.combinators; ( [ network time-zone no-new-session mount-cwd (readwrite (noescape "~/.config/${name}")) (readwrite (noescape "~/.local/share/${name}")) (readwrite (noescape "~/.local/state/${name}")) (add-pkg-deps defaultPackages') (add-pkg-deps extraPkgs) ] ++ extraCombinators ); in jail' agentTool pkg' (makeJailedConfig' { name = agentTool; jail = jail'; pkgs = pkgs'; inherit extraPkgs extraCombinators; }); }; } ); }