@openape/nest
v0.3.0
Published
OpenApe Nest — local control-plane daemon that supervises agent processes on this computer. Talks to troop SP for ownership state, spawns/destroys agents via DDISA always-grants, supervises chat-bridge children (replacing per-agent launchd plists).
Maintainers
Readme
@openape/nest
Local control-plane daemon. Manages OpenApe agents on a single machine — provisions macOS users, hands the bridge lifecycle off to launchd, exposes a localhost HTTP API gated by DDISA grant tokens.
What it does
- Runs as a long-lived launchd-managed daemon under your user account (
~/Library/LaunchAgents/ai.openape.nest.plist) - Accepts API calls on
127.0.0.1:9091for agent lifecycle ops (spawn,destroy,list,status) - Every API call requires a DDISA-signed grant token in the
Authorization: Bearer …header - Bridge processes (
openape-chat-bridgeper agent) are NOT supervised in-daemon — they run as system-domain LaunchDaemons (one plist per agent in/Library/LaunchDaemons/eco.hofmann.apes.bridge.<agent>.plist) installed byapes agents spawn --bridge. launchd is the right OS-level supervisor on macOS; trying to duplicate that in the daemon crashloops without adding value.
Setup (one-time)
apes nest install # install + load the launchd plist
apes nest enroll # daemon gets its own DDISA agent identity
apes nest authorize # set the YOLO policy — covers the inner
# `apes agents spawn` calls the daemon makesAfter that, day-to-day lifecycle goes through apes nest:
apes nest spawn igor18 # provision a new agent
apes nest list # show agents this nest knows about
apes nest status # health-check
apes nest destroy igor18 # tear down
apes nest uninstall # remove the launchd plistWhy every API call needs a grant token
Without auth the API is gated only by "process running as the logged-in human can reach localhost:9091" — a compromised local process inherits everything. The grant-token requirement closes that gap and gives every call an audit record at the IdP. The flow:
apes nest <op>looks for an existing approved'always'/'timed'grant matching the operation.- If none, requests a fresh grant from the IdP. First-time grants for human callers wait for human approval (one approval covers the lifetime of the grant —
'always'is the default for nest-CLI calls). - Token (RFC-7519 JWT signed by the IdP) is fetched and presented as
Authorization: Bearer …. - The Nest verifies signature against the IdP's JWKS, checks
aud=nest,iss=<IdP URL>,target_host=<local hostname>, and exact-matches the embeddedcommandclaim against the route. Fails:401(auth) or403(command mismatch).
Grant-scope conventions
| CLI | Grant command | Reuse semantics |
|---|---|---|
| apes nest list | ["nest","list"] | One approval, reused forever. |
| apes nest status | ["nest","status"] | One approval, reused forever. |
| apes nest spawn <name> | ["nest","spawn"] (no name baked in) | One approval, any future spawn. Trade-off: a compromised local process running as the human can spawn arbitrary agents under that grant. Acceptable because spawn is reversible and audited. |
| apes nest destroy <name> | ["nest","destroy","<name>"] | Per-name. Destroying each agent is its own approval. Destructive ops keep tighter scoping by design. |
Direct curl to the API is supported but you must fetch a grant token yourself. See tests/auth-negative.sh for an example token-fetch.
Negative-test smoke
bash apps/openape-nest/tests/auth-negative.shVerifies: no-bearer → 401, garbage-bearer → 401, wrong-audience → 401, command-mismatch → 403.
Why no in-daemon bridge supervisor
Earlier versions ran a per-agent process supervisor inside the Nest daemon to keep openape-chat-bridge instances alive. It was removed because:
apes agents spawn --bridgealready installs a system-domainLaunchDaemonper agent. launchd KeepAlive's it as the agent UID with the right PATH (the bridge binary is at/Users/<agent>/.bun/bin/openape-chat-bridge).- The supervisor's children inherited the daemon's PATH (the human user's PATH, which doesn't include any agent's
~/.bun/bin), so they crashlooped onCommand not found: openape-chat-bridgewhile the launchd-domain bridge ran fine. - Each crashloop produced an auto-approved YOLO grant — pushing one notification per cycle.
Single-source-of-truth on launchd. The Nest is now an API surface in front of apes agents spawn|destroy, nothing more.
