Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

zeph serve — Persistent Agent Service

zeph serve-sessions runs Zeph as a long-lived process exposing durable conversation sessions over an HTTP/SSE API — create sessions, stream responses, and manage them remotely without an interactive terminal.

Naming note: the command is zeph serve-sessions, not the bare zeph serve you might expect. zeph serve already names the scheduler’s foreground daemon — both features can be enabled in the same build, so a second command claiming the same name wasn’t viable.

cargo build --release --features session
zeph serve-sessions

REST + SSE API

All routes except /health operate on the same durable event log described in Session Persistence and Resume — a session created here can be resumed later via /conv resume or zeph sessions resume in any other channel, and vice versa.

Method & PathPurpose
GET /healthUnauthenticated liveness check — status, uptime, live session count
POST /sessionsCreate a session
GET /sessionsList live session ids
GET /sessions/:idDurable metadata + live status (works even for a session whose actor has ended — it’s still resumable)
DELETE /sessions/:idEnd a live session
POST /sessions/:id/promptSubmit a prompt (fire-and-forget; 202 Accepted once queued)
GET /sessions/:id/eventsServer-Sent Events stream of the session’s output (tokens, tool calls, tool results, turn completion)
POST /sessions/:id/forkEager-copy the session into a fresh child, which becomes immediately usable
# Create a session and stream its output
SID=$(curl -s -X POST http://127.0.0.1:8420/sessions | jq -r .session_id)
curl -N "http://127.0.0.1:8420/sessions/$SID/events" &
curl -X POST "http://127.0.0.1:8420/sessions/$SID/prompt" \
  -H "Content-Type: application/json" \
  -d '{"text": "Summarize this repository."}'

Session Actors

Each live session runs as an independent SessionActor — the agent that owns it runs on a dedicated OS thread with its own async runtime, isolated from every other session and from the HTTP server’s own request-handling. Multiple SSE clients (or an SSE client and a TUI attaching to the same session) can subscribe to one session’s output concurrently; a subscriber that falls behind has its own missed events dropped, never the connection — the durable log is always there to catch up from.

Idle Eviction

A background task (serve.evict) periodically scans for sessions with no attached output subscribers whose activity has gone stale past session_idle_ttl_secs, and ends them — freeing the OS thread and in-memory state. The session itself isn’t deleted: its durable log remains on disk and it can be resumed again later (via this API, /conv resume, or zeph sessions resume), which spins up a fresh SessionActor and replays the log.

Authentication

/sessions* routes can execute shell, file, and web tools on behalf of any caller that reaches the port — treat this API with the same care as a shell. Bearer-token authentication is controlled by require_auth (true by default) and auth_token_vault_key: the token itself is never written to config.toml — only the name of the vault key it’s resolved from at startup.

zeph vault set ZEPH_SERVE_AUTH_TOKEN "$(openssl rand -hex 32)"

If require_auth = true but no token can be resolved from the configured vault key, zeph serve-sessions refuses to bind any address other than loopback — an unauthenticated API on a non-loopback address is a real risk, not a warning to skip past. Set require_auth = false only on a network you fully trust.

--acp

The --acp flag runs the ACP (Agent Client Protocol) transport in-process with zeph serve-sessions. Both the /sessions* HTTP API and the ACP-over-HTTP transport bind to separate listeners and share a single SemanticMemory/SQLite pool and TaskSupervisor, avoiding concurrent writes to the same database file.

# Combined mode (recommended for IDE integration)
zeph serve-sessions --acp

This requires the acp-http feature (bundled in the ide feature bundle). Without it, --acp produces a clear error naming the feature to rebuild with.

Combined Mode Specifics

  • Listeners: /sessions* routes bind to [serve] http_addr; ACP-over-HTTP binds to [acp] http_bind (a second, independent address/port).
  • Shared state: one SemanticMemory/SQLite pool, one TaskSupervisor, one durable event log directory ([session] data_dir). Sessions created via either listener are visible and resumable from the other.
  • Authentication: if [serve] require_auth = true, you must also set [acp] auth_token (resolved from the vault). A non-loopback [acp] http_bind with an unset auth token is rejected at startup to prevent accidentally exposing the shared acp_sessions table unauthenticated.
  • Lifecycle: if either listener crashes, the other is immediately cancelled and the process exits. This avoids silently serving with a broken listener in the background.

Alternatively, run them in separate processes (for debugging, or if you prefer separate resource pools):

zeph serve-sessions &
zeph --acp-http  # in a second process, over HTTP transport

Both processes share the same durable event logs on disk (via [session] data_dir), so sessions created in one are visible and resumable from the other. However, this uses two independent database connection pools, so scale carefully.

Configuration

[serve]
http_addr = "127.0.0.1:8420"              # bind address
require_auth = true                        # require a bearer token on /sessions* (not /health)
auth_token_vault_key = "ZEPH_SERVE_AUTH_TOKEN"  # vault key name to resolve the token from
max_sessions = 50                          # maximum concurrent live sessions
session_idle_ttl_secs = 1800               # idle eviction TTL (30 minutes)
max_queued_prompts = 8                     # per-session prompt mailbox capacity

See Also