a789495a98
FreeBSD Smoke / FreeBSD Smoke (x86_64) (push) Has been cancelled
CI / Quality Guardrails (push) Has been cancelled
CI / Build & Test (macos-latest) (push) Has been cancelled
CI / Build & Test (ubuntu-latest) (push) Has been cancelled
CI / Build & Test (windows-latest) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / PowerShell Syntax (push) Has been cancelled
CI / Windows Cross-Target Check (Linux) (push) Has been cancelled
285 lines
18 KiB
Markdown
285 lines
18 KiB
Markdown
# jcode Telemetry
|
|
|
|
jcode collects **anonymous, minimal usage statistics** to help understand how many people use jcode, what providers/models are popular, whether onboarding works, which feature families are used, how often sessions succeed, and whether performance/regressions are improving. This data helps prioritize development without collecting prompts or code.
|
|
|
|
Recent telemetry additions also include: coarse onboarding steps, explicit thumbs-up / thumbs-down feedback, build-channel / dev-mode cleanup flags, session/workflow/tool-category summaries, coarse project language buckets, retention helpers like active days in the last 7 / 30 days, workflow cadence fields for session timing and multi-sessioning, privacy-safe per-turn timing/outcome metrics, and schema v5 agent-time / autonomy / pain-attribution metrics.
|
|
|
|
## What We Collect
|
|
|
|
### Install Event (sent once, on first launch)
|
|
|
|
| Field | Example | Purpose |
|
|
|-------|---------|----------|
|
|
| `id` | `a1b2c3d4-...` | Random UUID, not tied to your identity |
|
|
| `event` | `"install"` | Event type |
|
|
| `version` | `"0.6.0"` | jcode version |
|
|
| `os` | `"linux"` | Operating system |
|
|
| `arch` | `"x86_64"` | CPU architecture |
|
|
|
|
### Upgrade Event
|
|
|
|
| Field | Example | Purpose |
|
|
|-------|---------|----------|
|
|
| `id` | `a1b2c3d4-...` | Same random UUID |
|
|
| `event` | `"upgrade"` | Event type |
|
|
| `version` | `"0.9.1"` | Current jcode version |
|
|
| `from_version` | `"0.8.1"` | Previously recorded jcode version |
|
|
| `os` / `arch` | `"linux"` / `"x86_64"` | Environment breakdown |
|
|
|
|
### Auth Success Event
|
|
|
|
| Field | Example | Purpose |
|
|
|-------|---------|----------|
|
|
| `id` | `a1b2c3d4-...` | Same random UUID |
|
|
| `event` | `"auth_success"` | Event type |
|
|
| `auth_provider` | `"claude"` | Which provider/account system was configured |
|
|
| `auth_method` | `"oauth"` | Coarse auth method only |
|
|
| `version` / `os` / `arch` | `"0.9.1"` / `"linux"` / `"x86_64"` | Activation funnel dimensions |
|
|
|
|
### Onboarding Step Event
|
|
|
|
| Field | Example | Purpose |
|
|
|-------|---------|----------|
|
|
| `event` | `"onboarding_step"` | Event type |
|
|
| `step` | `"first_prompt_sent"` | Coarse funnel step |
|
|
| `auth_provider` | `"openai"` | Optional provider dimension for auth steps |
|
|
| `auth_method` | `"oauth"` | Optional auth-method dimension for auth steps |
|
|
| `milestone_elapsed_ms` | `42000` | Rough time from install to milestone |
|
|
|
|
### Feedback Event
|
|
|
|
| Field | Example | Purpose |
|
|
|-------|---------|----------|
|
|
| `event` | `"feedback"` | Event type |
|
|
| `feedback_text` | `"The model switcher is confusing"` | Freeform feedback explicitly submitted with `/feedback ...` |
|
|
| `feedback_rating` | `"up"` / `"down"` | Legacy explicit product sentiment, if present |
|
|
| `feedback_reason` | `"slow"` | Legacy optional coarse reason bucket, if present |
|
|
|
|
### Sponsored Discovery Event
|
|
|
|
One event is sent after each `discover_tools` attempt. A random per-request ID
|
|
is also sent to the discovery API as the `x-jcode-discovery-request-id` header,
|
|
allowing client reliability telemetry to be correlated with server request logs
|
|
without exposing prompts or a persistent telemetry identifier to that service.
|
|
|
|
| Field | Example | Purpose |
|
|
|-------|---------|----------|
|
|
| `event` | `"discovery"` | Event type |
|
|
| `request_id` | `"9a23..."` | Random correlation ID scoped to one request |
|
|
| `phase` | `"browse"` / `"select"` / `"unknown"` | Discovery funnel stage |
|
|
| `category` | `"payments"` | Fixed discovery category, when valid |
|
|
| `selected_tool` | `"agentcard"` | Public catalog tool name in the select phase |
|
|
| `outcome` | `"success"` / `"failure"` | Attempt result |
|
|
| `failure_reason` | `"timeout"` | Allowlisted coarse failure class only |
|
|
| `http_status` | `200` | Discovery service response status, if received |
|
|
| `latency_ms` | `125` | End-to-end client attempt latency |
|
|
| `response_bytes` | `2048` | Response payload size, if received |
|
|
| `result_count` | `3` | Number of browse results, or one for selection |
|
|
| `query_present` / `reason_present` | `true` / `true` | Presence flags only |
|
|
| `custom_endpoint` | `false` | Whether a non-default discovery endpoint was configured |
|
|
|
|
The query text, selection-reason text, endpoint URL, prompts, transcript, file
|
|
paths, and tool setup instructions are **not** included in telemetry. The
|
|
backend rejects unknown phase, outcome, and failure labels rather than storing
|
|
arbitrary strings.
|
|
|
|
### Session Start Event
|
|
|
|
| Field | Example | Purpose |
|
|
|-------|---------|----------|
|
|
| `id` | `a1b2c3d4-...` | Same random UUID |
|
|
| `event` | `"session_start"` | Event type |
|
|
| `version` | `"0.6.0"` | jcode version |
|
|
| `os` | `"linux"` | Operating system |
|
|
| `arch` | `"x86_64"` | CPU architecture |
|
|
| `provider_start` | `"OpenAI"` | Provider when session started |
|
|
| `model_start` | `"gpt-5.4"` | Model when session started |
|
|
| `resumed_session` | `false` | Whether this was a resumed session |
|
|
| `session_start_hour_utc` | `13` | Coarse hour-of-day bucket for workflow timing |
|
|
| `session_start_weekday_utc` | `2` | Weekday bucket for usage cadence |
|
|
| `previous_session_gap_secs` | `3600` | How long since this install's previous session |
|
|
| `sessions_started_24h` / `sessions_started_7d` | `3` / `8` | How bursty a user's workflow is recently |
|
|
| `active_sessions_at_start` | `2` | Concurrent sessions observed including this one |
|
|
| `other_active_sessions_at_start` | `1` | Other sessions already open when this started |
|
|
|
|
### Session End / Crash Event
|
|
|
|
| Field | Example | Purpose |
|
|
|-------|---------|----------|
|
|
| `id` | `a1b2c3d4-...` | Same random UUID |
|
|
| `event` | `"session_end"` / `"session_crash"` | Event type |
|
|
| `version` | `"0.6.0"` | jcode version |
|
|
| `os` | `"linux"` | Operating system |
|
|
| `arch` | `"x86_64"` | CPU architecture |
|
|
| `provider_start` | `"OpenAI"` | Provider when session started |
|
|
| `provider_end` | `"OpenAI"` | Provider when session ended |
|
|
| `model_start` | `"gpt-5.4"` | Model when session started |
|
|
| `model_end` | `"gpt-5.4"` | Model when session ended |
|
|
| `provider_switches` | `0` | How many times you switched providers |
|
|
| `model_switches` | `1` | How many times you switched models |
|
|
| `duration_mins` | `45` | Session length in minutes |
|
|
| `duration_secs` | `2700` | Finer-grained session length |
|
|
| `turns` | `23` | Number of user prompts sent |
|
|
| `had_user_prompt` | `true` | Whether any real prompt was submitted |
|
|
| `had_assistant_response` | `true` | Whether the assistant produced a response |
|
|
| `assistant_responses` | `6` | Number of assistant responses |
|
|
| `first_assistant_response_ms` | `1200` | Time to first assistant response |
|
|
| `first_tool_call_ms` | `900` | Time to first tool invocation |
|
|
| `first_tool_success_ms` | `1500` | Time to first successful tool execution |
|
|
| `first_file_edit_ms` | `2200` | Time to first successful file edit |
|
|
| `first_test_pass_ms` | `4100` | Time to first successful test run |
|
|
| `tool_calls` | `8` | Number of tool executions |
|
|
| `tool_failures` | `1` | Number of tool execution failures |
|
|
| `executed_tool_calls` | `10` | Centralized count of actual registry tool executions |
|
|
| `executed_tool_successes` | `9` | Successful registry tool executions |
|
|
| `executed_tool_failures` | `1` | Failed registry tool executions |
|
|
| `tool_latency_total_ms` | `4200` | Aggregate tool execution latency |
|
|
| `tool_latency_max_ms` | `1800` | Slowest single tool call |
|
|
| `file_write_calls` | `2` | Count of write/edit/patch style tool uses |
|
|
| `tests_run` | `1` | Coarse count of test runs triggered |
|
|
| `tests_passed` | `1` | Coarse count of successful test runs |
|
|
| `input_tokens` / `output_tokens` | `12345` / `678` | Session-level provider-reported token usage totals |
|
|
| `cache_read_input_tokens` / `cache_creation_input_tokens` | `9000` / `1200` | Session-level provider-reported prompt-cache token totals when available |
|
|
| `total_tokens` | `23223` | Sum of input, output, cache-read, and cache-creation tokens |
|
|
| `feature_*_used` | `true/false` | Whether a feature family was used (memory, swarm, web, email, MCP, side panel, goals, selfdev, background, subagents) |
|
|
| `tool_cat_*` | `0..N` | Coarse tool category counts (read/search, write, shell, web, memory, subagent, swarm, email, side-panel, goal, MCP, other) |
|
|
| `command_*_used` | `true/false` | Whether a slash-command family was used in-session |
|
|
| `workflow_*_used` | `true/false` | Whether the session looked like coding, research, testing, background, subagent, or swarm work |
|
|
| `unique_mcp_servers` | `2` | Count of distinct MCP servers touched in-session |
|
|
| `session_success` | `true` | Coarse success proxy based on outcomes like responses, successful tools, tests, or edits |
|
|
| `abandoned_before_response` | `false` | Whether the user engaged but got no successful outcome before ending |
|
|
| `session_stop_reason` | `"tool_error_loop"` | Coarse inferred pain/churn bucket, such as crash, auth blocked, rate limited, no first response, too slow, tool failures, no useful action, or completed successfully |
|
|
| `agent_role` | `"foreground"` / `"subagent"` | Coarse role classification for the session: foreground, background, subagent, or swarm |
|
|
| `parent_session_id` | `"session_..."` | Optional parent session ID for attributing spawned/background/subagent work to the initiating session |
|
|
| `agent_active_ms_total` | `7200000` | Sum of active agent time across finalized turns; two agents active for two hours count as four agent-hours in aggregate |
|
|
| `agent_model_ms_total` / `agent_tool_ms_total` | `5400000` / `1800000` | Approximate active-time split between model/agent thinking and registry tool execution latency |
|
|
| `session_idle_ms_total` | `300000` | Time around turns where the session was open but no agent activity was observed |
|
|
| `time_to_first_agent_action_ms` | `900` | Time from session start to the first assistant response or tool action |
|
|
| `time_to_first_useful_action_ms` | `1500` | Time from session start to the first successful tool/file/test outcome, falling back to first response |
|
|
| `spawned_agent_count` | `3` | Count of background, subagent, and swarm task invocations attributed to the session |
|
|
| `background_task_count` / `background_task_completed_count` | `1` / `1` | Background work started and successfully completed via background/scheduled tool paths |
|
|
| `subagent_task_count` / `subagent_success_count` | `1` / `1` | Subagent task invocations and successful completions |
|
|
| `swarm_task_count` / `swarm_success_count` | `1` / `0` | Swarm/agent-coordination task invocations and successful completions |
|
|
| `user_cancelled_count` | `1` | Urgent interrupt count, used to detect sessions where the user stopped the agent mid-work |
|
|
| `transport_https` | `2` | Number of provider requests sent over HTTPS/SSE |
|
|
| `transport_persistent_ws_fresh` | `1` | Number of fresh persistent WebSocket requests |
|
|
| `transport_persistent_ws_reuse` | `5` | Number of turns that reused an existing persistent WebSocket |
|
|
| `transport_cli_subprocess` | `0` | Number of requests sent through a CLI subprocess transport |
|
|
| `transport_native_http2` | `0` | Number of requests sent through native HTTP/2 transports |
|
|
| `transport_other` | `0` | Number of requests using any other transport |
|
|
| `project_repo_present` | `true` | Whether the working directory looked like a repo |
|
|
| `project_lang_*` | `true/false` | Coarse project-language buckets (Rust, JS/TS, Python, Go, Markdown, mixed) |
|
|
| `days_since_install` | `12` | Rough install age in days |
|
|
| `active_days_7d` / `active_days_30d` | `4` / `9` | How many distinct active days this install had recently |
|
|
| `session_start_hour_utc` / `session_end_hour_utc` | `13` / `14` | Session timing buckets for workflow analysis |
|
|
| `session_start_weekday_utc` / `session_end_weekday_utc` | `2` / `2` | Weekday timing buckets |
|
|
| `previous_session_gap_secs` | `1800` | Time since the previous session on this install |
|
|
| `sessions_started_24h` / `sessions_started_7d` | `5` / `12` | Recent session burstiness |
|
|
| `active_sessions_at_start` / `other_active_sessions_at_start` | `2` / `1` | Concurrent-session snapshot at session start |
|
|
| `max_concurrent_sessions` | `3` | Highest concurrent session count seen during the session |
|
|
| `multi_sessioned` | `true` | Whether the user appeared to be running multiple sessions |
|
|
| `resumed_session` | `false` | Whether this session was resumed |
|
|
| `end_reason` | `"normal_exit"` | Coarse end reason |
|
|
| `errors` | `{"provider_timeout": 0, ...}` | Count of errors by category |
|
|
|
|
### Turn End Event
|
|
|
|
This is a privacy-safe per-prompt summary event. It contains no prompt text, no response text, and no tool inputs/outputs.
|
|
|
|
| Field | Example | Purpose |
|
|
|-------|---------|----------|
|
|
| `event` | `"turn_end"` | Event type |
|
|
| `turn_index` | `4` | Which user turn in the session this was |
|
|
| `turn_started_ms` | `182000` | Time from session start to turn start |
|
|
| `turn_active_duration_ms` | `8200` | Active duration until the last meaningful response/tool activity |
|
|
| `idle_before_turn_ms` / `idle_after_turn_ms` | `45000` / `12000` | Workflow pacing around the turn |
|
|
| `assistant_responses` | `1` | Responses produced during this turn |
|
|
| `first_assistant_response_ms` | `1200` | Time to first response within the turn |
|
|
| `first_tool_call_ms` / `first_tool_success_ms` | `900` / `1500` | Tool timing within the turn |
|
|
| `first_file_edit_ms` / `first_test_pass_ms` | `2200` / `4100` | Useful outcome timing within the turn |
|
|
| `tool_calls` / `tool_failures` | `3` / `1` | Coarse tool activity within the turn |
|
|
| `executed_tool_calls` / `executed_tool_successes` / `executed_tool_failures` | `4` / `3` / `1` | Registry tool execution outcomes |
|
|
| `tool_latency_total_ms` / `tool_latency_max_ms` | `2600` / `1400` | Tool latency footprint within the turn |
|
|
| `file_write_calls` / `tests_run` / `tests_passed` | `1` / `1` / `1` | Outcome proxies for coding workflows |
|
|
| `input_tokens` / `output_tokens` | `1200` / `180` | Turn-level provider-reported token usage totals |
|
|
| `cache_read_input_tokens` / `cache_creation_input_tokens` | `8000` / `600` | Turn-level provider-reported prompt-cache token totals when available |
|
|
| `total_tokens` | `9980` | Sum of input, output, cache-read, and cache-creation tokens for the turn |
|
|
| `feature_*_used` | `true/false` | Which feature families were touched in the turn |
|
|
| `tool_cat_*` | `0..N` | Tool category mix for the turn |
|
|
| `workflow_*_used` | `true/false` | What kind of workflow this turn looked like |
|
|
| `turn_success` | `true` | Whether the turn produced a useful response/outcome |
|
|
| `turn_abandoned` | `false` | Whether the turn appears to have ended without success |
|
|
| `turn_end_reason` | `"next_user_prompt"` | Why the turn was finalized |
|
|
|
|
### Shared Event Metadata
|
|
|
|
Most events also carry a few coarse quality / cleanup fields:
|
|
|
|
| Field | Example | Purpose |
|
|
|-------|---------|----------|
|
|
| `event_id` | `"uuid"` | Deduplication |
|
|
| `session_id` | `"uuid"` | Joins session-scoped events together |
|
|
| `schema_version` | `3` | Forward-compatible parsing |
|
|
| `build_channel` | `"release"` / `"selfdev"` / `"local_build"` | Filter out dev/test usage |
|
|
| `is_git_checkout` | `true/false` | Distinguish source-tree usage from installed usage |
|
|
| `is_ci` | `true/false` | Filter CI noise |
|
|
| `ran_from_cargo` | `true/false` | Filter local dev launches |
|
|
|
|
## What We Do NOT Collect
|
|
|
|
- No file paths, project names, or directory structures
|
|
- No code, prompts, or LLM responses, except text explicitly submitted with `/feedback ...`
|
|
- No tool inputs or tool outputs
|
|
- No MCP server names or configurations
|
|
- No IP addresses (Cloudflare Workers don't log these by default)
|
|
- No personal information of any kind
|
|
- No error messages or stack traces in telemetry (only coarse categories and end reasons)
|
|
- No exact wall-clock timestamps beyond coarse hour-of-day / weekday buckets
|
|
|
|
The UUID is randomly generated on first run and stored at `~/.jcode/telemetry_id`. It is not derived from your machine, username, email, or any identifiable information.
|
|
|
|
## How It Works
|
|
|
|
1. On first launch, jcode generates a random UUID and sends an `install` event
|
|
2. When a session begins, jcode sends a `session_start` event
|
|
3. When a session ends normally, jcode sends a `session_end` event with coarse session metrics
|
|
4. When auth succeeds, jcode sends a coarse `auth_success` event for activation-funnel analysis
|
|
5. When jcode detects a version change, it sends an `upgrade` event
|
|
6. On best-effort crash/signal handling, jcode sends a `session_crash` event
|
|
7. jcode may also send one-off onboarding milestone events and explicit feedback events when triggered
|
|
8. Requests are fire-and-forget HTTP POSTs that don't block normal usage (install/session shutdown have short bounded blocking timeouts)
|
|
9. If a request fails (offline, firewall, etc.), jcode silently continues - no retries, no queuing
|
|
|
|
The telemetry endpoint is a Cloudflare Worker that stores events in a D1 database. The source code for the worker is in [`telemetry-worker/`](./telemetry-worker/).
|
|
|
|
### Schema v5 deployment note
|
|
|
|
Agent-time, autonomy, and pain-attribution fields require the D1 migration in `telemetry-worker/migrations/0008_agent_time_and_churn.sql`. Until that migration is applied, schema v5 clients can still send the new JSON payloads, but the worker will drop unknown columns through dynamic column filtering and dashboard agent-time panels will remain empty or show optional-panel errors. After migration, run/redeploy the telemetry worker and query the dashboard's **Agent time / autonomy** panel.
|
|
|
|
## How to Opt Out
|
|
|
|
Any of these methods will disable telemetry completely:
|
|
|
|
```bash
|
|
# Option 1: Environment variable
|
|
export JCODE_NO_TELEMETRY=1
|
|
|
|
# Option 2: Standard DO_NOT_TRACK (https://consoledonottrack.com/)
|
|
export DO_NOT_TRACK=1
|
|
|
|
# Option 3: File-based opt-out
|
|
touch ~/.jcode/no_telemetry
|
|
```
|
|
|
|
When opted out, zero network requests are made. The telemetry module short-circuits immediately.
|
|
|
|
## Verification
|
|
|
|
This is open source. The entire telemetry implementation is in [`src/telemetry.rs`](./src/telemetry.rs) - you can read exactly what gets sent. There are no other network calls related to telemetry anywhere in the codebase.
|
|
|
|
## Data Retention
|
|
|
|
Telemetry data is used in aggregate only (install count, active users, provider distribution, session success/crash rates, feature-level counts). Individual event records are retained for up to 12 months and then deleted.
|
|
|
|
High-volume raw events are pruned earlier on a nightly schedule, after their aggregate signal has been captured in a compact daily-activity rollup: per-turn and per-session-start records and onboarding-step records are kept for about 30 days, upgrade records for about 60 days, and auth-success records for about 180 days. Session summary records (the per-session aggregate counts described above) are kept for up to 12 months.
|