Skip to main content

Provider workers

A provider worker is a standalone process in its own repository. Core does not depend on any worker's code, and a worker does not depend on core's code. The entire contract between them is:

  1. The proto messagescairn.v1 (activities, segments, metrics…) and cairn.worker.v1 (Job, JobResult, WorkerEvent, WorkerManifest).
  2. The NATS subjects — see the pipeline.

This is why the workers can be in different languages: cairn-provider-strava is Go, cairn-provider-garmin is Python. Each commits its own generated proto stubs (Go .pb.go / Python _pb2.py) so it builds with no buf/toolchain dependency.

What a worker does

  • Registers via the enrollment-token flow (NATS auth-callout mints scoped nkey credentials).
  • Consumes cairn.jobs.*.<provider> jobs.
  • Fetches from the provider's API (using per-user tokens delivered over NATS).
  • Publishes cairn.worker.v1.JobResult with WorkerEvents (imported activities, laps, segment efforts, records, metrics).
  • Heartbeats its capability manifest (which data types it can read/backfill).

Write your own provider

Pick a language with protobuf + NATS support, generate the cairn.v1 + cairn.worker.v1 stubs from the proto contract, implement the job loop, and declare a capability manifest. The Go (strava) and Python (garmin) workers are the two reference implementations — the Python one is the smaller, clearer template since it implements the loop from scratch.

The normative checklist of everything a compliant worker MUST implement — required consumers, heartbeats, claim-checked results, failure envelopes, reconcile semantics — is the provider contract, verifiable mechanically with cairn-core's worker-conformance harness.

:::info Standalone by design Earlier, the Strava worker shared Go packages with core via internal/. It was extracted to be fully standalone (its own go.mod, a copied worker SDK + a slim worker-side NATS client), proving the real contract is the wire format, not shared code — exactly like the Python worker. :::