You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
UseJunction does not use a single sync pipeline. Data arrives through four independent paths that all land in UsageDaily (and related inventory tables) with source-aware priority:
Path
Mechanism
Typical source
Who sets it up
Device local sync
Agent polls local tool storage → UUS session upload
device_observed / estimated
Enrolled desktop agent
Cloud provider sync
Control plane polls vendor admin APIs
vendor_verified
Org admin (Integrations)
OTEL push
Claude Code telemetry pushed to control plane
otel_observed
Agent + telemetry endpoint
Manual import
CSV/JSON invoice upload
invoice_imported
Org admin
There are no vendor webhooks for tool usage. Billing webhooks (Lemon Squeezy) reconcile subscription seats only — not per-tool usage.
flowchart TB
subgraph device ["Desktop agent"]
P[providers.All]
C[collect.go]
SE[syncengine/upload.go]
LS[localsync HTTP]
P --> C --> SE
LS --> C
end
subgraph ingest ["Control plane ingest"]
START["/ingest/sync/usage/start"]
CHUNK["/ingest/sync/usage/chunk"]
COMMIT["/ingest/sync/usage/commit"]
OTEL["/otel/v1/metrics"]
WORK["/ingest/work-sessions"]
end
subgraph server ["Server sync services"]
US[usage-sync.ts]
INV[tools / accounts / quotas inventory]
SD[sync-detected.ts]
PS[integrations/sync.ts]
AD[adapters.ts]
end
subgraph storage ["PostgreSQL"]
UD[UsageDaily]
PC[ProviderConnection]
SR[SyncRun]
end
SE --> START --> US
US --> INV --> SD
CHUNK --> US
COMMIT --> UD
OTEL --> UD
WORK -.->|signals, not UsageDaily| UD
CRON["cron/provider-sync"] --> PS --> AD
PS --> PC
PS --> UD
US --> SR
US --> UD
Loading
Catalog tools
The product catalog (apps/admin/lib/tools/catalog.ts) defines six billing surfaces. Each maps to one or more agent provider IDs and optional cloud integrations.
Catalog key
Agent ID(s)
Cloud integration
Primary sync path
chatgpt-codex
codex
OpenAI API Platform (openai/api_platform)
Device local JSONL
claude
claude
Anthropic API Platform + Enterprise (anthropic/api_platform, anthropic/enterprise)
Device local JSONL + OTEL
cursor
cursor
Cursor Teams (cursor/teams)
Device local SQLite + vendor events
antigravity
antigravity
—
Device local SQLite
github-copilot
copilot
GitHub Copilot (github/copilot)
Device local SQLite + org API
opencode
opencode
—
Device local SQLite
The agent also observes tools outside the billing catalog (Continue, Cline, Roo, Ollama, LM Studio). These are device-observed only — no cloud pull adapters exist today.
Once per UTC day (via heartbeat fullUsageRescanDay)
production-deployment.md
UUS delta sync
Usage partitions use grain: date × tool × model × source × repository.
The server stores DeviceUsageFingerprint per partition. On session start, only partitions whose content hash changed since the last sync are requested. Absolute daily totals are replaced — never incremented. Sync-engine (/api/ingest/sync/usage/{start,chunk,commit}) is the only usage ingest path.
Detected plan sync
When the agent reports account identity and quota snapshots, syncDetectedPlansForDevice() (apps/admin/lib/tools/sync-detected.ts) auto-creates or updates subscription seats from vendor-reported plans. See Subscription cycle utilization.
Per-tool: device local sync
ChatGPT / Codex (codex)
Aspect
Detail
Detection
~/.codex/config.toml, auth.json, or codex on PATH
Identity
auth.json access token → account email/plan
Quota
Local probe (probe.ProbeCodexQuota)
Local data
~/.codex/sessions/ and archived_sessions/ JSONL
Parser
Cumulative total_token_usage deltas per session line
Attribution
codex vs codex-work via session_meta.originator
Cache
JSONL watermark snapshot; skip rescan when files unchanged
Source
device_observed with estimated_api cost from rate card
Cloud alt
OpenAI org API — tokens, costs, API keys (see below)
Claude (claude)
Aspect
Detail
Detection
~/.claude/ or ~/.config/claude/, .credentials.json
Claiming: lease-based (claimDueConnections, 5 min lease, up to 5 per cron tick)
What gets synced
Each adapter returns members, seats (where applicable), API keys (OpenAI/Anthropic), and usage rows. The server upserts:
ExternalIdentity — vendor user → developer mapping (email match)
SeatAssignment — seat inventory
ProviderApiKey — API key inventory + developer mapping
UsageDaily — source: vendor_verified, costKind: verified_usage when cost present
Cursor Teams (cursor/teams)
Aspect
Detail
Auth
Admin API key (HTTP Basic)
Validate
GET api.cursor.com/teams/members
Members
Team member list
Usage
POST /teams/daily-usage-data — composer/chat/agent requests, lines, tabs
Spend
POST /teams/spend (paginated) — subscription-cycle spend per member
Seats
One active seat per member
Tool name
cursor
GitHub Copilot (github/copilot)
Aspect
Detail
Auth
GitHub App OAuth install → installation token
Validate
GET /orgs/{org}/copilot/billing
Seats
GET /orgs/{org}/copilot/billing/seats (paginated)
Usage
Per-day GET /orgs/{org}/copilot/metrics/reports/users-1-day → NDJSON download links
Lookback
28 days initial, 3 days incremental
Tool name
github-copilot
OpenAI API Platform (openai/api_platform)
Aspect
Detail
Auth
Organization admin API key (Bearer)
Members
GET /v1/organization/users
Projects + API keys
Projects list → per-project API keys with owner mapping
Usage
GET /v1/organization/usage/completions grouped by user, API key, project, model
Costs
GET /v1/organization/costs (graceful 403/404 skip)
Tool name
openai-api
Not API-synced: ChatGPT/Codex workspace subscriptions (openai/chatgpt_codex_workspace) — manual import only.
Anthropic API Platform (anthropic/api_platform)
Aspect
Detail
Auth
Organization admin API key
Members
GET /v1/organizations/users
API keys
GET /v1/organizations/api_keys
Usage
GET /v1/organizations/usage_report/messages in 31-day chunks
Costs
GET /v1/organizations/cost_report (graceful 403/404 skip)
Grouping
API key, workspace, model
Tool name
anthropic-api
Anthropic Enterprise / Claude Code (anthropic/enterprise)
Aspect
Detail
Auth
Organization admin API key
Usage
GET /v1/organizations/usage_report/claude_code
Fields
Sessions, active time, lines added/removed, commits, PRs
Tool name
claude-code
Members
Inferred from usage rows (no separate users endpoint)
Manual import (invoice_import)
POST /api/integrations/[id]/import accepts CSV/JSON rows → UsageDaily with source: invoice_imported. Used when no API adapter exists or for reconciliation.
Device-observed connections (device_observed)
Presence-only connections with no vendor pull. The enrolled agent is the sole data source.
Path 3: OTEL push (Claude Code)
Aspect
Detail
Endpoint
POST /api/otel/v1/metrics
Auth
Telemetry endpoint token or device bearer token
Format
OTLP JSON metrics
Source
otel_observed
Setup
Agent configures Claude Code to emit OTEL to the control plane URL
OTEL complements — but does not replace — local JSONL scan for Claude. Source priority favors vendor_verified > otel_observed > device_observed for activity; see Usage Accounting Contract.
Path 4: Signals / work extraction (separate pipeline)
Work sessions and app/domain journeys are not part of the usage sync session. They use separate ingest routes and tables: