← All posts
By The agentjail team

v0.5.0: Daemon Grant Server, Policy Fixes

Grants move from netproxy to daemon with PID-based session binding - no agent can approve its own requests.

v0.5.0 release: daemon-hosted grant server with PID-based session binding and policy hardening

agentjail v0.5.0 is out. The theme this release: grants graduate from the netproxy into the always-on daemon, bound to sessions by OS-level PID verification instead of agent-supplied identity.

Daemon-hosted grant server

In v0.4.0, runtime grants lived on the netproxy control socket. That worked, but it meant grants only existed when --netproxy was active. v0.5.0 moves the entire grant system to the daemon, which is always running.

# Agent (sandboxed) claims a grant:
agentjail allow host api.example.com --reason "fetch deployment status"

# Human (unsandboxed terminal) approves:
agentjail grants
agentjail grant approve <grant_id>

# View full audit history:
agentjail grants --log

The key change is how sessions are bound. Instead of trusting the agent to identify itself, the daemon extracts the requesting process’s PID via SO_PEERCRED (Linux) or LOCAL_PEERPID (macOS) at the socket level. The agent never supplies its own identity — the kernel does.

Grant commands now auto-detect the backend: daemon first, netproxy fallback if available. The merged listing includes a SOURCE column so you can see where each grant lives.

$ agentjail grants
GRANT       HOST                    STATUS    SOURCE    SESSION
a7f2c1      api.example.com         approved  daemon    fdf6ea95
b3d9e4      db.staging.internal     pending   daemon    a303efe0

Full design in ADR 0047.

Hook config protection

A sandboxed agent could silently overwrite ~/.claude/settings*.json to remove agentjail’s hooks — effectively disabling its own guardrails. v0.5.0 adds a file_policy/hook_config ask rule that intercepts writes to these files and requires explicit human approval.

This closes a real gap. The previous no-hook-self-disable rule attempted to catch this, but its Bash regex was overly broad — it matched >= and => as shell redirects, blocking legitimate plugin operations like claude-mem. That rule is removed. The new approach works at the file policy layer, not regex pattern matching, so it catches the actual threat without false positives.

Fail-open sentinel

When agentjail can’t enforce a policy (daemon not running, socket unreachable), it needs to decide: block everything, or let the agent work with a warning? v0.5.0 ships a one-time warning sentinel mechanism that takes the fail-open path but ensures the human sees exactly what happened.

The sentinel fires once per failure mode per session. No repeated warnings for the same issue, no silent failures.

Under the hood

  • SSH port 22 added to sandbox fallback ports — agents that need SSH access no longer require a custom overlay.
  • make dev-install target for contributors: builds, installs, syncs policy rules, restarts the daemon, and verifies the install via SHA-256 checksums. One command.
  • PATH shim regenerated on upgrade so brew and curl installs pick up the current template without manual intervention.
  • Daemon restart uses launchctl kickstart instead of stop+start, avoiding the race where the daemon socket disappears between the two commands.
  • Landlock test fixed to reference the current control socket path (was still pointing at the old one).

Security

daemon-ctl.sock — the socket where grant approvals happen — is denied to the sandboxed agent on macOS via sbpl network-outbound deny, mirroring the isolation already in place for the netproxy control socket. An agent cannot self-approve grants. This is enforced at the OS level, not by convention.

Upgrade

curl -fsSL https://agentjail.io/install.sh | sh
# or
brew upgrade LuD1161/tap/agentjail

Full changelog on the changelog page. Source on GitHub.