Imported from mrdaak/agentsbox (
AGENTS.md). Install upstream withnpx skills add mrdaak/agentsbox. Copyright stays with the author.
Agent Instructions
Infrastructure-only repo (no application source, no tests, no package manager for
this repo itself): Bash/nushell/Node scripts, a Containerfile, pinned-tool Nix
files, and a flake.nix that builds the user-facing agentsbox command. For
build/run usage and repo layout see README.md.
Commands
| Task | Command |
|---|---|
Dev shell (sets AGENTS_TOOLS_DIR, prepends bin/) |
nix develop |
| Build image | nu make.nu build |
| Force rebuild (no cache) + drop nix store volume | nu make.nu rebuild |
| Run container in a project dir | nu make.nu run --workdir <dir> |
| Verify host env (nix, podman, image) | nu make.nu doctor |
No test suite exists — do not create placeholder test files. The dev shell
(nix develop, which the container entrypoint re-execs into) puts nu, bash,
podman, and the repo's own agentsbox/make.nu on PATH (AGENTS_TOOLS_DIR
set, bin/ prepended by the flake shellHook): exercise the real config_*
readers and source make.nu to run its real helpers (e.g. port-flags) directly
rather than reasoning about them in the abstract. nu make.nu build/run/
doctor still need a host — the podman binary is present in-box but nested
podman does not run inside an agentsbox container, so defer those to a host shell.
External References
| Need | File |
|---|---|
| Build/run usage, repo layout, features | README.md |
Conventions & Invariants
- Rootless only: never use
sudoor run Podman as root. - Every
podman run: include--rm,--security-opt no-new-privileges:true,--cap-drop=ALL,--pids-limit,--memory, and--user agent(the box runs as a non-root in-container user). Add--userns=keep-id:uid=1000,gid=1000viauserns-flags— a local Linux podman needs it to map the invoking user onto agent's uid, whilepodman machine(macOS/Windows) rejects--usernsoutright and already id-maps its shared dirs. - In-container home dir is
/home/agent:make.nurun_argsenv vars (XDG_*), every config bind-mount target,built-in-mounts, andbin/agentsbox's default secret target (/home/agent/<filename>) all assume this.bin/shell-entrypointsetsHOME=/home/agent. Change all of them together if the in-container user ever moves. - Project hash parity:
make.nuworkdir-hash,bin/agentsboxsha1_8, andbin/list-secretsall use SHA-1 (first 8 hex) of the canonical absolute workdir path. Do not change the algorithm without re-verifying all three. - Flake package:
dontPatchShebangs = true— scripts areCOPY'd into a container with different nix store paths; patching shebangs breaks them. - Bash strict mode:
set -euo pipefailin every Bash script. Exception:shell-entrypointuses onlyset -e(it re-execs throughnix developand runs fallback logic after failed commands). - Config is parsed, never sourced:
.agentsbox/config.tomland~/.config/agentsbox.tomlare read withnu, never executed — a cloned repo must not run code atentertime. nu -cTOML reads (Bash→nushell boundary only): wrap in2>/dev/null || truefor missing-key handling, but that also hides real parse errors — run the expression bare against a real TOML file first and confirm output before wrapping. Aconfig_*reader that silently returns empty (its feature no-ops) is the signature of a swallowed parse error in itsnu -cbody — run the body bare to surface it. Inside.nufiles, do not spawnnu -c; usetry { open $file | get k } catch { fallback }inline.installed_agentsis global-only (~/.config/agentsbox.toml): the image is a host-level artifact shared by all projects. Fixed set{claude, codex, pi, opencode}; absent key → all four. Switching requires a rebuild.--a2ais incompatible with a customnetwork—enteraborts rather than run a broken A2A mesh. Underhost/container:network modes,--auth,--web, and[[ports]]port publishing are skipped (Podman rejects them).[[volumes]]validation:namematches^[A-Za-z0-9_.-]+$;targetis absolute and must not collide with a built-in mount (/workspace,/nix,/root/.claude, …). Malformed entries are hard errors. Read from both.agentsbox/config.toml(project, prefixedagent-<hash>-<name>) and~/.config/agentsbox.toml(global, prefixedagent-global-<name>); on a shared target the project mount wins (mirrors secrets).[[ports]]is project-only (.agentsbox/config.toml): there is no global ports equivalent — host ports are scarce, not shareable like volumes. Fieldshost/containerare integers;binddefaults to127.0.0.1(0.0.0.0→ LAN). Transported tomake.nuasAGENTSBOX_PORTS(onehost:container:bindper line);port-flagsemits-p <bind>:<host>:<container>, gated onnot no_publish(same flag as--auth/--web).- Nushell list-typed flags (
--foo: list<string>) take a single[a,b]value, not repeated--foo a --foo b. Pass variable-length lists from Bash via env vars (one entry per line) — seeAGENTSBOX_VOLUMES/AGENTSBOX_GLOBAL_VOLUMES/AGENTSBOX_PORTS. default (expr)is eager — use anifwhen the fallback has side effects.- Non-zero externals abort nushell — wrap in
try { … } catch { … }to convert to a custom message/exit. - Secrets are podman secrets, never env vars or baked into
Containerfile/make.nu. Project secrets are prefixedagent-<hash>-<name>, globalsagent-global-<name>; on a shared mount target the project secret wins. :Zon all Podman bind mounts (SELinux-aware systems). Create host dirs withmkdir -pbefore mounting (make.nu runalready does this)./nixvolume image-stamp:make.nuensure-nix-volume-stampedstamps theagent-nix-storevolume'sagents.imagelabel with the running image's full digest (podman image inspect … --format '{{.Id}}'). Onenter, a stamp mismatch (or a legacy unstamped volume) drops and reseeds the volume. Do not change the label key (agents.image) or the digest source ({{.Id}}) without re-verifyingensure-nix-volume-stamped,main rebuild, andmain gc-nix-storetogether.:Uon/nixand/pnpm-store: both named volumes seed from image content owned by root;:Uchowns them to the box user. Without it single-user nix (build-users-group =, no daemon) cannot lock/nix/var/nix/dbas uid 1000 andnix developfails in every box.- Version sync: the
versioninflake.nixand the pinned install URL inREADME.md(github:mrdaak/agentsbox/v<version>) must bump together. No automated check exists; see the release checklist. - Comments: one-line header after the shebang stating what the file does;
inline
#only for non-obvious why (ordering deps, cross-file invariants, footgun guards). Never restate the code or leave commented-out code.
Naming
bin/scripts + config files:kebab-case, no extension.make.nu:constinSCREAMING_SNAKE_CASE; subcommands/helpers inkebab-case. Tasks areexport def "main <name>"; helpers are plaindef.- Nix:
camelCase(buildInputs,shellHook,runtimeDeps).