Skip to content

edgeplaned Daemon

edgeplaned is the headless work-executor daemon. Think of edgeplane as kubectl and edgeplaned as kubelet — edgeplane is the operator interface, edgeplaned is the node-side executor. Agents communicate with it via Unix socket; operators interact through edgeplane agent commands, not edgeplaned directly.

edgeplaned absorbed these daemon responsibilities across v0.8–v0.10:

VersionResponsibility
v0.8–v0.9Fleet agent lifecycle (launch, restart, Zellij integration via ZellijHosted runtime)
v0.9Cron dispatch — ~/.edgeplane/edgeplaned/cron.toml, 1-minute tick loop
v0.10Watchdog — polls systemd units, restarts dead agents with throttling
v0.15+Task worker — ephemeral subagent spawning for mesh execution

For normal operation, use edgeplane daemon up. For advanced scripting or debugging, invoke edgeplaned directly:

Terminal window
edgeplane daemon up
# Advanced / debug
edgeplaned run --backend-url http://localhost:8008

edgeplaned reads its node identity from /etc/edgeplane/node.json at startup. Register the node first:

Terminal window
edgeplane agent node register --hostname <hostname>
# → writes JWT to /etc/edgeplane/node.json

For persistent operation, run as a systemd user service:

[Unit]
Description=EdgePlane Daemon
After=network-online.target
[Service]
ExecStart=/usr/local/bin/edgeplaned run --backend-url http://localhost:8008
Restart=on-failure
RestartSec=5
EnvironmentFile=%h/.edgeplane/env
[Install]
WantedBy=default.target

edgeplaned supports these agent runtime kinds (see crates/edgeplaned/crates/edgeplaned-runtimes/src/):

RuntimeDescription
claude_codeOne-shot claude -p
claude_agent_acpPersistent JSON-RPC; ACP protocol
codexOpenAI Codex CLI
geminiGoogle Gemini CLI
zellij_hostedLong-running agents hosted in a Zellij pane; signals via edgeplane agent signal

All sockets live in ~/.edgeplane/edgeplaned/:

SocketPurpose
mgmt.sockJSON-RPC 2.0 management gateway
secrets.sockSecrets broker (agent subprocesses only)
edgeplaned.sockPTY attach gateway

As of v0.13.x, edgeplaned supports mediated attach — the tower proxies WebSocket attach requests to the node daemon, eliminating the need for direct network access to agent nodes.

When the web dashboard or edgeplane attach connects to an agent on a remote node:

Web browser → /api/attach-ws → edgeplane-tower → edgeplaned (remote node) → agent PTY

The attach-secret handshake is self-healing — if edgeplaned restarts, it re-registers and re-issues the attach secret. The next attach attempt succeeds automatically.

edgeplaned injects two environment variables into agent subprocesses:

  • EP_SECRETS_SOCKET — path to secrets.sock
  • EP_SECRETS_SESSION — session ID for this agent

Agents retrieve secrets without ever receiving raw credentials:

Terminal window
VALUE=$(edgeplaned get-secret MY_API_KEY)

Or speak the protocol directly:

Terminal window
echo '{"op":"get","session":"'$EP_SECRETS_SESSION'","name":"MY_API_KEY"}' \
| nc -U "$EP_SECRETS_SOCKET"

Raw secret values are never written to disk or embedded in config files.

Jobs are defined in ~/.edgeplane/edgeplaned/cron.toml. edgeplaned reads it at startup and on edgeplane agent cron reload.

[[job]]
name = "my-job"
schedule = "30 6 * * 1-5" # 5-field cron, local time
session = "my-profile" # target profile / Zellij session name
prompt = "run /my-skill"
# dispatch = "signal" # "signal" (default) or "bash"
[[job]]
name = "my-heartbeat"
kind = "heartbeat"
interval = "30m" # "Ns", "Nm", "Nh", "Nd", or compound "2h30m"
session = "my-profile"
prompt = "run /my-check"

Dispatch modes:

dispatchBehavior
signal (default)edgeplane agent signal to the profile agent — has full profile context
bashLiteral shell command passed to bash -c — no LLM, no session

Manage cron:

Terminal window
edgeplane agent cron list # list all jobs and next fire time
edgeplane agent cron describe <name> # full config + last fire
edgeplane agent cron history <name> # recent fires
edgeplane agent cron reload # re-parse cron.toml (no daemon restart needed)
edgeplane agent cron gc-now # force garbage-collect stale dedup entries

Cron schedules are local time. Dispatcher tick is on the order of minutes — sub-minute expressions and sub-minute heartbeat intervals won’t fire faster than the tick.

edgeplaned polls each supervised agent’s systemd unit every 60 seconds. Dead units are restarted with throttling (90s post-restart grace, 30-minute retry throttle) plus an optional nightly restart.

Terminal window
edgeplane agent supervise list
edgeplane agent supervise status <id>
edgeplane agent supervise restart <id>
edgeplane agent supervise pause <id> # disable auto-restart
edgeplane agent supervise resume <id> # re-enable auto-restart

edgeplaned’s task worker runs the claim loop that enables distributed mesh execution. See Architecture: Ephemeral Task Agents for the full model.

Running an agent work loop:

Terminal window
edgeplane daemon agent enroll --domain <id> --runtime claude_code
edgeplane run claude --domain <id>

Environment variables for the work loop:

VariableDefaultPurpose
EP_BASE_URLhttp://localhost:8008Backend URL

Creating a MeshTask for dispatch:

The /work/missions/$MISSION_ID/tasks REST path is an internal API path. The agent-facing interface is via MCP tools — prefer submit_mesh_task from within an agent session and claim_mesh_task for claiming. The curl example below is for direct API access (e.g. from automation scripts or debugging):

Terminal window
curl -X POST http://<edgeplane-host>/work/missions/$MISSION_ID/tasks \
-H "Authorization: Bearer <session-token>" \
-H "Content-Type: application/json" \
-d '{
"title": "task title",
"description": "what to do",
"claim_policy": "first_claim",
"priority": 5
}'

Claim policy options:

PolicyBehavior
first_claimAny available agent with matching capabilities
assignedSpecific agent only
broadcastAll agents

Retry a failed task (internal REST path — prefer the retry_mesh_task MCP tool from agent sessions):

Terminal window
curl -X POST http://<edgeplane-host>/work/tasks/<task-id>/retry \
-H "Authorization: Bearer <session-token>"
  • Event bus threading: task_ready WebSocket events may not wake the work loop reliably in single-worker deployments. The startup poll is the reliable dispatch path — restart the loop after creating tasks if events don’t fire.
  • sudo in tasks: agent subprocesses run without a TTY; sudo will fail unless the node has passwordless sudo configured.
  • GLIBC mismatch: build edgeplane/edgeplaned natively on the target node if it runs an older glibc than your build machine.
  • Tasks vs MeshTasks: the regular task API (/domains/{id}/m/{id}/t) is Kanban-style tracking. The work loop only operates on MeshTask objects at /work/missions/{id}/tasks. Always use the /work/ API when creating tasks for agent dispatch.