Summary
Audit of telemetry across relay (this repo) and relaycast (hosted side) revealed three classes of problems:
- Data is fragmented across two PostHog projects with no shared identity, so we can't answer basic usage questions.
- Missing dimensions mean even within each project we can't segment by harness, can't split CLI vs SDK, and can't count unique humans.
- PostHog keys are hardcoded in source, so forks pollute our data and we have no dev/staging separation.
This issue tracks the full fix plan, prioritized.
What we can answer today
| Question |
Status |
Notes |
| Total users of agent-relay |
⚠️ Partial |
Two PostHog projects; client uses hashed machine-ID, server uses workspace-ID. No join. |
| CLI vs SDK split |
❌ No |
SDK (packages/sdk/) emits zero telemetry. |
| Agents spun up |
✅ Yes (client) |
Broker agent_spawn event in src/telemetry.rs + src/main.rs:~1643. |
| OS distribution |
✅ Captured, ❌ not surfaced |
os/os_version/arch on every event (packages/telemetry/src/events.ts:55-76); no dashboard segments on it. |
| Messages sent |
✅ Yes |
Client: message_send. Server: usageRecords.messagesSent + messageLogs. |
| Which harnesses used most |
❌ No |
Broker tracks the spawned child's CLI (normalize_cli_name, src/main.rs:6666), not the parent harness (Claude Code vs Cursor vs Codex vs Gemini). |
Gaps
- No SDK telemetry —
packages/sdk/ has no track() calls. Can't measure SDK adoption.
- No orchestrator/harness identification — broker doesn't record what's driving it.
- No install / update / first-run events —
runInstallCommand in src/cli/lib/core-maintenance.ts is silent. No adoption curve.
- No broker crash/panic telemetry — Rust panics fire nothing.
- No unique-user metric on the server —
distinct_id = workspace_id (relaycast/packages/server/src/lib/telemetry.ts:18). 1 workspace with 10 humans looks like 10 workspaces with 1 human.
- No cross-workspace admin dashboard —
/console/stats (relaycast/packages/server/src/routes/console.ts) is per-workspace only.
- No workflow step / swarm worker granularity —
workflow_run fires once at completion; no per-step timing or failure data.
- MCP telemetry is a third silo —
src/cli/relaycast-mcp.ts uses @relaycast/mcp telemetry which goes to the relaycast PostHog, not relay's.
- Dashboard apps have zero client analytics —
observer-dashboard, site/ have no PostHog JS.
Set up poorly
- Two PostHog projects with no shared identity — same human shows up as a hashed machine-ID in one, workspace-ID in the other.
- Workspace ID as distinct_id on the server side — should be authenticated user with workspace as a group/property.
origin_client is always '@relaycast/mcp' (relaycast/packages/mcp/src/telemetry.ts:219) — useless for harness segmentation.
- PostHog is doing double duty as log sink (
relaycast/packages/server/src/lib/logger.ts:166) and event store — OTel logs aren't indexed as events and pollute volume.
- No server-side raw event log — if PostHog is down, events vanish.
- Event schema drift risk —
relay/packages/telemetry/src/events.ts and relaycast/packages/types/src/telemetry.ts define overlapping events independently.
Fix plan
P0 — Answer the business questions (this week)
P0.5 — Extract PostHog keys from source
PostHog phc_* keys are write-only and safe to be public — the reasons to extract them are: stopping forks from polluting prod data, enabling staging separation, and quota protection.
P1 — Make the data trustworthy (this sprint)
P2 — Queryable without PostHog UI
Repo scope
The repos should stay separate (different release cycles, different deploy targets, different blast radius). The fragmentation problem is in the data, not the code boundary — fixed by unifying the PostHog project + the event schema, not by merging the repos.
Files most likely to change
relay:
src/telemetry.rs — key extraction, harness field, panic hook
src/main.rs — harness detection, panic hook
packages/telemetry/src/events.ts — schema additions (orchestrator_harness, app)
packages/telemetry/src/client.ts — key from build env, no-op when missing
packages/sdk/ — new telemetry hooks
src/cli/lib/core-maintenance.ts — install/update events
.github/workflows/release.yml — POSTHOG_KEY secret injection
relaycast:
packages/server/src/lib/serverTelemetry.ts — read X-Relaycast-Harness, store on event
packages/server/src/lib/telemetry.ts — distinct_id strategy
packages/mcp/src/telemetry.ts — kill hardcoded key default, send harness header
packages/server/src/routes/console.ts (or new admin.ts) — cross-workspace analytics endpoint
packages/server/src/lib/logger.ts — split logs off PostHog
Summary
Audit of telemetry across
relay(this repo) andrelaycast(hosted side) revealed three classes of problems:This issue tracks the full fix plan, prioritized.
What we can answer today
packages/sdk/) emits zero telemetry.agent_spawnevent insrc/telemetry.rs+src/main.rs:~1643.os/os_version/archon every event (packages/telemetry/src/events.ts:55-76); no dashboard segments on it.message_send. Server:usageRecords.messagesSent+messageLogs.normalize_cli_name,src/main.rs:6666), not the parent harness (Claude Code vs Cursor vs Codex vs Gemini).Gaps
packages/sdk/has notrack()calls. Can't measure SDK adoption.runInstallCommandinsrc/cli/lib/core-maintenance.tsis silent. No adoption curve.distinct_id = workspace_id(relaycast/packages/server/src/lib/telemetry.ts:18). 1 workspace with 10 humans looks like 10 workspaces with 1 human./console/stats(relaycast/packages/server/src/routes/console.ts) is per-workspace only.workflow_runfires once at completion; no per-step timing or failure data.src/cli/relaycast-mcp.tsuses@relaycast/mcptelemetry which goes to the relaycast PostHog, not relay's.observer-dashboard,site/have no PostHog JS.Set up poorly
origin_clientis always'@relaycast/mcp'(relaycast/packages/mcp/src/telemetry.ts:219) — useless for harness segmentation.relaycast/packages/server/src/lib/logger.ts:166) and event store — OTel logs aren't indexed as events and pollute volume.relay/packages/telemetry/src/events.tsandrelaycast/packages/types/src/telemetry.tsdefine overlapping events independently.Fix plan
P0 — Answer the business questions (this week)
getppid()/ process tree, matchclaude/cursor/codex/gemini-cli/aider/ etc. Addorchestrator_harnesstoCommonPropertiesinpackages/telemetry/src/events.ts:55. Default"unknown"so we can size the long tail.X-Relaycast-Harnessheader on relay → relaycast calls; read it inrelaycast/packages/server/src/lib/serverTelemetry.ts:40and store on every server event.installandupdateevents inrunInstallCommand/ self-update path. ~5 lines.sdk_workflow_runandsdk_method_callevents inpackages/sdk/withsurface=sdk.P0.5 — Extract PostHog keys from source
None;track()no-ops when empty.POSTHOG_KEYfrom a secret:option_env!(\"POSTHOG_KEY\")insrc/telemetry.rs(kill the hardcodedphc_2uDu01GtnLABJpVkWw4ri1OgScLU90aEmXmDjufGdqr)defineinpackages/telemetry/src/client.tsphc_OAqBdey9...default inrelaycast/packages/mcp/src/telemetry.ts:33POSTHOG_KEY_PROD/POSTHOG_KEY_STAGINGas separate GitHub secrets..github/workflows/release.ymlto pass the secret to build steps.PostHog
phc_*keys are write-only and safe to be public — the reasons to extract them are: stopping forks from polluting prod data, enabling staging separation, and quota protection.P1 — Make the data trustworthy (this sprint)
POSTHOG_API_KEYenv at it. Addapp:property everywhere (broker/cli/sdk/relaycast-server/dashboard) so clean separation comes from properties, not from project boundaries. Export historical data from the old project if needed before sunset.distinct_id. Send hashed machine-ID from client + include as property when relaycast receives MCP/HTTP calls. Use PostHog$identify/alias to stitch workspace_id ↔ machine_id ↔ user_id.std::panic::set_hookinsrc/main.rsfires a synchronousbroker_panicevent witherror_classand first-frame symbol (no message — PII-safe).@relay/telemetry-eventsconsumed by both repos, or generate one from the other.P2 — Queryable without PostHog UI
/admin/analyticswithworkspaces_active,agent_spawns_by_cli,messages_by_day,harness_mix,os_mix. Backed by HogQL or daily rollup table.observer-dashboard,site/).workflow_step_runwith step name, duration, success.Repo scope
The repos should stay separate (different release cycles, different deploy targets, different blast radius). The fragmentation problem is in the data, not the code boundary — fixed by unifying the PostHog project + the event schema, not by merging the repos.
Files most likely to change
relay:
src/telemetry.rs— key extraction, harness field, panic hooksrc/main.rs— harness detection, panic hookpackages/telemetry/src/events.ts— schema additions (orchestrator_harness,app)packages/telemetry/src/client.ts— key from build env, no-op when missingpackages/sdk/— new telemetry hookssrc/cli/lib/core-maintenance.ts— install/update events.github/workflows/release.yml— POSTHOG_KEY secret injectionrelaycast:
packages/server/src/lib/serverTelemetry.ts— readX-Relaycast-Harness, store on eventpackages/server/src/lib/telemetry.ts— distinct_id strategypackages/mcp/src/telemetry.ts— kill hardcoded key default, send harness headerpackages/server/src/routes/console.ts(or newadmin.ts) — cross-workspace analytics endpointpackages/server/src/lib/logger.ts— split logs off PostHog