Skip to content

orch-monitor API

The orch-monitor process serves the dashboards (web + HUD) and a set of read-only HTTP endpoints. This page documents the Claude-account posture surface (CTL-1653); it is per-node and token-free by construction.

Returns this node’s Claude-account posture: the active account, each account’s 5h/7d utilization / reset times / status, and a sibling account with headroom. The response is derived from the CTL-1650 durable-token probe run in a token-scoped subshell, so no token value ever appears in the response (or in the monitor’s own environment).

  • Cached (~5 min TTL). Repeated calls within the TTL are served from cache — the same probedAt is returned and no inference call is spent.
  • ?refresh=true forces a fresh probe (operator-initiated; the only per-request probe path). Requires the X-Catalyst-Refresh header (any value), a trusted Host header, and a trusted Origin when one is present. The header is what stops a simple cross-site request (an <img>, a top-level navigation, a plain <form> GET — none of those can attach a custom header); the Host check is what stops a DNS-rebinding page (one that starts on an attacker domain and later re-resolves to this server’s own address, at which point it is same-origin to the browser and can attach the header with no CORS preflight, and may carry no Origin at all) — a plain read (no refresh) needs none of this.
    Terminal window
    curl -H "X-Catalyst-Refresh: 1" "http://localhost:7400/api/accounts?refresh=true"
  • Disabled — on a node with no claude-accounts.env (missing entirely, empty, or defining no usable CLAUDE_TOKEN_* entry — every entry still the PASTE_TOKEN_HERE placeholder counts as none), or when the probe is disabled, the endpoint returns { "available": false, "node": "<host>" }.
{
"available": true,
"node": "mini-2",
"generatedAt": "2026-08-05T12:00:00.000Z",
"probedAt": 1754395200000,
"cached": false,
"status": "rejected",
"active": {
"label": "acctA",
"email": "a@example.io",
"overallStatus": "rejected",
"representativeClaim": "seven_day",
"bindingWindow": "seven_day",
"bindingStatus": "rejected",
"fiveHour": { "pct": 40, "resetsAt": "2026-08-05T13:00:00.000Z", "status": "allowed" },
"sevenDay": { "pct": 100, "resetsAt": "2026-08-06T00:00:00.000Z", "status": "rejected" },
"error": null
},
"accounts": [/* one token-free view per account */],
"siblingWithHeadroom": { "label": "acctB", "email": "b@example.io" }
}

The node-level status is one of:

statusMeaning
okThe active account’s binding window is allowed.
degradedThe binding window is allowed_warning (nearing the limit).
rejectedThe active account is exhausted (binding window rejected) — the loud state.
errorThe probe hit a transport failure (the sensor is broken, not the account exhausted).
unknownNo account is active (CLAUDE_CODE_OAUTH_TOKEN unset).

An SSE stream of the same posture. On connect it emits the current cached summary immediately; a periodic probe (default 5 min) then pushes a fresh frame on each refresh. Each event:

event: account
data: { …the /api/accounts summary body… }

The web footer + HUD strip subscribe to this stream so the active-account indicator and the loud exhausted banner/overlay update live without a reload. When the active account’s binding window transitions ok↔rejected, the monitor also appends one edge-triggered account.status.changed event to the unified event log.