Skip to main content
Version: 0.2.0 – 0.2.2

Providers

Each provider is a separate worker process in its own repository. Core never imports worker code — the contract is the proto messages + the NATS subjects (see Provider workers). You run only the workers you need.

Enrollment​

In production the Strava worker authenticates to NATS with a one-time enrollment token (NATS auth-callout mints scoped credentials). Create one as an admin. The request is authenticated like any other API call: an admin's session cookie or personal access token.

curl -X POST https://cairn.example/api/admin/worker-enrollments \
-H "Authorization: Bearer cairn_pat_..." \
-H "Content-Type: application/json" \
-d '{"name": "strava-fetcher", "expires_in_hours": 720, "note": "prod Strava"}'
  • name (required): the worker name — lowercase letters, digits and hyphens, no leading or trailing hyphen. The worker's CAIRN_WORKER_NAME must equal it.
  • expires_in_hours (optional): defaults to 8760 (365 days), which is also the cap.
  • note (optional): free text shown in the admin list.

The 201 response carries the enrollment record and the plaintext token, shown once. Pass it to the worker as CAIRN_WORKER_ENROLLMENT_TOKEN. GET /api/admin/worker-enrollments lists enrollments, POST /api/admin/worker-enrollments/{id}/revoke revokes one.

Strava (Go)​

Repo: cairn-provider-strava. Strava is read-only for Cairn. Each user brings their own Strava API app (per-user OAuth) for rate-limit isolation and webhook ownership; users connect their account from the Connections screen.

docker run --rm \
-e CAIRN_NATS_URL=nats://nats:4222 \
-e CAIRN_WORKER_NAME=strava-fetcher \
-e CAIRN_WORKER_ENROLLMENT_TOKEN=... \
ghcr.io/johnnycube/cairn-provider-strava:latest

Only one Strava worker instance should own the webhook subject — set CAIRN_STRAVA_WEBHOOK_VERIFY_TOKEN on exactly one.

VariableDefaultNotes
CAIRN_NATS_URLnats://localhost:4222CAIRN_NATS_USER / CAIRN_NATS_PASSWORD for authenticated servers
CAIRN_WORKER_ENROLLMENT_TOKEN—one-time enrollment token from POST /api/admin/worker-enrollments
CAIRN_WORKER_NAMEstrava-fetchermust equal the enrollment's name
CAIRN_WORKER_INSTANCE_IDgeneratedstable id when you run several instances
CAIRN_STRAVA_WEBHOOK_VERIFY_TOKEN—set on exactly one instance
CAIRN_STRAVA_TOKEN_URLStrava'soverride for testing against a mock

Garmin (Python)​

Repo: cairn-provider-garmin. Garmin has no public activity OAuth API, so the worker uses the garminconnect library (Garth SSO). Per-user credentials are delivered over NATS. The worker does not use an enrollment token; it connects with CAIRN_NATS_USER / CAIRN_NATS_PASSWORD when set, otherwise anonymously.

docker run --rm \
-e CAIRN_NATS_URL=nats://nats:4222 \
ghcr.io/johnnycube/cairn-provider-garmin:latest
VariableDefaultNotes
CAIRN_NATS_URLnats://localhost:4222CAIRN_NATS_USER / CAIRN_NATS_PASSWORD are used when set
CAIRN_WORKER_NAMEgarmin-fetchershared by every instance of the worker
CAIRN_WORKER_INSTANCE_IDgeneratedunique per instance; in Kubernetes set it to the pod name so a restart reuses its presence key
CAIRN_HEARTBEAT_INTERVAL_S20presence heartbeat to the cairn_worker_presence KV
CAIRN_PULL_BATCH4jobs pulled per fetch
CAIRN_GARTH_HOME/tmp/cairn-garthGarth token store, keeps the Garmin session between jobs; mount a volume so MFA accounts are not re-prompted on every restart
CAIRN_GARMIN_EMAIL / ..._PASSWORD—dev fallback only — in production each user's credentials are delivered over NATS
CAIRN_PROTO_PATH<repo>/protolocation of the committed proto stubs

Writing your own provider​

A provider only needs to: register via enrollment, consume cairn.jobs.*.<provider>, and publish cairn.worker.v1.JobResult events. Use the committed proto stubs (Go or Python) as your contract. See Provider workers.