Activity and customer export API
Pilot v1; not a stable SDK. Reviewed 22 September 2026.
ophiolite.activity/1 includes event ID, project ID, kind, authenticated actor ID,
run ID, optional diagnostic trace ID, server UTC recorded time, evidence category,
coverage profile and typed event data. Server kinds are operation.requested,
operation.completed, operation.failed and operation.unconfirmed. Exact
references use project, asset and revision; a run ID is distinct from a revision.
Completed scalar events include parameters/unit, lineage and runtime measurements.
CPU seconds describe calculation process time. Peak RSS is the process lifetime
high-water mark, not per-operation allocation. No raw arrays appear in the event.
consumer.applied is explicitly client-reported. Its data includes exact reference,
binding ID, application/connector versions, follow/pin/copy and phase timings.
Profile /1 retains its historical inclusive apply_ms, including notification
waiting. Profile /2 uses optional timings; missing timings mean unavailable,
not zero. Duplicate IDs with different content fail. Identical heartbeats update the
last-seen row without appending another event. The server verifies current project
access and that the exact revision is available; it does not trust a caller-supplied
actor identity. Default retained consumer-event limit per project: 10,000,
configurable from 100 to 1,000,000.
Read a page
Section titled “Read a page”Browser POST /api/activity/list requires the existing session, allowed origin and
CSRF header. /api/activity/export accepts the same body and returns a page of
NDJSON with X-Next-Cursor. The list response contains stream ID, events,
next cursor, up to 200 recent consumer reports and declared coverage.
{"project_id":"YOUR_PROJECT","after":0,"limit":200}OAuth connectors use POST /api/v1/connector/activity/list; project-read API
delegates use POST /api/v1/projects/{project_id}/activity. Both recheck access.
Machine delegates do not fall back to browser cookies. Continue with next_cursor
until an empty page. Cursors are monotonically increasing within a journal stream;
gaps are normal and do not imply missing project events. A replacement journal
gets a different stream ID and requires explicit export restart.
Record a QGIS observation
Section titled “Record a QGIS observation”POST /api/v1/connector/activity/report with the connector bearer credential:
{ "reference":{"project_id":"YOUR_PROJECT","asset_id":"YOUR_ASSET","revision":"7"}, "binding_id":"a083f048-98eb-4b65-984b-b48139b371d0", "event_id":"333a127f-e938-4fe4-9d57-21298f4ae681", "profile":"qgis-scalar-consumer/2", "application_version":"4.2.2", "connector_version":"0.4.0", "mode":"follow", "timings":{"notification_wait_ms":15000,"download_ms":200,"prepare_ms":10,"gui_apply_ms":35}}This illustrative payload does not grant publication permission or certify human inspection. Tokens are never embedded in events. Capability profiles for additional hosts require implementation and host qualification before claiming support.
Export destinations
Section titled “Export destinations”Platform provides python -m project_gateway.activity_export --help. A token file,
or workload configuration, project, checkpoint and JSONL directory or PostgreSQL
destination are required.
SQL connection credentials come from OPHIOLITE_EXPORT_POSTGRES_DSN, kept outside
the browser and repository. Export commits to the destination before advancing the
checkpoint. SQL uses (stream_id,event_id) as its idempotency key and stores the
complete JSONB event. JSONL uses one atomically replaced segment per event. Do not
share a checkpoint between concurrent exporters.
Watch mode reloads the token file and pauses on failure. Current five-minute API delegates require renewal and remain tied to their browser session. Revocation prevents future reads, not access to already exported copies. Customer SQL password rotation does not alter checkpoint identity.
The integration repository’s deployment/observability/ includes tested local
Jaeger/Collector/PostgreSQL containers and a configurable customer OTLP exporter.
These are single-node examples, not production HA, SSO, backups or retention
qualification. Optional diagnostic queues can lose spans; durable scientific
lineage and operation journals are independent of tracing.
Renewable workload identity
Section titled “Renewable workload identity”For unattended export, IT provisions a confidential OIDC client with the Workspace
audience and client-credentials grant. Its exact issuer/subject must map to a
native project viewer with no compute grant. Gateway workload_clients maps that
client ID to {"subject":"EXACT_SUBJECT","projects":["PROJECT_ID"]}. This restricts
access; it does not replace native project permissions. Only the activity read
endpoint accepts these workload credentials. Each request checks introspection,
issuer, audience, client, subject, expiry, identity state and project access.
Use --workload-config /private/workload.json instead of --token-file. The mode-0600
JSON file contains exactly issuer, client_id, client_secret. The exporter
renews in memory before expiry and reloads rotated configuration. It requires no
browser. Disable the mapped identity or revoke its project grant to stop reads.
The deployment examples include a supervised service and customer-owned SQL sink.
Retention, sampling and delivery links
Section titled “Retention, sampling and delivery links”OPHIOLITE_CONSUMER_RETENTION_DAYS defaults to 0 (no pruning). Positive days prune
old delivery observations and presence on project access, at most once a minute.
Inactive projects are pruned when accessed again. Minimal identity/fingerprint
tombstones remain to reject altered replays. Scientific operation events and
publication intents are never pruned by this option.
Pages expose pruned_through and consumer_retention_days. A newly encountered
export gap requires --accept-retained-history; it cannot restore deleted events.
Export regularly before retention expires. Customer sink retention is independent.
OPHIOLITE_TRACE_SAMPLE_RATIO (0–1, default 1) controls parent-based diagnostic
sampling. No trace ID is advertised for an unsampled operation; durable events
remain. Jaeger’s example OPHIOLITE_TRACE_TTL defaults to 168h. Viewer links use
OPHIOLITE_TRACE_VIEWER_URL, reachable from the user’s browser and separately
secured by customer IT.
A new consumer report has its own trace linked to the producing trace where known.
Client phase durations are attributes, not backdated server spans. Server-derived
publication_trace_id, publication_recorded_at, and server_receipt_lag_ms
correlate the report with the committed revision. Lag includes waiting/reporting;
it is not screen latency. Optional W3C trace_context is correlation metadata,
never a credential. Repeated heartbeats create no additional diagnostic traces.
