Skip to content

Agent Gateway

The Agent Gateway is self-host only. It runs inside your appliance, where agent frameworks on your machine can reach it. The Second Brain MCP server is not limited to the appliance any more: cloud serves 37 tools in single-key mode (v2.49.0), while named per-agent keys and the full 42-tool lane remain appliance surfaces.

The Agent Gateway connects external AI agent frameworks to Glassy, letting you dispatch tasks and share MCP tools from one central workspace.


Overview

The Agent Gateway provides a pluggable adapter system that bridges Glassy with local and cloud-based AI agent frameworks. Each adapter implements a common interface (getStatus, sendTask, getSessions, getConfigSnippet, healthCheck) so you can manage all your agents from a single UI.

Supported Frameworks

Framework Type Default Endpoint Session Continuity
OpenClaw Local http://127.0.0.1:18789 user field in chat completions
Hermes Local http://127.0.0.1:8642 X-Hermes-Session-Key header
Antigravity Cloud Google Gemini API Stateless — dispatch returns sessionId: null

Enabling the Agent Gateway

The Agent Gateway is behind a feature flag and disabled by default.

Server-side

Set in your .env:

ENABLE_AGENT_GATEWAY=true

Client-side

Set in your .env:

VITE_ENABLE_AGENT_GATEWAY=true

Both flags must be enabled for full functionality. The server flag mounts the API routes at /api/agents; the client flag shows the sidebar item and settings section.


Using the Agent Gateway

Adding an Agent Connection

  1. Navigate to Settings → Agent connections (or click Add Agent in the Agent Gateway view).
  2. Select the framework type (OpenClaw, Hermes, or Antigravity).
  3. Enter a label for the connection.
  4. For local agents (OpenClaw, Hermes), enter the base URL (defaults are pre-filled).
  5. For Antigravity, enter your Google API key.
  6. Optionally provide a bearer token for authentication.
  7. Click Add Connection.

The gateway will automatically detect if the framework is running on your machine.

Dispatching Tasks

  1. Open the Agent Gateway from the sidebar.
  2. Click Dispatch on any connected agent card.
  3. Type your task in the dispatch panel (up to 10,000 characters).
  4. Press Ctrl+Enter (or Cmd+Enter on macOS) to dispatch, or click the Dispatch button.
  5. The response will appear in the panel and be logged to the activity feed.

Viewing Activity

The activity feed at the bottom of the Agent Gateway view shows recent dispatches, errors, and connection events. You can filter by action type and load more entries with pagination.

MCP Config Snippets

Each agent connection can generate an MCP config snippet that configures the agent to use Glassy's MCP server. Click MCP Config on any agent row in Settings to view and copy the snippet.

The snippet includes:

  • MCP server URL and authentication header
  • Tool filter (where supported) to limit which Glassy tools the agent can access
  • Framework-specific settings (e.g., enabling the chat completions endpoint for OpenClaw, API server for Hermes)

Event-Triggered Dispatch (Calendar)

v2.36.0-beta.22+ — calendar events can now start agent tasks on their own. Open any event in the Today calendar cockpit and add a "when this event starts, run…" agent task (validated against the same rules as manual dispatch, up to 10,000 characters). A minute-tick cron fires due payloads through your connected agent:

  • At-most-once delivery — every dispatch is written to the agent_dispatch_log ledger before the task is sent, so server restarts never double-fire an event.
  • Flag-gated — set ENABLE_CALENDAR_AUTOMATION=true (plus ENABLE_AGENT_GATEWAY=true) and restart. Off by default; the calendar is fully functional without it.
  • Results in the activity feed — dispatch outcomes land in the same Agent Gateway activity feed as manual dispatches.
  • Rules can fire too — GlassyKeep rules support on_due/on_overdue triggers with dispatch_agent, create_event, and push_reminder actions, deduplicated through the same ledger.

See the Calendar page for the full workflow.


