Skip to content

Telemetry and logs API

Analytics, telemetry, log, MCP, and scheduled task endpoints.

Back to HTTP API overview.

Requires analytics permission.

Aggregate request counts, memory operation totals, and per-endpoint hit counts collected since daemon start.

Response — collector-defined usage summary object.

Recent error events from the analytics collector.

Query parameters

Parameter Description
stage Filter by pipeline stage (e.g., mutation)
since ISO timestamp — only errors after this time
limit Max errors to return

Response

{
"errors": [ { "stage": "mutation", "message": "...", "at": "..." } ],
"summary": { "total": 5, "byStage": { "mutation": 5 } }
}

Latency histograms for key operation groups: remember, recall, mutate.

Response — collector-defined latency object with p50/p95/p99 per group.

Recent structured log entries. Same data as GET /api/logs but namespaced under analytics.

Query parameters

Parameter Description
limit Max log entries (default: 100)
level debug, info, warn, or error
category Filter by log category (e.g., memory, pipeline)
since ISO timestamp lower bound

Response

{ "logs": [...], "count": 47 }

Combined view of mutation diagnostics and recent mutation errors. Useful for auditing data integrity.

Response

{
"mutation": { ... },
"recentErrors": [ ... ],
"errorSummary": { ... }
}

Session continuity scores over time. Tracks how well memory injection maintains context across sessions.

Query parameters

Parameter Type Description
project string Filter by project path (optional)
limit integer Max scores to return (default: 50)

Response

{
"scores": [
{
"id": "uuid",
"session_key": "abc-123",
"project": "/path/to/project",
"harness": "claude-code",
"score": 0.85,
"memories_recalled": 12,
"memories_used": 8,
"novel_context_count": 3,
"reasoning": "...",
"created_at": "2026-02-21T10:00:00.000Z"
}
],
"summary": {
"count": 50,
"average": 0.78,
"trend": 0.05,
"latest": 0.85
}
}

Latest continuity score per project. Returns one row per project, ordered by most recent.

Response

{
"scores": [
{ "project": "/path/to/project", "score": 0.85, "created_at": "2026-02-21T10:00:00.000Z" }
]
}

Telemetry endpoints expose local event data collected by the daemon. The standard event stream excludes prompt text, memory content, credentials, and raw session keys. Recall QA telemetry is a separate local-only ledger that intentionally stores query text and result snapshots for manual review, so it requires analytics permission and is never forwarded to external telemetry sinks.

Query raw telemetry events.

Query parameters

Parameter Type Description
event string Filter by event type (e.g., llm.generate)
since string ISO timestamp lower bound
until string ISO timestamp upper bound
limit integer Max events (default: 100, clamped to 1-10000)

Response

{
"events": [
{
"event": "llm.generate",
"properties": { "inputTokens": 500, "outputTokens": 200, "durationMs": 1200 },
"timestamp": "2026-02-21T10:00:00.000Z"
}
],
"enabled": true
}

Returns a bounded, payload-free summary of the daemon collector. This route requires analytics permission and is also the dashboard’s source for distinguishing daemon silence from a delivery outage.

{
"enabled": true,
"status": "degraded",
"deliveryConfigured": true,
"bufferedEventCount": 0,
"queuedUnsentEventCount": 12,
"oldestUnsentEventAgeSec": 184,
"lastDaemonEventAgeSec": 9,
"lastSuccessfulDeliveryAgeSec": 902,
"recentDeliverySuccessCount": 31,
"recentDeliveryFailureCount": 3,
"consecutiveFailures": 3,
"backoffActive": true,
"droppedEventCount": 0,
"flushIntervalMs": 300000
}

status is local-only when no remote sink is configured, healthy when delivery is current, and degraded when delivery is failing or an unsent queue is aging. enabled: false means the daemon collector is disabled. Age values are seconds and may be null when no event or successful delivery has ever been observed. The response never includes install identifiers, endpoint credentials, paths, event properties, response bodies, or user identity.

Inference emits additional local-first telemetry events:

  • inference.route
  • inference.execute
  • inference.stream
  • inference.fallback

These events intentionally exclude raw prompts, response text, secrets, credentials, and session references.

