- Go 92.7%
- Shell 7.3%
`warden -version` prints the module version Go 1.24+ stamps from the tag on HEAD (a pseudo-version between tags, +dirty for an uncommitted tree) followed by the short commit, so a running binary is always traceable to source without any build flag. scripts/build-release.sh refuses a dirty tree or an untagged HEAD, builds the static linux/arm64 binary into dist/, cross-checks the embedded build info (target, no CGO, clean commit, stamped version), writes SHA256SUMS and signs it with the configured SSH signing key. README documents the procedure and dist/ is ignored. |
||
|---|---|---|
| .claude | ||
| .codex/agents | ||
| cmd | ||
| docs | ||
| internal | ||
| scripts | ||
| .gitignore | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| README.md | ||
warden
Escalation runner for azkaban jails.
warden is a single static-binary Go daemon that lets LocalAGI agents submit bounded jobs which run as non-interactive Claude/Codex sessions inside rootless azkaban jails, and pushes the resulting report back into the agent's conversation. It is the sole policy-enforcement point (budgets, timeouts, queue, audit) between the local model and paid sessions.
Status
Implemented per docs/warden-design.md; the golden contract tests
(tool schemas, job.json, audit lines) and the stub-executor
definition-of-done suite live under internal/. The manual
integration check is documented in docs/manual-integration.md.
Running
warden takes one JSON configuration file and nothing else:
warden -config /path/to/warden.json
warden -version prints the release version and the commit it was
built from, then exits.
The complete field list, with an example, is the "Configuration" section
of docs/warden-design.md. Three fields are worth checking first:
listen—HOST:PORTfor the MCP endpoint, the only listening socket. warden binds it before recovering anything, so a busy or wrong address fails the start instead of spending a session.token_file— the shared MCP bearer token. It must be non-empty and mode 0600; warden refuses to start on a group- or world-accessible token file, and applies the same rule tolocalagi.api_key_file.spool_dir— warden's only persistence, created 0700. It must be an absolute path, as must every other path in the config: warden opens its own files against whatever working directory the service manager gives it, and runs each client launcher from the job directory, so a relative path lands somewhere the config never named.
Service expectations (the unit file belongs to the deployer):
- A simple service with
Restart=on-failure, running as the warden user; rootless podman additionally requires that user to have subuids and lingering enabled. - Leave
KillModeat its default, so stopping the service signals the whole control group. A job still running at that point is recorded asinterruptedat the next start, and any container left behind is removed then via the job'scontainer.cid. - Configuration is read once at startup — there is no reload. Restart the service to apply a change.
Running warden by hand and interrupting it mid-job orphans the jail
session: the executor puts each client launcher in its own process
group, so a terminal's Ctrl-C never reaches it. Prefer the service
manager; after an interrupted hand run, remove any leftover container
with podman rm -f "$(cat <spool_dir>/jobs/<job_id>/container.cid)".
Constraints
- Go standard library plus
github.com/modelcontextprotocol/go-sdk v1.1.0and its pinned dependency set (jsonschema-gois imported directly for the explicit tool schema); any further dependency needs explicit approval. - Estate-neutral: no host names, addresses, or tenant data in code, tests, examples, or docs. Everything deployment-specific comes from the config file.
- Target: static
linux/arm64build (CGO_ENABLED=0); develops and tests on any architecture.
Commands
go mod download # setup
go test ./... # test
go vet ./... && go test ./... && \
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o /dev/null ./cmd/warden && \
scripts/verify-agent-config.sh # verify
Releasing
A release is a signed tag plus the artifacts scripts/build-release.sh
builds from it, uploaded by hand to the forge release for that tag:
git tag -s v0.1.0 -m "warden v0.1.0" # on a clean, tested main
scripts/build-release.sh v0.1.0 # dist/: binary, SHA256SUMS, SHA256SUMS.sig
git push origin main v0.1.0
The script refuses a dirty tree or a HEAD not tagged with the requested
version, builds the static linux/arm64 binary (Go stamps the tag's
version and the commit into it; warden -version prints both), checks
that embedded build info (target, no CGO, version, clean commit), writes
SHA256SUMS, and signs it with the SSH key named by
git config user.signingkey (--no-sign skips that step). Verify a
download with sha256sum -c SHA256SUMS, then check the signature against
the release's published key:
ssh-keygen -Y verify -f allowed_signers -I <principal> -n file \
-s SHA256SUMS.sig < SHA256SUMS
External contracts
The design pins its external contracts to:
- LocalAGI
v2.8.1—git clone --depth 1 --branch v2.8.1 https://github.com/mudler/LocalAGI - azkaban
e82e4a9—git clone https://git.unitoo.it/claudiomaradonna/azkaban(headless contract:--cidfile, exit-code propagation,--rm --initsignal handling, stderr-only diagnostics)
Before implementing a contract, re-verify it against the pinned source; if the source contradicts the design document, the source wins and the document is amended.
License
MIT — see LICENSE.