MainSDK
Search⌘K
Architecture

Telemetry and signals

How MainSDK logs, traces and audits on open standards, what is redacted, and what leaves your app and when.

Building for 0.2

Status Status is where the work is: Planned (in a milestone, not started), Building (tickets in progress), Preview (usable, may change), then the stability it ships at.

Stability The promise an interface ships with.

  • Stable Follows semantic versioning; breaking changes need a new major, 12 months of overlap and a codemod.
  • Beta Usable in production; may change before it becomes stable.
  • Experimental May change or go away; needs an explicit opt-in in main.yaml.
Stability levels
Updated 2026-10-28

Every app gets structured logs, traces and an append-only audit log from its first run, free and local. Redaction happens in your process before anything is written or exported. Nothing reaches MainSDK Cloud until you log in and opt in.

Open standards

StandardUsed for
OpenTelemetry logs data modelEvery log record: severity, body, attributes, resource
OpenTelemetry semantic conventionsWhere it happened (code.function.name, code.file.path, code.line.number) and what failed (exception.*)
W3C Trace Contexttraceparent links an error to the request, job and change that caused it
RFC 9457 problem detailsEvery API error, plus our code, fix, retryable, trace_id and rule
RFC 3339, UTCEvery timestamp
OCSFAudit and security events, read as-is by security tools

Event ids are UUIDv7.

Where telemetry goes

flowchart LR
  app["Your app<br/>log · spans · decisions · audit"] --> red["Redaction<br/>in process"]
  red --> term["terminal<br/>default"]
  red --> local[(".mainsdk/events/<br/>7 days, git-ignored")]
  red --> buf["Bounded buffer<br/>async, never blocks"]
  buf --> otel["Your OTLP endpoint<br/>Datadog, Grafana, Honeycomb …"]
  buf -. "only after mainsdk login<br/>and opt-in (phase 2)" .-> cloud["MainSDK Cloud<br/>your region"]
Diagram
main.yaml
telemetry:
  to: [terminal, otel, mainsdk]     # any mix; default [terminal]
  otel: { endpoint: https://otel.pinecart.dev:4318, headers: { authorization: secret:OTEL_TOKEN } }
  sample: 0.2                       # traces only
  budget: 2M                        # events a month sent to MainSDK Cloud

MAINSDK_TELEMETRY=1 is the same as adding mainsdk to telemetry.to, and it still needs mainsdk login. Without login, no connection is made to any MainSDK host and the CLI says log in to send telemetry. Logout stops sending before the next batch.

What is redacted, before anything leaves

  • Labelled values: fields labelled personal, sensitive, child or phi become [redacted:personal] and so on. pan is never stored at all.
  • Secrets: anything resolved from a secret: reference, and known key formats such as msk_live_ and msk_test_.
  • Never collected by default: request and response bodies, cookies, and the authorization, cookie and set-cookie headers.
  • User ids: pseudonymised with a keyed hash per project before export.
  • IP addresses: trimmed, IPv4 to /24 and IPv6 to /48. 203.0.113.77 is exported as 203.0.113.0.

The telemetry contract

telemetry@1 lists every field we collect, its purpose and its redaction rule, published as JSON Schema. A field not in the contract is not exported: the exporter drops it and warns locally with MAIN-LOG-0005.

Sampling never touches enforcement

sample applies to traces only. Errors, policy decisions and audit records are never sampled. Over a budget, we sample what we store, never what we enforce.

The audit log

flowchart LR
  r1["record n-1<br/>hash h1"] --> r2["record n<br/>prev: h1, hash h2"] --> r3["record n+1<br/>prev: h2, hash h3"]
Diagram
  • Append-only and tamper-evident: each record carries the hash of the previous one. log.audit.verify() detects any edit, deletion or reorder and returns where the chain broke.
  • Records are OCSF. Every policy decision is written with its policy version, for example as an OCSF Authorization event with actor, action, resource and decision.
  • Never dropped silently: if its sink is unavailable, it buffers to local disk and reports MAIN-LOG-0010.

Still open: where the audit log lives in production by default, and whether chain checkpoints are signed, and with which key.

When the exporter is down

Export is asynchronous, buffered and bounded. When the endpoint is unreachable, telemetry is dropped with a telemetry.dropped counter and requests keep their speed. See request lifecycle.

Security signals

WhatPhase
Hosted search, retention and mainsdk logs --follow --env prod from our endpoint2
AI traces in the OpenTelemetry GenAI conventions2
SIEM streaming per customer organisation2
Fleet Defend: signals from inside every app to the SIEM in OCSF, enriched with app, owner, environment and data labels; detections as Sigma rules mapped to MITRE ATT&CK4 (Fleet)

Fleet Defend signals come from the places MainSDK already decides: the sign-in check, the owner-scope check, the rate limiter, the outbound call, the AI call and the agent action. For example, an outbound call to an unknown host that was refused maps to T1041 and T1195. Because the SDK reports what it decided, not raw traffic, the signals are few.

Next

Was this page helpful?

↑↓ moveEnter openEsc close

Not decided yet