Recall emits recall.performed at the shared search boundary. Its properties are counts and metadata only: surface, type when classification is reliable (semantic, keyword, temporal, or graph), results, latencyMs, and truncated. Retrieval-outcome telemetry separately emits recall.attempted and recall.outcome. Those events use only bounded surface, result-state, delivery-state, and count fields: explicit_api, tool_call, prompt_injection, dashboard, or other; empty, non_empty, truncated, or error; and returned, injected, consumed, or not_delivered. A prompt-submit admission skip may also include the fixed reason skipped_low_signal. They never include query text, prompt text, memory content, identifiers, citations, or feedback prose.

Source indexing emits bounded source.lifecycle summaries. The sourceClass taxonomy is fixed (transcript, document, repository, note_vault, browser, other); lifecycle phases cover connection, indexing, readiness, first recall, and recurring freshness. Counts, source size, duration, and freshness lag are bucketed or capped, and operation summaries replace per-document events. Source names, identifiers, paths, URLs, titles, error messages, and content are never included.

Aggregated telemetry statistics since daemon start or since a given timestamp.

Query parameters

Parameter Type Description
since string ISO timestamp lower bound (optional)

Response

{
"enabled": true,
"totalEvents": 500,
"llm": {
"calls": 120,
"errors": 2,
"totalInputTokens": 60000,
"totalOutputTokens": 24000,
"totalCost": 0.45,
"p50": 800,
"p95": 2400
},
"embedding": {
"calls": 480,
"totalTokens": 1200000,
"cost": 0.024,
"bySource": [
{ "source": "recall", "tokens": 900000, "cost": 0.018 },
{ "source": "memory-capture", "tokens": 300000, "cost": 0.006 }
]
},
"dreaming": {
"calls": 12,
"tokensInput": 180000,
"tokensOutput": 24000,
"tokensCacheRead": 60000,
"tokensCacheWrite": 0,
"cacheAccounting": {
"cacheRequests": 12,
"cacheHits": 6,
"cacheMisses": 2,
"cacheUnknown": 4,
"cacheWrites": 2,
"cacheAccountingAvailablePasses": 8,
"cacheAccountingUnavailablePasses": 4,
"hitRate": 0.75,
"byProvider": [
{ "provider": "anthropic", "cacheRequests": 12, "cacheHits": 6, "cacheMisses": 2, "cacheUnknown": 4, "cacheWrites": 2, "cacheAccountingAvailablePasses": 8, "cacheAccountingUnavailablePasses": 0, "hitRate": 0.75 }
],
"byModel": [
{ "model": "claude-test", "cacheRequests": 12, "cacheHits": 6, "cacheMisses": 2, "cacheUnknown": 4, "cacheWrites": 2, "cacheAccountingAvailablePasses": 8, "cacheAccountingUnavailablePasses": 0, "hitRate": 0.75 }
],
"byWorkloadClass": [
{ "workloadClass": "memory_extraction", "cacheRequests": 12, "cacheHits": 6, "cacheMisses": 2, "cacheUnknown": 4, "cacheWrites": 2, "cacheAccountingAvailablePasses": 8, "cacheAccountingUnavailablePasses": 0, "hitRate": 0.75 }
]
},
"cost": 0.45,
"artifactsConsidered": 36,
"memoriesCreated": 8,
"memoriesUpdated": 0,
"memoriesSuperseded": 3,
"memoriesRetired": 1,
"claimsChanged": 11,
"relationshipsChanged": 4,
"provenanceLinksChanged": 14,
"toolCalls": 96,
"durationMs": 182000,
"outcomes": [
{ "outcome": "completed", "calls": 8 },
{ "outcome": "no-op", "calls": 4 }
],
"outcomeCodes": [
{ "code": "completed", "calls": 8 },
{ "code": "no_work", "calls": 4 }
],
"byMode": [
{
"mode": "incremental",
"calls": 12,
"tokensInput": 180000,
"tokensOutput": 24000,
"cost": 0.45,
"cacheRequests": 12,
"cacheHits": 6,
"cacheMisses": 2,
"cacheUnknown": 4,
"cacheWrites": 2,
"cacheAccountingAvailablePasses": 8,
"cacheAccountingUnavailablePasses": 4,
"hitRate": 0.75,
"artifactsConsidered": 36,
"memoriesCreated": 8,
"memoriesUpdated": 0,
"memoriesSuperseded": 3,
"memoriesRetired": 1,
"claimsChanged": 11,
"relationshipsChanged": 4,
"provenanceLinksChanged": 14,
"toolCalls": 96,
"durationMs": 182000
}
]
},
"sessions": {
"ended": 18,
"tokensInput": 240000,
"tokensOutput": 36000,
"tokensCacheRead": 60000,
"tokensCacheWrite": 0,
"cost": 0.924
},
"inference": {
"routes": 40,
"executes": 18,
"streams": 4,
"errors": 3,
"cancelled": 1,
"fallbacks": 5,
"p50": 120,
"p95": 900
},
"recall": {
"calls": 80,
"outcomes": {
"attempted": 100,
"returned": 70,
"delivered": 20,
"bySurface": [
{ "surface": "explicit_api", "attempted": 70, "returned": 50, "delivered": 0 },
{ "surface": "prompt_injection", "attempted": 30, "returned": 0, "delivered": 20 }
]
},
"p50": 42,
"p95": 310,
"byType": [
{ "type": "keyword", "calls": 30 },
{ "type": "semantic", "calls": 50 }
]
},
"pipelineErrors": 3,
"pipelineErrorsByStage": { "extraction": 1, "decision": 1, "embedding": 1 },
"pipelineErrorsByCode": {
"EXTRACTION_PARSE_FAIL": 1,
"DECISION_TIMEOUT": 1,
"EMBEDDING_PROVIDER_DOWN": 1
},
"pipelineOperations": {
"total": 12,
"incidents": 2,
"classes": {
"indexing": {
"operations": 8,
"accepted": 42,
"skipped": 3,
"retried": 5,
"failed": 2,
"durationMs": 18400,
"queueAgeMs": 3200,
"outcomes": { "completed": 6, "partial": 2 },
"causes": { "context_limit": 1, "provider_unavailable": 1 },
"durationBuckets": { "1-9s": 8 },
"queueAgeBuckets": { "1-9s": 8 }
}
}
}
}