Security

  • SSRF Protection: agent URLs are validated per surface. On the cloud, a strict localhost allowlist applies (localhost, 127.0.0.1, ::1, host.docker.internal) and external URLs are rejected. On a self-hosted appliance (beta.40+), LAN and Tailscale addresses are also allowed (http://192.168.x.x:8642, http://box.tailnet.ts.net:8642) — you own the network the appliance runs on, so pointing an agent at another machine on it is the normal case.
  • CLI Safety: Hermes CLI fallback uses execFile with an args array (not exec), preventing command injection.
  • Rate Limiting: 30 dispatches per minute, 12 status polls per minute per user.
  • Activity Logging: All dispatches and errors are logged to the agent_activity table with 30-day retention. MCP keys and auth tokens are never logged.
  • Token Storage: Config tokens are stored locally in the Glassy database. For Clear (self-hosted) instances, this is on your own machine.
  • User Isolation: On hosted (multi-user) instances, all agent connections are scoped by user_id. Users can only see, edit, delete, or dispatch to their own agents. Activity logs are scoped via JOIN on agent_connections.user_id.
  • SaaS Restrictions: On SaaS instances, local-only agent frameworks (OpenClaw, Hermes) are hidden from the framework selector. Only Antigravity (cloud, Google Gemini API) is available. The agent discovery banner is suppressed. Ollama "local" connection type is also hidden — only "cloud" (ollama.com) is offered.

API Reference

All endpoints are mounted at /api/agents and require authentication.

Method Path Description
GET /api/agents List all agent connections with status
POST /api/agents Create a new agent connection
GET /api/agents/:id Get single agent status
PUT /api/agents/:id Update an agent connection
DELETE /api/agents/:id Delete an agent connection
POST /api/agents/:id/task Dispatch a task to an agent
GET /api/agents/:id/sessions List agent sessions
GET /api/agents/:id/config Get MCP config snippet
GET /api/agents/activity List recent activity
GET /api/agents/discover Discover local agent frameworks

Dispatching a task over the API

POST /api/agents/:id/task with a body whose key is task, not prompt. The task is capped at 10,000 characters.

curl -sX POST http://localhost:8080/api/agents/<connection-id>/task \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"task": "Summarise what changed in the vault today"}'
{ "success": true,
  "response": "…the model's actual answer…",
  "sessionId": "glassy_1790988394714",
  "resumeId": "hres-…",
  "metadata": { "completionId": "chatcmpl-…", "model": "…", "usage": { "total_tokens": 1234 } } }

The session contract, as a rule. sessionId is the session key: pass it back as {"task":"…","options":{"sessionId":"<that value>"}} to continue the same conversation. It is never the provider's per-call id — that is metadata.completionId. A transport with no sessions (Antigravity/Gemini) returns sessionId: null rather than a value that implies resumability.

resumeId is a separate resume handle when the gateway has one. On Hermes, the gateway has two headers: X-Hermes-Session-Key (long-term memory scope — this is what sessionId carries) and X-Hermes-Session-Id (actual conversation history, returned in the response header). The adapter reads that header into resumeId, and you pass it back as {"task":"…","options":{"sessionId":"…","resumeId":"<that value>"}}. Passing back only the key resumes nothing and lets memory accumulate under the key (a field measurement saw 5.3× cost at turn two); forwarding the id is flat at 1.0×. OpenClaw and Antigravity return resumeId: null — OpenClaw resumes on the sessionId it already carries (the user field), and Antigravity has no sessions.

Why that distinction is spelled out

Before v2.41.0 this field carried the provider's completion id instead of the key. Passing it back therefore handed the gateway a key it had never issued, so every turn started a fresh session and re-seeded the agent's full system prompt — which is why multi-turn dispatch looked stateless and expensive, and why a filed report of "dispatch re-pays its context every turn" could not be reproduced as anything else. The observation was right; the handle was wrong.

Optional options. The recognized keys are timeout (positive milliseconds, capped at 10 minutes), model, sessionId, and resumeId. Anything else — including a timeout of "30s", which used to coerce to an immediate abort — comes back in warnings[] naming the key and the reason, and the dispatch still runs:

{ "success": true, "sessionId": "glassy_1790988394714",
  "warnings": [ { "code": "IGNORED_OPTION",
                  "message": "\"timeout\" must be a positive number of milliseconds" } ] }

Nothing is dropped silently, so a dispatch that ignored part of your input says so instead of behaving in a way you have to explain later.

The record of every dispatch lives at GET /api/agents/activity (action, task_text, response_text, timestamp) and in the panel's activity feed. A dispatch that "did nothing" is usually visible there as an error row carrying the upstream message — check that before concluding the connection is wrong.

Agent-as-vault-provider (no-Obsidian self-host)

On a self-host, an operator can declare one Agent Gateway connection the vault provider by setting vaultProvider: true in that connection's config. Then glassy_vault_read and glassy_vault_append dispatch to that agent — which holds the filesystem — instead of needing the Obsidian stack, with a deterministic [glassy-vault-provider] instruction and the agent's reply mapped back (file contents on read, NOT_FOUND → 404, OK/error on write). glassy_obsidian_proxy still requires the full Obsidian stack and is not routed through the provider. The capability is advertised as agentIdentity.agentVaultProvider in GET /api/capabilities, so an agent learns the lane exists rather than improvising an MCP shim behind obsidian_url.


Troubleshooting

Agent shows "Offline"

  • Ensure the agent framework is running on your machine.
  • Check that the base URL is correct (localhost on cloud; on a self-hosted appliance, localhost or any LAN/Tailscale address — beta.40+).
  • Verify any required authentication tokens are set.

Agent shows "Setup needed"

  • OpenClaw: Enable the chat completions endpoint in openclaw.json: gateway.http.endpoints.chatCompletions.enabled: true
  • Hermes: Enable the API server by setting API_SERVER_ENABLED=true in your Hermes .env file. Without the API server, tasks will fall back to the Hermes CLI.

"Hermes CLI not found"

Install the Hermes CLI tool or enable the Hermes API server for task dispatch.

MCP key not found

Generate an MCP key in Settings → Knowledge Base → MCP Server before configuring agents. The MCP key is required for agents to access Glassy tools.