Gateway
The Gateway is the persistent process that keeps OpenVesper running. Hub-and-spoke architecture: every channel routes through one place, with shared sessions, proactive heartbeats, command queue, compaction, routing, and delegation.
Why a persistent process?
- One session shared across CLI, Telegram, VSCode (channel docking)
- Heartbeats run on schedule โ agents message you proactively
- Steer in-flight runs by sending follow-up messages
- Compact long conversations automatically
- Async API for long-running tasks (runId + wait/abort)
- WebSocket transport for real-time streaming
- OAuth flows handled locally with PKCE
Starting the gateway
Foreground (logs to your terminal):
vesper gateway startDetached background:
vesper gateway start --detach
vesper gateway status
vesper gateway logs --lines 100
vesper gateway stopChannel commands
Any message starting with / is intercepted before reaching the LLM:
| Command | Effect |
|---|---|
/new | Start a fresh session |
/reset | Clear current session messages |
/status | Show session info, running run, queue state |
/agent <mode> | Switch active agent |
/queue <mode> | Set queue mode: steer / followup / collect / default |
/compact [hint] | Summarize old messages to free context |
/stop | Abort the current run |
/help | List available commands |
Queue modes (handling mid-run messages)
What happens when you send a new message while the agent is busy? Three modes:
steer(default) โ inject into the active run after current tool calls, before the next LLM call. Use this for "wait, actually do X instead".followupโ queue the message, deliver as a new turn after current ends. Debounce 1s by default.collectโ batch multiple queued messages and deliver as one structured prompt.
Async API
For long-running tasks, fire-and-forget then check back:
# Returns immediately with { runId, acceptedAt }
curl -X POST http://127.0.0.1:18789/agent/async \
-d '{"sessionKey":"u1", "message":"analyze 100 tokens"}'
# Later โ block until done (timeout 5 min default)
curl -X POST http://127.0.0.1:18789/agent/run/r_xyz/wait
# Or cancel
curl -X POST http://127.0.0.1:18789/agent/run/r_xyz/abortCompaction
When the context window fills up, OpenVesper compacts the conversation: older messages are summarized into a single system message, recent messages kept verbatim. Trigger manually with /compact or via API:
# Check token usage
curl http://127.0.0.1:18789/sessions/u1/tokens
# Compact (keep last 10 messages verbatim)
curl -X POST http://127.0.0.1:18789/sessions/u1/compact \
-d '{"keepRecent": 10}'Multi-agent routing
The router examines a message and picks the best specialist agent:
curl -X POST http://127.0.0.1:18789/agent/route \
-d '{"message":"check this Solana token for rugs"}'
# โ { "mode": "bags-hunter", "score": 12, "reason": "matched: solana, token, rug" }Delegation
One agent can sub-query another without changing your active agent:
curl -X POST http://127.0.0.1:18789/agent/delegate \
-d '{
"parentSessionKey": "u1",
"delegateAgent": "code-reviewer",
"query": "review this snippet for security issues"
}'Or hand off the entire session:
curl -X POST http://127.0.0.1:18789/agent/handoff \
-d '{"sessionKey":"u1", "newAgent":"defi-strategist"}'OAuth (local PKCE flow)
Plugins that need Gmail, Calendar, GitHub access can authorize via OAuth. The entire flow runs on your machine โ tokens never leave it.
# Authorize Google (Gmail + Calendar)
vesper oauth login google \
--client-id YOUR_GOOGLE_CLIENT_ID \
--client-secret YOUR_SECRET
# A URL prints โ open it, authorize, browser redirects to localhost:53174,
# tokens save to ~/.openvesper/tokens/google.json (mode 0600).
# List authorized providers
vesper oauth list
# Revoke
vesper oauth logout googleBuilt-in provider templates: google, github, slack. You bring your own Client ID โ register an OAuth app with the provider.
Heartbeat daemon
Scans .agents/ for HEARTBEAT.md files with enabled: true. On schedule, the gateway wakes each agent with its checklist. If the agent has work, it runs tools and returns a reply (delivered via the configured channel). If not, it returns HEARTBEAT_OK โ gateway silently suppresses.
Endpoints
Bound to 127.0.0.1:18789 by default. Never exposed publicly.
Agent
| Method | Path | Purpose |
|---|---|---|
| POST | /agent | Sync run, returns full reply |
| POST | /agent/async | Async run, returns runId |
| POST | /agent/stream | SSE streaming reply |
| GET | /agent/run/:runId | Run status |
| POST | /agent/run/:runId/wait | Block until complete |
| POST | /agent/run/:runId/abort | Cancel |
| POST | /agent/route | Routing decision |
| POST | /agent/delegate | Sub-query another agent |
| POST | /agent/handoff | Transfer session |
Sessions
| Method | Path |
|---|---|
| GET | /sessions |
| GET | /sessions/:key |
| POST | /sessions/:key/reset |
| POST | /sessions/:key/agent |
| POST | /sessions/:key/compact |
| GET | /sessions/:key/tokens |
| GET | /sessions/:key/queue |
| POST | /sessions/:key/queue/mode |
OAuth & Heartbeat
| Method | Path |
|---|---|
| POST | /oauth/start |
| GET | /oauth/tokens |
| GET | /oauth/tokens/:provider |
| DELETE | /oauth/tokens/:provider |
| GET | /heartbeat/status |
| POST | /heartbeat/reload |
| GET | /lanes |
| GET | /health |
| WS | /ws |
Security
- Loopback bind default. Gateway listens on
127.0.0.1only. - No remote access without explicit setup. Use Tailscale, SSH tunnel, or Cloudflare Tunnel.
- Session files mode 0600. Only your user can read them.
- OAuth tokens mode 0600. Stored at
~/.openvesper/tokens/. - Tool permissions still enforced. Mutating tools audit or prompt.
- Zero data retention. No OpenVesper servers. Nothing leaves your machine.
Hooks (extensibility)
8 lifecycle events: agent:bootstrap, agent:tool-call, agent:tool-result, agent:complete, agent:error, agent:queued, command:new, command:reset.
import { hooks } from "@openvesper/gateway/hooks";
hooks.register("agent:bootstrap", async (ctx) => {
ctx.systemPrompt += "\n## Local time\n" + new Date().toISOString();
return ctx;
});