Each llm, embedding, dreaming, and sessions object also contains a coverage object keyed by provider_reported, locally_estimated, configured_rate, local_zero_cost, unavailable, and mixed. Each bucket contains calls, tokens, and cost totals. The mixed bucket is used for session summaries that combine more than one accounting provenance; it is not missing accounting.

dreaming.cacheAccounting contains request-level counters only for passes where an inference provider reported cache fields. cacheAccountingUnavailablePasses counts passes without that provider coverage; their counters are not inferred as zero. A reported zero cache read/write value is an unknown request, not a miss. hitRate is cacheHits / (cacheHits + cacheMisses), so unknown requests are outside the denominator. byProvider, byModel, and byWorkloadClass use the same totals and availability fields; byMode exposes the same cache totals for each Dreaming mode.

Embedding cost values are USD. The sessions block is a derived view over matching usage events and should not be added to event-level cost totals. The session.end event carries the same collector-derived totals, keyed by a truncated hash of the session key rather than the raw key.

pipelineErrors and its stage/code maps count raw failed attempts and remain backward-compatible. pipelineOperations is the bounded primary reliability view: it reports one logical operation summary per class (indexing, memory_capture, recall, dreaming, extraction, or other), including accepted, skipped, retried, and failed counts, duration and queue-age buckets, outcomes, and normalized cause families. Its incidents count includes failed or partial operations, so a large source cannot inflate the primary incident count by chunk count or retry count. Operation summaries contain no source identifiers, hashes, paths, provider messages, stacks, or raw input.

Export raw telemetry events as newline-delimited JSON (NDJSON).

Query parameters

Parameter Type Description
since string ISO timestamp lower bound (optional)
limit integer Max events (default: 10000, clamped to 1-100000)

ResponseContent-Type: application/x-ndjson. Each line is a JSON-serialized telemetry event. Returns 404 if telemetry is not enabled.

Query local recall QA telemetry captured when telemetry.memorySearchQaEnabled: true.

Query parameters

