No description
  • Go 92.7%
  • Shell 7.3%
Find a file
Claudio Maradonna 415460b5f6
build(release): add -version, the release script, and a Releasing section
`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.
2026-09-04 12:33:04 +02:00
.claude chore: enable localrecall-automatic memory profile 2026-09-03 11:39:50 +02:00
.codex/agents chore: enable localrecall-automatic memory profile 2026-09-03 11:39:50 +02:00
cmd build(release): add -version, the release script, and a Releasing section 2026-09-04 12:33:04 +02:00
docs docs: add a Running section and align constraints wording 2026-09-03 20:05:13 +02:00
internal fix(runner): keep LocalAGI waits off the dispatch and recovery paths 2026-09-03 22:15:12 +02:00
scripts build(release): add -version, the release script, and a Releasing section 2026-09-04 12:33:04 +02:00
.gitignore build(release): add -version, the release script, and a Releasing section 2026-09-04 12:33:04 +02:00
AGENTS.md chore: enable localrecall-automatic memory profile 2026-09-03 11:39:50 +02:00
CLAUDE.md chore: initialize from agent-foundry template 2026-09-03 11:30:11 +02:00
go.mod chore(deps): tidy go.mod after adding the MCP SDK 2026-09-03 18:50:21 +02:00
go.sum chore(deps): tidy go.mod after adding the MCP SDK 2026-09-03 18:50:21 +02:00
LICENSE chore: initialize from agent-foundry template 2026-09-03 11:30:11 +02:00
README.md build(release): add -version, the release script, and a Releasing section 2026-09-04 12:33:04 +02:00

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:

  • listenHOST:PORT for 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 to localagi.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 KillMode at its default, so stopping the service signals the whole control group. A job still running at that point is recorded as interrupted at the next start, and any container left behind is removed then via the job's container.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.0 and its pinned dependency set (jsonschema-go is 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/arm64 build (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.1git clone --depth 1 --branch v2.8.1 https://github.com/mudler/LocalAGI
  • azkaban e82e4a9git clone https://git.unitoo.it/claudiomaradonna/azkaban (headless contract: --cidfile, exit-code propagation, --rm --init signal 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.