All endpoints live at http://127.0.0.1:9876. Most require an X-Agent-Id
header identifying the calling agent.
Health check. No auth required.
{"status":"ok","uptime_seconds":152986,"agents_online":2}Server statistics (messages, agents, events, token counters).
Prometheus metrics endpoint. No auth required (public, like /health).
Returns Prometheus exposition format text with:
| Metric | Type | Labels | Description |
|---|---|---|---|
envoy_requests_total |
counter | method, path, status |
Total HTTP requests by method, normalized path, and status class (2xx/4xx/5xx) |
envoy_request_duration_ms |
histogram | path |
Request latency in milliseconds. Buckets: 0.5, 1, 5, 10, 50, 100, 500, 1000, 5000 |
envoy_agents_online |
gauge | (none) | Number of currently active agents |
envoy_messages_pending |
gauge | (none) | Reserved for future use (currently always 0) |
envoy_ws_connections |
gauge | (none) | Reserved for future use (currently always 0) |
Path segments that look like IDs (numeric, id* prefix, or UUID format) are collapsed to :id to prevent cardinality explosion. For example, /agents/id1/messages/42/ack becomes /agents/:id/messages/:id/ack.
Example scrape config:
scrape_configs:
- job_name: 'envoy'
static_configs:
- targets: ['127.0.0.1:9876']
scrape_interval: 15s
metrics_path: /metricsRegisters a new agent or returns an existing one (idempotent by name).
Request body:
| Field | Type | Required | Notes |
|---|---|---|---|
name |
string | yes | Human-readable name |
kind |
string | yes | Agent type (e.g. "claude", "hermes") |
parent_id |
string | no | Parent agent ID for subagents |
Response (200):
{
"agent_id": "id1117",
"is_new": true,
"kind": "hermes",
"name": "claude-main",
"online": true,
"parent_id": null,
"lifecycle": "active"
}The response agent_id must be used as X-Agent-Id in all subsequent calls.
Subagents receive hierarchical IDs (e.g. parent id1 -> child id1.1).
Requires X-Agent-Id header.
Cascades to all children.
Request body: {"agent_id": "id1117"}
Response: {"affected": ["id1117", "id1117.1"], "retired": true}
Keep-alive ping.
Messages use a poll-based model. There is no push/WebSocket notification
for incoming messages -- agents must poll /agents/{id}/messages/pending
periodically. This is a known limitation inherited from the MCP query-based
interface.
Request body:
| Field | Type | Required | Notes |
|---|---|---|---|
from |
string | yes | Sender agent ID |
to |
string | yes | Recipient agent ID |
type |
string | yes | "direct" or "broadcast" |
parts |
array | yes | Message parts (see below) |
Each part is a flat object: {"text": "message content"}.
Response: {"message_id": "6751", "status": "delivered"}
Returns undelivered messages for this agent.
Request body: {"agent_id": "id1114"}
Response: {"acked_by": ["id1114"], "message_id": "6751"}
Circuit breaker status for an agent.
Record a circuit breaker failure event.
All session/evidence endpoints are prefixed with /atheneum/.
Request body:
| Field | Type | Required | Notes |
|---|---|---|---|
session_id |
string | yes | UUID, generated by client |
agent |
string | yes | Agent name |
project |
string | yes | Project name |
tool |
string | no | Default: "cli" |
trigger |
string | no | Default: "manual" |
model |
string | no | Model identifier |
git_branch |
string | no | Current git branch |
git_head |
string | no | Current HEAD commit SHA |
parent_session_id |
string | no | Parent session for subagents |
Response: {"session_id": "...", "recorded": true}
Query params: project, last (default 5), parent_id
Inspects a specific session's summary and its associated events and tool calls.
Query params: limit (default 20)
Response:
{
"session": {
"session_id": "sess-1",
"project": "envoy",
"git_branch": "main",
"trigger": "cli",
"started_at": "2026-06-22T00:58:34Z",
"ended_at": null,
"exit_status": "running",
"tool_call_count": 0,
"file_write_count": 0,
"commit_count": 0,
"parent_session_id": null,
"last_tool": null,
"last_tool_summary": null,
"total_input_tokens": 0,
"total_output_tokens": 0,
"total_cost_usd": 0.0
},
"event_count": 1,
"tool_call_count": 0,
"tool_calls": [],
"events": [
{
"event_id": 1,
"event_type": "session_start",
"entity_id": "sess-1",
"session_id": "sess-1",
"payload": {
"project": "envoy",
"tool": "hermes"
},
"timestamp": "2026-06-22T00:58:34Z"
}
]
}Request body:
| Field | Type | Required |
|---|---|---|
exit_status |
string | yes |
prompt_count |
u32 | no |
tool_call_count |
u32 | no |
file_write_count |
u32 | no |
commit_count |
u32 | no |
test_run_count |
u32 | no |
total_input_tokens |
u64 | no |
total_output_tokens |
u64 | no |
total_cost_usd |
f64 | no |
Response: {"status": "ended", "session_id": "..."}
Request body:
| Field | Type | Required | Notes |
|---|---|---|---|
summary |
string | yes | What was done |
files_changed |
string[] | no | Files modified |
outcome |
string | no | Default: "complete" |
Response: {"recorded": true}
Returns recent tool_call events, optionally scoped to one session, plus an aggregated usage summary.
Query params: session_id, limit (default 20)
Response:
{
"count": 2,
"usage": [
{"tool_name": "magellan", "count": 1},
{"tool_name": "mirage", "count": 1}
],
"events": [
{
"event_id": 11,
"event_type": "tool_call",
"entity_id": "sess-1:tool:11",
"session_id": "sess-1",
"payload": {"tool_name": "magellan"},
"timestamp": "2026-06-22T01:10:00Z"
}
]
}Returns recent handoffs with optional project and agent filtering.
Query params: project, agent, limit (default 10)
Response:
{
"count": 1,
"handoffs": [
{
"id": 7,
"name": "claude3->claude4",
"from_agent": "claude3",
"to_agent": "claude4",
"manifest": {"task": "inspect sessions"},
"created_at": "2026-06-22T01:12:00Z"
}
]
}All evidence endpoints return {"recorded": true} on success.
| Field | Type | Required |
|---|---|---|
session_id |
string | yes |
role |
string | yes |
sequence |
u32 | no |
input_hash |
string | yes |
input_tokens |
u64 | no |
output_hash |
string | no |
output_tokens |
u64 | no |
latency_ms |
u64 | no |
model |
string | no |
cost_usd |
f64 | no |
| Field | Type | Required |
|---|---|---|
session_id |
string | yes |
tool_name |
string | yes |
tool_version |
string | no |
input_hash |
string | no |
input_summary |
string | no |
output_hash |
string | no |
output_summary |
string | no |
exit_status |
string | yes |
latency_ms |
u64 | no |
input_tokens_est |
u64 | no |
tool_category |
string | no |
Query recent tool call events and get aggregated counts per tool.
Query params: session_id (optional), limit (default 50)
Response:
{
"count": 1,
"usage": [
{
"tool_name": "magellan",
"count": 1
}
],
"events": [...]
}| Field | Type | Required |
|---|---|---|
session_id |
string | yes |
file_path |
string | yes |
file_id |
string | no |
before_hash |
string | no |
after_hash |
string | no |
lines_added |
u32 | no |
lines_deleted |
u32 | no |
lines_changed |
u32 | no |
write_type |
string | no |
| Field | Type | Required |
|---|---|---|
session_id |
string | yes |
commit_sha |
string | yes |
parent_sha |
string | no |
message |
string | yes |
author |
string | yes |
files_changed |
u32 | no |
lines_inserted |
u32 | no |
lines_deleted |
u32 | no |
commit_type |
string | yes |
feature_tag |
string | no |
| Field | Type | Required |
|---|---|---|
session_id |
string | yes |
test_name |
string | yes |
test_suite |
string | no |
test_command |
string | no |
result |
string | yes |
duration_ms |
u64 | no |
logs_summary |
string | no |
commit_sha |
string | no |
| Field | Type | Required |
|---|---|---|
session_id |
string | yes |
bug_commit_sha |
string | yes |
fix_commit_sha |
string | yes |
fix_type |
string | yes |
severity |
string | yes |
cycles_to_fix |
u32 | no |
time_to_fix_ms |
u64 | no |
| Field | Type | Required |
|---|---|---|
session_id |
string | yes |
bench_name |
string | yes |
mean_ns |
i64 | no |
median_ns |
i64 | no |
p95_ns |
i64 | no |
is_regression |
bool | no |
| Field | Type | Required |
|---|---|---|
session_id |
string | yes |
event_type |
string | yes |
entity_id |
string | yes |
payload |
object | yes |
Query params: session_id, event_type, limit (default 50)
| Field | Type | Required |
|---|---|---|
agent |
string | yes |
discovery_type |
string | yes |
target |
string | yes |
metadata |
object | no |
Response: {"discovery_id": 7502, "agent": "...", "target": "...", "discovery_type": "..."}
Query params: project, limit
Query params: q, language, k (default 5)
Searches symbols across all registered project databases.
Response:
{
"query": "build_router",
"language": "rust",
"count": 3,
"results": [
{"project": "envoy", "id": 25495, "kind": "Symbol", "name": "build_router", ...}
]
}Query params: q, language, k (default 5), depth (default 1)
BFS from search hits into per-project subgraphs. Returns entities and edges.
Response:
{
"count": 1,
"views": [
{
"project": "envoy",
"entry_id": 25495,
"entities": [...],
"edges": [{"id": 31638, "kind": "CALLER", "from_id": 25495, "to_id": 25518}]
}
]
}Returns entity count, edge count, and per-kind breakdowns.
Returns incoming and outgoing edges for an entity.
Query params: depth (default 2)
Query recent handoff events.
Query params: project (optional), agent (optional), limit (default 10)
Response:
{
"count": 1,
"handoffs": [...]
}Upgrade to WebSocket for real-time events. The standard MCP interface is poll-based (no push), so this endpoint exists for future use.