Parameter Type Description
agent_id string Filter by agent id
session_key string Filter by session key
route string Filter by recall route
since string ISO timestamp lower bound
until string ISO timestamp upper bound
no_hits boolean Filter to no-hit or hit-producing searches
limit integer Max rows, clamped to 1-500, default 100
offset integer Pagination offset, default 0

Response

{
"items": [
{
"id": "search-event-id",
"created_at": "2026-05-06T21:22:00.000Z",
"route": "POST /api/memory/recall",
"agent_id": "ant",
"session_key": "session-1",
"query": "what did we decide about recall qa",
"filters": { "limit": 10, "readPolicy": "isolated" },
"result_count": 1,
"top_score": 0.91,
"no_hits": false,
"duration_ms": 12.34,
"results": [
{
"rank": 1,
"id": "memory-id",
"score": 0.91,
"source": "memory",
"content": "Captured recall result content..."
}
]
}
],
"count": 1
}

Export local recall QA telemetry as newline-delimited JSON. Supports the same filters as GET /api/telemetry/memory-search; limit is clamped to 1-10000.

Return recent structured log entries from the in-memory log buffer.

Query parameters

Parameter Description
limit Max entries (default: 100)
level Minimum level: debug, info, warn, error
category Filter by category string
since ISO timestamp — only logs after this time

Response

{ "logs": [...], "count": 100 }

Server-Sent Events stream of live log output. Each event is a JSON-serialized LogEntry. The connection sends an initial {"type":"connected"} event and then emits entries in real time as the daemon generates them.

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

Each SSE event:

data: {"level":"info","category":"memory","message":"Memory saved","at":"..."}

The stream stays open until the client disconnects.

Model Context Protocol endpoint using Streamable HTTP transport (stateless). Supports POST (send messages), GET (SSE stream), and DELETE (session teardown).

Exposes memory/session tools: memory_search, session_search, memory_store, memory_get, memory_list, memory_modify, memory_forget. See the MCP server reference for full tool documentation.

POST /mcp — Send MCP JSON-RPC messages. Returns JSON or SSE stream.

MCP admission is bounded to 8 in-flight requests. An admitted request whose JSON body exceeds 512 KiB returns HTTP 413; a request arriving at a saturated admission cap returns HTTP 503 with a JSON-RPC error and should be retried. Marketplace proxy refreshes are single-flight per authorization and scope context for 30 seconds.

GET /mcp — Open an SSE stream for server-initiated notifications.

DELETE /mcp — Terminate MCP session (no-op in stateless mode).

List all scheduled tasks with their last run status.

Response

{
"tasks": [{
"id": "uuid",
"name": "Review open PRs",
"prompt": "Review all open pull requests",
"cron_expression": "0 9 * * *",
"harness": "claude-code",
"working_directory": "/path/to/project",
"enabled": 1,
"last_run_at": "2026-02-23T09:00:00Z",
"next_run_at": "2026-02-24T09:00:00Z",
"last_run_status": "completed",
"last_run_exit_code": 0
}],
"presets": [
{"label": "Every 15 min", "expression": "*/15 * * * *"},
{"label": "Hourly", "expression": "0 * * * *"},
{"label": "Daily 9am", "expression": "0 9 * * *"},
{"label": "Weekly Mon 9am", "expression": "0 9 * * 1"}
]
}

Create a new scheduled task.

Request body

{
"name": "Review open PRs",
"prompt": "Review all open pull requests and summarize findings",
"cronExpression": "0 9 * * *",
"harness": "claude-code",
"workingDirectory": "/path/to/project"
}

Response (201)

{"id": "uuid", "nextRunAt": "2026-02-24T09:00:00Z"}

Get a single task with its 20 most recent runs.

Update a task’s name, prompt, cron, harness, working directory, or enabled state.

Delete a task and all its run history (cascade).

Trigger an immediate manual run. Returns 202 with runId. Returns 409 if the task already has a running execution. Skill usage analytics are attributed using non-breaking task scope hints when available.

Paginated run history. Supports limit and offset query parameters.

Server-Sent Events stream of live task output. Replays buffered output on connect, then streams new events in real time. Sends keepalive comments every 15 seconds.

Event types

Type Description
connected Initial connection confirmation
run-started A run has begun (includes runId)
run-output Stdout or stderr chunk (stream field)
run-completed Run finished (includes exitCode)
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive