Releases: tesserine/agentd
v0.1.1
Daemon that runs autonomous AI agent sessions in ephemeral Podman containers.
This release introduces per-invocation work input, aligns with the shared commons exit-code convention, and tightens container isolation.
Added
- Per-invocation work input.
agentd runaccepts one of three mutually-exclusive work surfaces without profile edits:--work-unit <id>,--request <text>, or--artifact-type <type> --artifact-file <path>. Request text is synthesized into.runa/workspace/request/operator-input.json; artifact-file input places validated JSON at.runa/workspace/<type>/<file-stem>.json. The runner enforces mutual exclusion and validates path components at the trust boundary regardless of caller. - Canonical request convention.
--requestdepends on the configured methodology declaring support for the commons canonical request artifact type with a supported version (1.0.0in v0.1.x). Unsupported or undeclared methodologies reject text input with an actionable error instead of silently materializing unchecked content. - Explicit
audit_rootin runner API.agentd_runner::SessionSpecrequires an explicitaudit_rootfield.
Changed
- Shared exit-code convention. Session outcomes across
agentdandagentd-runnercarry semantic labels plus raw exit codes. Daemon and CLI surfaces report labels such asblockedandgeneric_failure.agentd runexits successfully for normal terminal states (success,blocked,nothing_ready). Timeout remains an agentd-layer outcome outside the shared exit-code vocabulary. - Linux-only platform contract.
agentd-runnerdeclares its platform contract at compile time. Non-Linux builds now fail explicitly instead of compiling dead fallback code. - Bind mount reservation scoping. Additional bind mounts reserve only runner-owned targets (
/agentd/methodology,/home/{profile},/home/{profile}/repoplus descendants), allowing supported read-only and read-write mounts elsewhere under$HOMEwithout runner setup mutating host-backed data. - Profile bind-mount overlap detection. Profile-declared bind mounts reject overlapping container targets within the same profile before container startup.
- Audit record defaults. Persistent audit records default to
$XDG_STATE_HOME/tesserine/audit/<profile>/<session_id>/, falling back to$HOME/.local/state/tesserine/audit/<profile>/<session_id>/for rootless installs.daemon.audit_rootis available as an explicit override for root-owned system installs. - Audit sealing discipline. Completed audit records seal directories to
0555and non-symlink entries to0444, skip symlinks while sealing, and updateagentd/session.jsonthrough atomic temp-file replacement.
Fixed
- Session teardown skips audit finalization and sealing when cleanup fails, leaving
agentd/session.jsonintentionally incomplete instead of marking a session complete while its audit bind mount may still be live. - Completed session outcomes remain caller-visible when only audit finalization fails after teardown cleanup succeeds.
- Audit sealing refuses multi-linked entries before rewriting metadata, preventing host file mode changes through hard-linked audit aliases.
- Allocation rollback failure preserves the incomplete audit-record signal instead of finalizing
agentd/session.jsonafter leaked cleanup state.
Dependencies
Requires runa v0.1.1 or later (uses the new .runa/workspace/ invariant) and commons v0.1.1 or later (uses the canonical request artifact spec).
Late additions (April 22, 2026 evening)
After the initial v0.1.1 work was tagged, integration testing surfaced a foundational gap that became #84: agentd run (the client subcommand) was reading the daemon's config file to find the socket path, coupling client and daemon to a shared file in a way that produced footguns at deployment. PR #85 decoupled the client from the daemon config:
agentd runnow finds the daemon via well-known socket-path convention or explicit--socket-pathoverride; never reads daemon config.- Default socket discovery walks
$XDG_RUNTIME_DIR/agentd/agentd.sock→/tmp/agentd-$UID/agentd.sock→/run/agentd/agentd.sock, with each candidate verified by Ping/Pong handshake before being selected. - Default
/tmp/agentd-$UID/directory creation is now atomic viamkdir(2)with mode 0700, eliminating a TOCTOU race against symlink substitution. - Profile resolution moved entirely to the daemon side; client sends profile name and lets the daemon resolve
repodefaults. - Bare
agentd --config /path/to/agentd.tomlstill works as a daemon-mode shorthand foragentd daemon --config /path/to/agentd.toml.
This work was foundational enough to gate v0.1.1's tag on its completion; the tag now points at the post-#84 merge commit.
v0.1.0
Daemon that runs autonomous AI agent sessions in ephemeral Podman containers.
Key capabilities:
- Foreground daemon with single-instance enforcement via PID file
- Unix socket operator interface for manual and scheduled session dispatch
- Profile-based configuration: base image, methodology mount, credentials, session command
- Ephemeral Podman containers with unprivileged execution, credential injection via secrets, and force-removal on teardown
- Startup reconciliation of stale resources from prior runs
- Cron-based profile scheduling through the daemon socket
- Structured JSON logging with tracing
- Two-signal shutdown: first SIGTERM drains, second force-exits