



  

<!DOCTYPE html>
<html
  lang="en"
  
  data-color-mode="auto" data-light-theme="light" data-dark-theme="dark"
  data-a11y-animated-images="system" data-a11y-link-underlines="true"
  
  >




  <head>
    <meta charset="utf-8">
  <link rel="dns-prefetch" href="https://github.githubassets.com">
  <link rel="dns-prefetch" href="https://avatars.githubusercontent.com">
  <link rel="dns-prefetch" href="https://github-cloud.s3.amazonaws.com">
  <link rel="dns-prefetch" href="https://user-images.githubusercontent.com/">
  <link rel="preconnect" href="https://github.githubassets.com" crossorigin>
  <link rel="preconnect" href="https://avatars.githubusercontent.com">

<script type="importmap">{"imports":{"react":"https://github.githubassets.com/assets/react-e27d1b3e03961e68.js","react-dom":"https://github.githubassets.com/assets/react-dom-e5fd46a22d5c4058.js","react-dom/client":"https://github.githubassets.com/assets/react-dom-client-1b4a3ee065998cea.js","react-is":"https://github.githubassets.com/assets/react-is-e0b593954b4706d8.js","react-reconciler":"https://github.githubassets.com/assets/react-reconciler-8e99e505c4429605.js","react/compiler-runtime":"https://github.githubassets.com/assets/react-compiler-runtime-4610bd6d3de9c049.js","react/jsx-dev-runtime":"https://github.githubassets.com/assets/react-jsx-dev-runtime-ea55d68667d559e5.js","react/jsx-runtime":"https://github.githubassets.com/assets/react-jsx-runtime-4915cb0f5b3aff04.js","scheduler":"https://github.githubassets.com/assets/scheduler-58b860b049ca307c.js"}}</script>
<meta name="react-profiling" content="0" data-turbo-transient="true" />
<meta name="react-import-map" content="react,react-dom,react-dom/client,react-dom/profiling,react-is,react-reconciler,react/compiler-runtime,react/jsx-dev-runtime,react/jsx-runtime,scheduler@777f63f87cd0" data-turbo-track="reload" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-e27d1b3e03961e68.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-compiler-runtime-4610bd6d3de9c049.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/scheduler-58b860b049ca307c.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-dom-e5fd46a22d5c4058.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-dom-client-1b4a3ee065998cea.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-is-e0b593954b4706d8.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-jsx-runtime-4915cb0f5b3aff04.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-reconciler-8e99e505c4429605.js" />

  


  <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/light-5c4e9fc574bf49f3.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/light_high_contrast-fb37c309e0603a69.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/dark-afff6c53aef9b9d1.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/dark_high_contrast-c409873d7987dffa.css" /><link data-color-theme="light" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light-5c4e9fc574bf49f3.css" /><link data-color-theme="light_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_high_contrast-fb37c309e0603a69.css" /><link data-color-theme="light_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_colorblind-0f910d8806d5761b.css" /><link data-color-theme="light_colorblind_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_colorblind_high_contrast-a7abd4d4c49ac593.css" /><link data-color-theme="light_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_tritanopia-5fc4c4a9cb41e596.css" /><link data-color-theme="light_tritanopia_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_tritanopia_high_contrast-ed0cee9214dedabd.css" /><link data-color-theme="dark" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark-afff6c53aef9b9d1.css" /><link data-color-theme="dark_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_high_contrast-c409873d7987dffa.css" /><link data-color-theme="dark_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_colorblind-78a2491d538dab5a.css" /><link data-color-theme="dark_colorblind_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_colorblind_high_contrast-c26b63d7c532d0a2.css" /><link data-color-theme="dark_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_tritanopia-a6f60cea68c08405.css" /><link data-color-theme="dark_tritanopia_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_tritanopia_high_contrast-f66faf28b2ea18b6.css" /><link data-color-theme="dark_dimmed" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_dimmed-6701f6218c53cf5b.css" /><link data-color-theme="dark_dimmed_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_dimmed_high_contrast-7037fa46ae124d97.css" />

  <style type="text/css">
    :root {
      --tab-size-preference: 4;
    }

    pre, code {
      tab-size: var(--tab-size-preference);
    }
  </style>

    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-primitives-97df7784617ce1ea.css" />
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-9be9fe6313f476af.css" />
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/global-62747e27e61258dc.css" />
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/github-b04ca6fccda778e2.css" />
  <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/repository-72bd7d974b5ac1cc.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/code-4c5c0895f723f870.css" />

  

  <script type="application/json" id="client-env">{"locale":"en","featureFlags":["actions_caches_react_shell","actions_enable_background_steps","actions_new_hosted_runner_image_select_sizes_and_versions","actions_runners_react_shell","agent_author_search_expansion","agent_author_search_expansion_ui_pulls","alternate_user_config_repo","async_conversion_coverage_enabled","billing_billable_licenses_cost_center_bucket_fix","billing_budget_expiration","billing_cost_center_list_assigned_resources","billing_discount_threshold_notification","code_quality_enablement_banner_targeting","code_quality_remove_preview","code_view_raf_sticky_lines","codespaces_prebuild_region_target_update","coding_agent_third_party_model_ui","copilot_agent_snippy","copilot_ahp_tool_call_timing","copilot_api_agentic_issue_marshal_yaml","copilot_automation_repo_mcp_servers","copilot_automations_pagination","copilot_base_model_policy_row","copilot_chat_auto_mode_v2","copilot_chat_clear_model_selection_for_default_change","copilot_chat_early_task_provisioning","copilot_chat_persist_session_drafts","copilot_chat_vision_dotcom_chat_ga_gate","copilot_css_textarea_autosize","copilot_custom_copilots","copilot_custom_copilots_feature_preview","copilot_duplicate_thread","copilot_extensions_removal_on_marketplace","copilot_fix_failed_workflows_all_skus","copilot_hide_hovercard","copilot_immersive_task_hyperlinking","copilot_mc_cli_resume_any_users_task","copilot_mission_control_agent_merge_fix_ci","copilot_mission_control_agent_merge_resolve_conflicts","copilot_mission_control_awps_batching","copilot_mission_control_early_stop","copilot_mission_control_managed_sandbox_environments","copilot_mission_control_needs_attention","copilot_mission_control_reasoning_effort","copilot_mission_control_sandbox_remote_bypass","copilot_mission_control_task_alive_updates","copilot_mission_control_task_sharing","copilot_org_policy_page_focus_mode","copilot_share_active_subthread","copilot_spaces_ga","copilot_spaces_individual_policies_ga","copilot_swe_agent_authorization_status_ui","copilot_swe_agent_automation_resource_scoped_writes","copilot_swe_agent_discussion_comment_trigger","copilot_swe_agent_discussion_opened_trigger","copilot_swe_agent_discussion_updated_trigger","copilot_swe_agent_hide_model_picker_if_only_auto","copilot_swe_agent_issue_assigned_trigger","copilot_swe_agent_issue_comment_trigger","copilot_swe_agent_issue_labeled_trigger","copilot_swe_agent_pr_comment_model_picker","copilot_swe_agent_pull_request_assigned_trigger","copilot_swe_agent_pull_request_comment_trigger","copilot_swe_agent_pull_request_labeled_trigger","copilot_swe_agent_pull_request_merged_trigger","copilot_swe_agent_pull_request_opened_trigger","copilot_swe_agent_pull_request_ready_for_review_trigger","copilot_swe_agent_pull_request_review_requested_trigger","copilot_swe_agent_pull_request_review_submitted_trigger","copilot_swe_agent_pull_request_synchronize_trigger","copilot_swe_agent_sub_issue_added_trigger","copilot_swe_agent_use_subagents","copilot_task_api_github_rest_style","copilot_task_scoped_alive_channel","copilot_token_based_billing","copilot_unconfigured_is_inherited","copilot_user_can_upgrade_plan_field","copilot_web_integration_cutover","copilot_workbench_sunset_redirect","dashboard_agents_module_auth_token_check","dashboard_indexeddb_caching","fgpat_permissions_selector_redesign","glc_code_quality_repo_settings_workflow_config","hyperspace_2025_logged_out_batch_1","hyperspace_2025_logged_out_batch_2","hyperspace_2025_logged_out_batch_3","in_product_messaging_datadog_monitoring","ipm_ubb_individual_budget_banner","issue_fields_multi_select","issue_inline_avatars","issue_pinned_views","issue_pinned_views_team_vs_personal","issue_relative_time_micro","issue_viewer_paved_path","issues_expanded_file_types","issues_hide_closed_sub_issues","issues_lazy_load_comment_box_suggestions","issues_react_chrome_container_query_fix","labels_archiving","labels_archiving_info","landing_pages_ninetailed","lifecycle_label_name_updates","marketing_cookie_consent_banner","marketing_pages_search_explore_provider","memex_default_issue_create_repository","memex_live_update_hovercard","memex_mwl_filter_field_delimiter","memex_remove_deprecated_type_issue","merge_queue_restricted_pushers_warning","merge_status_header_feedback","milestone_closed_issues_prioritization","octocaptcha_origin_optimization","primer_react_css_anchor_positioning","primer_react_merged_forwarded_refs","primer_react_timeline_list_semantics","prs_copilot_app_open_action","prs_css_anchor_positioning","pull_request_copilot_attribution_header","pull_request_overview_merge_control","pull_request_overview_panel_edit_description","pull_request_persister","pull_request_stacks_navigation_shortcuts","pull_request_virtualization_image_estimate","pull_request_virtualization_loader_batching","pull_request_virtualization_scroll_compensation","pull_request_virtualization_scroll_intent","quick_search_lazy_suggestions","react_blob_isolate_code_lines","react_blob_ssr_content_visibility","react_data_router_tanstack_allowed","react_logged_out_repository_header","react_query_props_with_key","react_sandbox_future_tanstack","repo_app_turbo","repo_issues_sidebar_layout","repo_pulls_dashboard_declutter","repo_pulls_dashboard_ga","repo_pulls_dashboard_persistence","repos_contributors_limited_default_range","review_involves_filter","rule_ignored_file_paths","rulesets_actor_list_editor","sample_network_conn_type","security_center_artifact_filters_popover","see_who_reacted","semantic_similarity_duplicate_issue_detection","session_logs_ungroup_reasoning_text","set_sha256_on_repo_creation_form","site_banner_desktop_copilot_app","site_ghca_pixel_mona","site_github_app_ga_page","site_github_app_ga_page_highlight","site_github_app_mobile_native_share","site_global_banner_dev_days_attendee","site_global_nav_spark_models_removed","speculation_rules_ui_service","suggest_custom_property_values_copilot","suppress_automated_browser_vitals","swp_forms_disable_octocaptcha","thread_resolution_reason","update_issue_suggestions","viewscreen_sandbox","warn_inaccessible_attachments","webp_support","workstream_plugin_bootstrap"],"githubDomain":"https://github.com","copilotApiOverrideUrl":"https://api.githubcopilot.com","cmcApiUrl":"https://api.github.com/cmc_internal/api"}</script>
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/high-contrast-cookie-3663bcaacc724f4c.js"></script>
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/wp-runtime-721126455a2225e3.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/app-foundation-156c6259e31cc551.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/app-runtime-f6ce38f47c2e1d56.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/fetch-utilities-804a14996977c014.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ser-fb5d13278eb42203.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/tp-ea613009a991e211.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/environment-107a7753389a8a2d.js" defer="defer"></script>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/app-runtime.25915bc98fb322a6.module.css" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/catalyst-52ed81112a548e10.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/selector-observer-e8810f64c443fb9b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/relative-time-element-fe7e72f699fdf493.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/by-9da36843ba9d191d.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ja9-9a1160b939f2cd52.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/3h-55903cf2303047ad.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/hk-0d35a1220587d888.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/jz5-c964b1a3671f2a92.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/hj-1d800d09e9a8720a.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/j0-1ad12374da9777f2.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/github-elements-531d35538b61fd0d.js" defer="defer"></script>
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/element-registry-bf5e3b2aee197122.js" defer="defer"></script>
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/runtime-helpers-5e0b3ae3c4036207.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/aria-live-752acdc868e2da64.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/hotkey-e87ffadced20a3c9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-core-75bc55d9971828b7.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/a9-34620c7b13885011.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ur-643d2814115561a9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/4t6-5d0869970ac0aac0.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/pb0-a5c5ec36d311aeef.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/6n-afcf86ccabc4cad2.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/zj-f08c728cf00018aa.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/o6-2a1c68d269710ee9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/h9a-c6405aa090de0e84.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/vy6-3c3e6e96629c2ce4.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/js-4eb97d5803e657c0.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/g7-baf9e817ae102b01.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/unc-96389cade7bad821.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/nu-65322a6997c6c93c.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/behaviors-5dd3809b5c8bac3c.js" defer="defer"></script>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/react-core.3792087592bf207a.module.css" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/code-menu-4318f0f4c608f3dd.js" defer="defer"></script>
  
  <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/primer-react-7afef75d393cf294.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/op-acddf38478d45ef9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ncx-461e4b09f2e67ee5.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/qmp-c7cfba40cf5a93b0.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/j6-148a74299e5a01ab.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/t7l-a52ba56147f77909.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/4u-ec4874f70bfd5d76.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/s0-481bd34f90bc2bd7.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/y5-ed17e73b4c0bd15e.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/n4-be595475cdbf7d4b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/j8-23a3c5ff8eef412d.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/la-27679061f16e1495.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/iu-9806a0291a782cbe.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ftx-39fb490e3c1d778f.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/zi-32a0c3c081ea5cce.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/sg-7a5d50475874c0e1.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/pd-6a8710840033e042.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/86g-ec28c25ed7d5de06.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/sn-1bab7384818953b7.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/iq-6d4ecf6d2fb6993c.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/p2-7d8e7cee5b46cb45.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/7d-2e3cc25d719f3a95.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/4d-76d8acdf21a33266.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/tsb-e0f6288ab985d9d2.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/lf-910ef220ce85c660.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/2j-2f19c1afd2ceaf93.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/me-f1476ec44a29f34a.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/p2u-e654a57b1a70c47d.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/5d-d97cc006d4da4d9b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/r5-38f013bc2c0fd298.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/r6s-9039f5619230a653.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/9e-cece06724bf6ea3b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/x9-3e077a3a37a73f9f.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/pj-87629cb5389d7663.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/eq-3764fd5f66494289.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/13-d889936dff7e5c0f.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/44-8193eea4af825ead.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/v4-9c1327d212e52a0d.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/id-7f39706ba9007db6.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ah-271362a1ed227d03.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/s1g-d434d712bca59d3a.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/vz-d7f4a583896f872e.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/47-c8c0ce2700acc5be.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/code-view-4118a687d0150749.js" defer="defer"></script>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.2d881b4d4a503d1c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/pj.75627bfeb9ceb1da.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/ah.2623f7c6ecbe2ecd.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/47.78770c57a48a810c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/code-view.37656c95a9729fb9.module.css" />


  <title>Codewhale/docs/TELEMETRY.md at main · codewhale-hq/Codewhale · GitHub</title>



  <meta name="route-pattern" content="/:user_id/:repository/blob/*name(/*path)" data-turbo-transient>
  <meta name="route-controller" content="blob" data-turbo-transient>
  <meta name="route-action" content="show" data-turbo-transient>
  <meta name="fetch-nonce" content="v2:c668308f-1155-56d9-7472-70c938aba478">

    
  <meta name="current-catalog-service-hash" content="f3abb0cc802f3d7b95fc8762b94bdcb13bf39634c40c357301c4aa1d67a256fb">


  <meta name="request-id" content="821C:24555C:B604990:ECC5184:6ACA639D" data-pjax-transient="true"/><meta name="html-safe-nonce" content="adafd11cb15f00eabbc2c964c27e263f22bd158f220f4d8e7d88d6c4fd725dea" data-pjax-transient="true"/><meta name="visitor-payload" content="eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI4MjFDOjI0NTU1QzpCNjA0OTkwOkVDQzUxODQ6NkFDQTYzOUQiLCJ2aXNpdG9yX2lkIjoiNzExNjc0MTA4NDQ3ODg1ODE0MSIsInJlZ2lvbl9lZGdlIjoiZnJhIiwicmVnaW9uX3JlbmRlciI6ImZyYSJ9" data-pjax-transient="true"/><meta name="visitor-hmac" content="9b66e85f03870bd9802a5dc9fc2809742880e2db283f8b416ddbdaed3602ae9e" data-pjax-transient="true"/>


    <meta name="hovercard-subject-tag" content="repository:1137711311" data-turbo-transient>


  <meta name="github-keyboard-shortcuts" content="repository,source-code,file-tree,copilot" data-turbo-transient="true" />
  

  <meta name="selected-link" value="repo_source" data-turbo-transient>
  <link rel="assets" href="https://github.githubassets.com/">

    <meta name="google-site-verification" content="Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I">

<meta name="octolytics-url" content="https://collector.github.com/github/collect" />





  <meta name="analytics-location" content="/&lt;user-name&gt;/&lt;repo-name&gt;/blob/show" data-turbo-transient="true" />

  




    <meta name="user-login" content="">

  

    <meta name="viewport" content="width=device-width">

    

      <meta name="description" content="Open-source Rust agent engine and terminal client for Codewhale, with provider choice, tools, approvals and receipts. - Codewhale/docs/TELEMETRY.md at main · codewhale-hq/Codewhale">

      <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub">

    <link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub">
    <meta property="fb:app_id" content="1401488693436528">
    <meta name="apple-itunes-app" content="app-id=1477376905, app-argument=https://github.com/codewhale-hq/Codewhale/blob/main/docs/TELEMETRY.md" />

      <meta name="twitter:image" content="https://opengraph.githubassets.com/2d0b280439edc6d40adcfc52be30d8ec40db5b50cc309e72100cdb859381289d/codewhale-hq/Codewhale" /><meta name="twitter:site" content="@github" /><meta name="twitter:card" content="summary_large_image" /><meta name="twitter:title" content="Codewhale/docs/TELEMETRY.md at main · codewhale-hq/Codewhale" /><meta name="twitter:description" content="Open-source Rust agent engine and terminal client for Codewhale, with provider choice, tools, approvals and receipts. - codewhale-hq/Codewhale" />
  <meta property="og:image" content="https://opengraph.githubassets.com/2d0b280439edc6d40adcfc52be30d8ec40db5b50cc309e72100cdb859381289d/codewhale-hq/Codewhale" /><meta property="og:image:alt" content="Open-source Rust agent engine and terminal client for Codewhale, with provider choice, tools, approvals and receipts. - codewhale-hq/Codewhale" /><meta property="og:image:width" content="1200" /><meta property="og:image:height" content="600" /><meta property="og:site_name" content="GitHub" /><meta property="og:type" content="object" /><meta property="og:title" content="Codewhale/docs/TELEMETRY.md at main · codewhale-hq/Codewhale" /><meta property="og:url" content="https://github.com/codewhale-hq/Codewhale/blob/main/docs/TELEMETRY.md" /><meta property="og:description" content="Open-source Rust agent engine and terminal client for Codewhale, with provider choice, tools, approvals and receipts. - codewhale-hq/Codewhale" />
  




      <meta name="hostname" content="github.com">



        <meta name="expected-hostname" content="github.com">


  <meta http-equiv="x-pjax-version" content="d05be8f8b6905b6460fc264e80447721dfee1e32cf9e4291c4bf58f160c9f705" data-turbo-track="reload">
  <meta http-equiv="x-pjax-csp-version" content="c4a65e47b0c850e1157ae8e66298070851d7e3b558038de5a3b4ff7a93e630ed" data-turbo-track="reload">
  <meta http-equiv="x-pjax-css-version" content="a80b0545b169f440b929ce2b977c76b6988f014cca6513fb83c5df6581635fb3" data-turbo-track="reload">
  <meta http-equiv="x-pjax-js-version" content="af51c6f9d659be0324665373df3ee542f817dbd7f66f352a087935f2ceabe545" data-turbo-track="reload">

  <meta name="turbo-cache-control" content="no-preview" data-turbo-transient="">

      <meta name="turbo-cache-control" content="no-cache" data-turbo-transient>

    <meta data-hydrostats="publish">

  <meta name="go-import" content="github.com/codewhale-hq/Codewhale git https://github.com/codewhale-hq/Codewhale.git">

  <meta name="octolytics-dimension-user_id" content="326694313" /><meta name="octolytics-dimension-user_login" content="codewhale-hq" /><meta name="octolytics-dimension-repository_id" content="1137711311" /><meta name="octolytics-dimension-repository_nwo" content="codewhale-hq/Codewhale" /><meta name="octolytics-dimension-repository_public" content="true" /><meta name="octolytics-dimension-repository_is_fork" content="false" /><meta name="octolytics-dimension-repository_network_root_id" content="1137711311" /><meta name="octolytics-dimension-repository_network_root_nwo" content="codewhale-hq/Codewhale" />
  



    

    <meta name="turbo-body-classes" content="logged-out env-production page-responsive">
  <meta name="disable-turbo" content="false">


  <meta name="browser-stats-url" content="https://api.github.com/_private/browser/stats">


  <meta name="browser-errors-url" content="https://api.github.com/_private/browser/errors">

  <meta name="release" content="3b1bb5b10f5c7fd1769d56e38b15dfddb34052a8" data-turbo-track="reload">
  <meta name="ui-target" content="full">

  <link rel="mask-icon" href="https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg" color="#000000">
  <link rel="alternate icon" class="js-site-favicon" type="image/png" href="https://github.githubassets.com/favicons/favicon.png">
  <link rel="icon" class="js-site-favicon" type="image/svg+xml" href="https://github.githubassets.com/favicons/favicon.svg" data-base-href="https://github.githubassets.com/favicons/favicon">

<meta name="theme-color" content="#1e2327">
<meta name="color-scheme" content="light dark" />


  <link rel="manifest" href="/manifest.json" crossOrigin="use-credentials">

  </head>

  <body class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
    <div data-turbo-body class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
      <div id="__primerPortalRoot__" style="z-index: 1000; position: absolute; width: 100%;" data-turbo-permanent></div>
      

    <div class="position-relative header-wrapper js-header-wrapper ">
      <a href="#start-of-content" data-skip-target-assigned="false" class="px-2 tmp-py-4 color-bg-accent-emphasis color-fg-on-emphasis show-on-focus js-skip-to-content">Skip to content</a>

      <span data-view-component="true" class="progress-pjax-loader Progress position-fixed width-full">
    <span style="width: 0%;" data-view-component="true" class="Progress-item progress-pjax-loader-bar left-0 top-0 color-bg-accent-emphasis"></span>
</span>      
      <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/19-c660652a0a1639be.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/keyboard-shortcuts-dialog-47c5223d8d1af8ef.js" fetchpriority="low" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.2d881b4d4a503d1c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/keyboard-shortcuts-dialog.d53d993320d57e14.module.css" />

<react-partial
  partial-name="keyboard-shortcuts-dialog"
  data-ssr="false"
  data-attempted-ssr="false"
  data-react-profiling="false"
>
  
  <script type="application/json" data-target="react-partial.embeddedData">{"props":{"docsUrl":"https://docs.github.com/get-started/accessibility/keyboard-shortcuts"}}</script>
  <div data-target="react-partial.reactRoot"></div>
</react-partial>





      

          <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/app-install-banner-partial-3c87deb7f0f20434.js" fetchpriority="low" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.2d881b4d4a503d1c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/app-install-banner-partial.7b357012e82003e7.module.css" />

<react-partial
  partial-name="app-install-banner-partial"
  data-ssr="false"
  data-attempted-ssr="false"
  data-react-profiling="false"
>
  
  <script type="application/json" data-target="react-partial.embeddedData">{"props":{}}</script>
  <div data-target="react-partial.reactRoot"></div>
</react-partial>


          

                <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/et9-7eeec247c287fca4.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/94v-e20946127faa8f6e.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/fz5-892a9e99cc92858d.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/jag-441e702bfd4c7904.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/hw-8ce7888b57d0a23c.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/rq-0ec82a12cf538a4d.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/1m-a7a4c022483b2713.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/marketing-header-70703fe17422eb58.js" fetchpriority="low" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.2d881b4d4a503d1c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-brand-css.fbc35b3d20e988ff.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/1m.fec8b575d0e5234f.module.css" />

<react-partial
  partial-name="marketing-header"
  data-ssr="true"
  data-attempted-ssr="true"
  data-react-profiling="false"
>
  
  <script type="application/json" data-target="react-partial.embeddedData">{"props":{"color_mode":"dark","logged_in":false,"marketing_page":false,"home_path":"/","login_path":"/login?return_to=https%3A%2F%2Fgithub.com%2Fcodewhale-hq%2FCodewhale%2Fblob%2Fmain%2Fdocs%2FTELEMETRY.md","signup_path":"/signup?ref_cta=Sign+up\u0026ref_loc=header+logged+out\u0026ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fblob%2Fshow\u0026source=header-repo\u0026source_repo=codewhale-hq%2FCodewhale","signup_enabled":true,"is_signup_controller":false,"show_search_and_nav":true,"hide_search":false,"private_mode_enabled":false,"should_use_dotcom_links":true,"auth_hydro_click":"{\"event_type\":\"authentication.click\",\"payload\":{\"location_in_page\":\"site header menu\",\"repository_id\":null,\"auth_type\":\"SIGN_UP\",\"originating_url\":\"https://github.com/codewhale-hq/Codewhale/blob/main/docs/TELEMETRY.md\",\"user_id\":null}}","auth_hydro_click_hmac":"4512a6a0748a88cf0189d958d154f077d9da7f0f8d5623516fbf40f6d515b205","overlay":false,"fixed":false}}</script>
  <div data-target="react-partial.reactRoot"><div data-color-mode="dark" data-light-theme="light" data-dark-theme="dark"><header class="MarketingHeader-module__root__Tk7n3 HeaderMktg header-logged-out" role="banner" data-marketing-header="true" data-color-mode="dark" data-light-theme="light" data-dark-theme="dark" data-is-top="true"><h2 class="MarketingHeader-module__visuallyHidden__sqKsl">Navigation Menu</h2><button type="button" class="MarketingHeader-module__backdrop__sw4RU" aria-label="Close navigation menu"></button><div class="MarketingHeader-module__bar__mBSyE"><div class="MarketingHeader-module__topRow__yeury"><div class="MarketingHeader-module__toggleSlot__hDxbh"><button type="button" class="HeaderMenuToggle-module__toggle__i8EiC" aria-label="Toggle navigation" aria-expanded="false"><span class="HeaderMenuToggle-module__toggleBar__jVN0H"></span><span class="HeaderMenuToggle-module__toggleBar__jVN0H"></span><span class="HeaderMenuToggle-module__toggleBar__jVN0H"></span></button></div><a href="/" aria-label="Homepage" class="HeaderLogo-module__logo__UFyHI" data-analytics-event="{&quot;action&quot;:&quot;homepage&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;logo&quot;,&quot;location&quot;:&quot;header&quot;,&quot;label&quot;:&quot;homepage_link_logo_header&quot;}"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-mark-github" viewBox="0 0 24 24" width="32" height="32" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.226 17.284c-2.965-.36-5.054-2.493-5.054-5.256 0-1.123.404-2.336 1.078-3.144-.292-.741-.247-2.314.09-2.965.898-.112 2.111.36 2.83 1.01.853-.269 1.752-.404 2.853-.404 1.1 0 1.999.135 2.807.382.696-.629 1.932-1.1 2.83-.988.315.606.36 2.179.067 2.942.72.854 1.101 2 1.101 3.167 0 2.763-2.089 4.852-5.098 5.234.763.494 1.28 1.572 1.28 2.807v2.336c0 .674.561 1.056 1.235.786 4.066-1.55 7.255-5.615 7.255-10.646C23.5 6.188 18.334 1 11.978 1 5.62 1 .5 6.188.5 12.545c0 4.986 3.167 9.12 7.435 10.669.606.225 1.19-.18 1.19-.786V20.63a2.9 2.9 0 0 1-1.078.224c-1.483 0-2.359-.808-2.987-2.313-.247-.607-.517-.966-1.034-1.033-.27-.023-.359-.135-.359-.27 0-.27.45-.471.898-.471.652 0 1.213.404 1.797 1.235.45.651.921.943 1.483.943.561 0 .92-.202 1.437-.719.382-.381.674-.718.944-.943"></path></svg></a><div class="AuthCTAs-module__mobileActions__NNzeV"><a class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw AuthCTAs-module__cta__WpwQq" href="/login?return_to=https%3A%2F%2Fgithub.com%2Fcodewhale-hq%2FCodewhale%2Fblob%2Fmain%2Fdocs%2FTELEMETRY.md" data-analytics-event="{&quot;action&quot;:&quot;sign_in&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;auth_cta&quot;,&quot;location&quot;:&quot;header&quot;,&quot;label&quot;:&quot;sign_in_link_auth_cta_header&quot;}" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/codewhale-hq/Codewhale/blob/main/docs/TELEMETRY.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="4512a6a0748a88cf0189d958d154f077d9da7f0f8d5623516fbf40f6d515b205"><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH">Sign in</span></span></a><button class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw HeaderAppearanceSettings-module__trigger__hUheK" type="button" aria-haspopup="dialog" aria-labelledby="_R_3dd_"><span class="Primer_Brand__Button-module__Button__leading-visual___jjtTe" data-testid="Button-leading-visual"><svg data-component="Octicon" focusable="false" aria-hidden="true" class="octicon octicon-sliders Primer_Brand__Button-module__Button__icon-visual____qybb" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M15 2.75a.75.75 0 0 1-.75.75h-4a.75.75 0 0 1 0-1.5h4a.75.75 0 0 1 .75.75Zm-8.5.75v1.25a.75.75 0 0 0 1.5 0v-4a.75.75 0 0 0-1.5 0V2H1.75a.75.75 0 0 0 0 1.5H6.5Zm1.25 5.25a.75.75 0 0 0 0-1.5h-6a.75.75 0 0 0 0 1.5h6ZM15 8a.75.75 0 0 1-.75.75H11.5V10a.75.75 0 1 1-1.5 0V6a.75.75 0 0 1 1.5 0v1.25h2.75A.75.75 0 0 1 15 8Zm-9 5.25v-2a.75.75 0 0 0-1.5 0v1.25H1.75a.75.75 0 0 0 0 1.5H4.5v1.25a.75.75 0 0 0 1.5 0v-2Zm9 0a.75.75 0 0 1-.75.75h-6a.75.75 0 0 1 0-1.5h6a.75.75 0 0 1 .75.75Z"></path></svg></span><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH"></span></span></button><div class="Primer_Brand__Tooltip-module__Tooltip___0Eipx" data-direction="s" aria-hidden="true" id="_R_3dd_">Appearance settings</div></div></div><div class="MarketingHeader-module__menu__GIy3y"><div class="MarketingHeader-module__menuWrapper__owstH"><nav class="MarketingNavigation-module__nav__W0KYY" aria-label="Global"><ul class="MarketingNavigation-module__list__tFbMb"><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_nd_">Platform<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_nd_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5knd_">AI CODE CREATION</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5knd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/copilot" data-analytics-event="{&quot;action&quot;:&quot;github_copilot&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_copilot_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copilot NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M7.998 15.035c-4.562 0-7.873-2.914-7.998-3.749V9.338c.085-.628.677-1.686 1.588-2.065.013-.07.024-.143.036-.218.029-.183.06-.384.126-.612-.201-.508-.254-1.084-.254-1.656 0-.87.128-1.769.693-2.484.579-.733 1.494-1.124 2.724-1.261 1.206-.134 2.262.034 2.944.765.05.053.096.108.139.165.044-.057.094-.112.143-.165.682-.731 1.738-.899 2.944-.765 1.23.137 2.145.528 2.724 1.261.566.715.693 1.614.693 2.484 0 .572-.053 1.148-.254 1.656.066.228.098.429.126.612.012.076.024.148.037.218.924.385 1.522 1.471 1.591 2.095v1.872c0 .766-3.351 3.795-8.002 3.795Zm0-1.485c2.28 0 4.584-1.11 5.002-1.433V7.862l-.023-.116c-.49.21-1.075.291-1.727.291-1.146 0-2.059-.327-2.71-.991A3.222 3.222 0 0 1 8 6.303a3.24 3.24 0 0 1-.544.743c-.65.664-1.563.991-2.71.991-.652 0-1.236-.081-1.727-.291l-.023.116v4.255c.419.323 2.722 1.433 5.002 1.433ZM6.762 2.83c-.193-.206-.637-.413-1.682-.297-1.019.113-1.479.404-1.713.7-.247.312-.369.789-.369 1.554 0 .793.129 1.171.308 1.371.162.181.519.379 1.442.379.853 0 1.339-.235 1.638-.54.315-.322.527-.827.617-1.553.117-.935-.037-1.395-.241-1.614Zm4.155-.297c-1.044-.116-1.488.091-1.681.297-.204.219-.359.679-.242 1.614.091.726.303 1.231.618 1.553.299.305.784.54 1.638.54.922 0 1.28-.198 1.442-.379.179-.2.308-.578.308-1.371 0-.765-.123-1.242-.37-1.554-.233-.296-.693-.587-1.713-.7Z"></path><path d="M6.25 9.037a.75.75 0 0 1 .75.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 .75-.75Zm4.25.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 1.5 0Z"></path></svg>GitHub Copilot</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Write better code with AI</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/ai/github-app" data-analytics-event="{&quot;action&quot;:&quot;github_copilot_app&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_copilot_app_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-mark-github NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M6.766 11.328c-2.063-.25-3.516-1.734-3.516-3.656 0-.781.281-1.625.75-2.188-.203-.515-.172-1.609.063-2.062.625-.078 1.468.25 1.968.703.594-.187 1.219-.281 1.985-.281.765 0 1.39.094 1.953.265.484-.437 1.344-.765 1.969-.687.218.422.25 1.515.046 2.047.5.593.766 1.39.766 2.203 0 1.922-1.453 3.375-3.547 3.64.531.344.89 1.094.89 1.954v1.625c0 .468.391.734.86.547C13.781 14.359 16 11.53 16 8.03 16 3.61 12.406 0 7.984 0 3.563 0 0 3.61 0 8.031a7.88 7.88 0 0 0 5.172 7.422c.422.156.828-.125.828-.547v-1.25c-.219.094-.5.156-.75.156-1.031 0-1.64-.562-2.078-1.609-.172-.422-.36-.672-.719-.719-.187-.015-.25-.093-.25-.187 0-.188.313-.328.625-.328.453 0 .844.281 1.25.86.313.452.64.655 1.031.655s.641-.14 1-.5c.266-.265.47-.5.657-.656"></path></svg>GitHub Copilot app</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Direct agents from issue to merge</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/mcp" data-analytics-event="{&quot;action&quot;:&quot;mcp_registry&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;mcp_registry_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-mcp NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M5.52 1.12a3.578 3.578 0 0 1 6.078 2.98 3.578 3.578 0 0 1 2.982 6.08l-3.292 3.293a.252.252 0 0 0 0 .354l.843.843a.749.749 0 1 1-1.06 1.06l-.844-.843a1.75 1.75 0 0 1 0-2.474L13.52 9.12a2.08 2.08 0 0 0 0-2.94 2.08 2.08 0 0 0-2.94 0L7.731 9.03A.75.75 0 0 1 6.67 7.97l2.85-2.85a2.08 2.08 0 0 0 0-2.94 2.08 2.08 0 0 0-2.94 0l-4.799 4.8A.75.75 0 0 1 .72 5.92Z"></path><path d="M7.52 3.12a.749.749 0 1 1 1.06 1.06L5.731 7.03A2.079 2.079 0 0 0 8.67 9.97l2.85-2.85a.749.749 0 1 1 1.06 1.06l-2.849 2.85A3.578 3.578 0 0 1 4.67 5.97Z"></path></svg>MCP Registry</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Integrate external tools</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9knd_">DEVELOPER WORKFLOWS</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9knd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/actions" data-analytics-event="{&quot;action&quot;:&quot;actions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;actions_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-workflow NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 1.75C0 .784.784 0 1.75 0h3.5C6.216 0 7 .784 7 1.75v3.5A1.75 1.75 0 0 1 5.25 7H4v4a1 1 0 0 0 1 1h4v-1.25C9 9.784 9.784 9 10.75 9h3.5c.966 0 1.75.784 1.75 1.75v3.5A1.75 1.75 0 0 1 14.25 16h-3.5A1.75 1.75 0 0 1 9 14.25v-.75H5A2.5 2.5 0 0 1 2.5 11V7h-.75A1.75 1.75 0 0 1 0 5.25Zm1.75-.25a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Zm9 9a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Z"></path></svg>Actions</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Automate any workflow</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/codespaces" data-analytics-event="{&quot;action&quot;:&quot;codespaces&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;codespaces_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-codespaces NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 11.25c0-.966.784-1.75 1.75-1.75h12.5c.966 0 1.75.784 1.75 1.75v3A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25Zm2-9.5C2 .784 2.784 0 3.75 0h8.5C13.216 0 14 .784 14 1.75v5a1.75 1.75 0 0 1-1.75 1.75h-8.5A1.75 1.75 0 0 1 2 6.75Zm1.75-.25a.25.25 0 0 0-.25.25v5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-5a.25.25 0 0 0-.25-.25Zm-2 9.5a.25.25 0 0 0-.25.25v3c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-3a.25.25 0 0 0-.25-.25Z"></path><path d="M7 12.75a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Zm-4 0a.75.75 0 0 1 .75-.75h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1-.75-.75Z"></path></svg>Codespaces</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Instant dev environments</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/issues" data-analytics-event="{&quot;action&quot;:&quot;issues&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;issues_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-issue-opened NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"></path></svg>Issues</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Plan and track work</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/code-review" data-analytics-event="{&quot;action&quot;:&quot;code_review&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;code_review_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-code NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path></svg>Code Review</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Manage code changes</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/code-quality" data-analytics-event="{&quot;action&quot;:&quot;code_quality&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;code_quality_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-codescan-checkmark NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.28 6.28a.75.75 0 1 0-1.06-1.06L6.25 8.19l-.97-.97a.75.75 0 0 0-1.06 1.06l1.5 1.5a.75.75 0 0 0 1.06 0l3.5-3.5Z"></path><path d="M7.5 15a7.5 7.5 0 1 1 5.807-2.754l2.473 2.474a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215l-2.474-2.473A7.472 7.472 0 0 1 7.5 15Zm0-13.5a6 6 0 1 0 4.094 10.386.748.748 0 0 1 .293-.292 6.002 6.002 0 0 0 1.117-6.486A6.002 6.002 0 0 0 7.5 1.5Z"></path></svg>Code Quality</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Enforce quality at merge</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_dknd_">APPLICATION SECURITY</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_dknd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/security/advanced-security" data-analytics-event="{&quot;action&quot;:&quot;github_advanced_security&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_advanced_security_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-shield-check NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m8.533.133 5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667l5.25-1.68a1.748 1.748 0 0 1 1.066 0Zm-.61 1.429.001.001-5.25 1.68a.251.251 0 0 0-.174.237V7c0 1.36.275 2.666 1.057 3.859.784 1.194 2.121 2.342 4.366 3.298a.196.196 0 0 0 .154 0c2.245-.957 3.582-2.103 4.366-3.297C13.225 9.666 13.5 8.358 13.5 7V3.48a.25.25 0 0 0-.174-.238l-5.25-1.68a.25.25 0 0 0-.153 0ZM11.28 6.28l-3.5 3.5a.75.75 0 0 1-1.06 0l-1.5-1.5a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l.97.97 2.97-2.97a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path></svg>GitHub Advanced Security</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Find and fix vulnerabilities</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/security/advanced-security/code-security" data-analytics-event="{&quot;action&quot;:&quot;code_security&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;code_security_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-code-square NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25Zm7.47 3.97a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1 0 1.06l-2 2a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L10.69 8 9.22 6.53a.75.75 0 0 1 0-1.06ZM6.78 6.53 5.31 8l1.47 1.47a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215l-2-2a.75.75 0 0 1 0-1.06l2-2a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path></svg>Code security</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Secure your code as you build</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/security/advanced-security/secret-protection" data-analytics-event="{&quot;action&quot;:&quot;secret_protection&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;secret_protection_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-lock NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M4 4a4 4 0 0 1 8 0v2h.25c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 12.25 15h-8.5A1.75 1.75 0 0 1 2 13.25v-5.5C2 6.784 2.784 6 3.75 6H4Zm8.25 3.5h-8.5a.25.25 0 0 0-.25.25v5.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25ZM10.5 6V4a2.5 2.5 0 1 0-5 0v2Z"></path></svg>Secret protection</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Stop leaks before they start</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ NavGroup-module__hasSeparator__FnMrN"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_hknd_">EXPLORE</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_hknd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/why-github" data-analytics-event="{&quot;action&quot;:&quot;why_github&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;why_github_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Why GitHub</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://docs.github.com" data-analytics-event="{&quot;action&quot;:&quot;documentation&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;documentation_link_platform_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Documentation</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://github.blog" data-analytics-event="{&quot;action&quot;:&quot;blog&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;blog_link_platform_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Blog</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://github.blog/changelog" data-analytics-event="{&quot;action&quot;:&quot;changelog&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;changelog_link_platform_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Changelog</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/marketplace" data-analytics-event="{&quot;action&quot;:&quot;marketplace&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;marketplace_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Marketplace</span></a></li></ul></div></li></ul><div class="NavDropdown-module__trailingLinkContainer__VgJGL"><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/features" data-analytics-event="{&quot;action&quot;:&quot;view_all_features&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_features_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all features</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></div></div></div></li><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_17d_">Solutions<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_17d_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5l7d_">BY COMPANY SIZE</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5l7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/enterprise" data-analytics-event="{&quot;action&quot;:&quot;enterprises&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;enterprises_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Enterprises</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/team" data-analytics-event="{&quot;action&quot;:&quot;small_and_medium_teams&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;small_and_medium_teams_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Small and medium teams</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/enterprise/startups" data-analytics-event="{&quot;action&quot;:&quot;startups&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;startups_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Startups</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/nonprofits" data-analytics-event="{&quot;action&quot;:&quot;nonprofits&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;nonprofits_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Nonprofits</span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9l7d_">BY USE CASE</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9l7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/use-case/app-modernization" data-analytics-event="{&quot;action&quot;:&quot;app_modernization&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;app_modernization_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">App Modernization</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/use-case/devsecops" data-analytics-event="{&quot;action&quot;:&quot;devsecops&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;devsecops_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">DevSecOps</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/use-case/devops" data-analytics-event="{&quot;action&quot;:&quot;devops&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;devops_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">DevOps</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/use-case/ci-cd" data-analytics-event="{&quot;action&quot;:&quot;ci/cd&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;ci/cd_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">CI/CD</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/solutions/use-case" data-analytics-event="{&quot;action&quot;:&quot;view_all_use_cases&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_use_cases_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all use cases</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_dl7d_">BY INDUSTRY</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_dl7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/healthcare" data-analytics-event="{&quot;action&quot;:&quot;healthcare&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;healthcare_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Healthcare</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/financial-services" data-analytics-event="{&quot;action&quot;:&quot;financial_services&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;financial_services_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Financial services</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/manufacturing" data-analytics-event="{&quot;action&quot;:&quot;manufacturing&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;manufacturing_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Manufacturing</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/government" data-analytics-event="{&quot;action&quot;:&quot;government&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;government_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Government</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/solutions/industry" data-analytics-event="{&quot;action&quot;:&quot;view_all_industries&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_industries_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all industries</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></li></ul></div></li></ul><div class="NavDropdown-module__trailingLinkContainer__VgJGL"><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/solutions" data-analytics-event="{&quot;action&quot;:&quot;view_all_solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_solutions_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all solutions</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></div></div></div></li><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_1nd_">Resources<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_1nd_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5lnd_">EXPLORE BY TOPIC</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5lnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/articles?topic=ai" data-analytics-event="{&quot;action&quot;:&quot;ai&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;ai_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">AI</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/articles?topic=software-development" data-analytics-event="{&quot;action&quot;:&quot;software_development&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;software_development_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Software Development</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/articles?topic=devops" data-analytics-event="{&quot;action&quot;:&quot;devops&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;devops_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">DevOps</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/articles?topic=security" data-analytics-event="{&quot;action&quot;:&quot;security&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;security_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Security</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/resources/articles" data-analytics-event="{&quot;action&quot;:&quot;view_all_topics&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_topics_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all topics</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9lnd_">EXPLORE BY TYPE</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9lnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/customer-stories" data-analytics-event="{&quot;action&quot;:&quot;customer_stories&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;customer_stories_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Customer stories</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/events" data-analytics-event="{&quot;action&quot;:&quot;events__webinars&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;events__webinars_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Events &amp; webinars</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/whitepapers" data-analytics-event="{&quot;action&quot;:&quot;ebooks__reports&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;ebooks__reports_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Ebooks &amp; reports</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/executive-insights" data-analytics-event="{&quot;action&quot;:&quot;business_insights&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;business_insights_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Business insights</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://skills.github.com" data-analytics-event="{&quot;action&quot;:&quot;github_skills&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_skills_link_resources_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">GitHub Skills</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_dlnd_">SUPPORT &amp; SERVICES</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_dlnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://docs.github.com" data-analytics-event="{&quot;action&quot;:&quot;documentation&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;documentation_link_resources_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Documentation</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://support.github.com" data-analytics-event="{&quot;action&quot;:&quot;customer_support&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;customer_support_link_resources_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Customer support</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/orgs/community/discussions" data-analytics-event="{&quot;action&quot;:&quot;community_forum&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;community_forum_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Community forum</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/trust-center" data-analytics-event="{&quot;action&quot;:&quot;trust_center&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;trust_center_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Trust center</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/partners" data-analytics-event="{&quot;action&quot;:&quot;partners&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;partners_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Partners</span></a></li></ul></div></li></ul><div class="NavDropdown-module__trailingLinkContainer__VgJGL"><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/resources" data-analytics-event="{&quot;action&quot;:&quot;view_all_resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_resources_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all resources</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></div></div></div></li><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_27d_">Open Source<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_27d_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5m7d_">COMMUNITY</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5m7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/open-source/sponsors" data-analytics-event="{&quot;action&quot;:&quot;github_sponsors&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_sponsors_link_open_source_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-sponsor-tiers NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.586 1C12.268 1 13.5 2.37 13.5 4.25c0 1.745-.996 3.359-2.622 4.831-.166.15-.336.297-.509.438l1.116 5.584a.75.75 0 0 1-.991.852l-2.409-.876a.25.25 0 0 0-.17 0l-2.409.876a.75.75 0 0 1-.991-.852L5.63 9.519a13.78 13.78 0 0 1-.51-.438C3.497 7.609 2.5 5.995 2.5 4.25 2.5 2.37 3.732 1 5.414 1c.963 0 1.843.403 2.474 1.073L8 2.198l.112-.125a3.385 3.385 0 0 1 2.283-1.068L10.586 1Zm-3.621 9.495-.718 3.594 1.155-.42a1.75 1.75 0 0 1 1.028-.051l.168.051 1.154.42-.718-3.592c-.199.13-.37.235-.505.314l-.169.097a.75.75 0 0 1-.72 0 9.54 9.54 0 0 1-.515-.308l-.16-.105ZM10.586 2.5c-.863 0-1.611.58-1.866 1.459-.209.721-1.231.721-1.44 0C7.025 3.08 6.277 2.5 5.414 2.5 4.598 2.5 4 3.165 4 4.25c0 1.23.786 2.504 2.128 3.719.49.443 1.018.846 1.546 1.198l.325.21.076-.047.251-.163a13.341 13.341 0 0 0 1.546-1.198C11.214 6.754 12 5.479 12 4.25c0-1.085-.598-1.75-1.414-1.75Z"></path></svg>GitHub Sponsors</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Fund open source developers</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9m7d_">PROGRAMS</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9m7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://securitylab.github.com" data-analytics-event="{&quot;action&quot;:&quot;security_lab&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;security_lab_link_open_source_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Security Lab</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://maintainers.github.com" data-analytics-event="{&quot;action&quot;:&quot;maintainer_community&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;maintainer_community_link_open_source_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Maintainer Community</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://stars.github.com" data-analytics-event="{&quot;action&quot;:&quot;github_stars&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_stars_link_open_source_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">GitHub Stars</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://archiveprogram.github.com" data-analytics-event="{&quot;action&quot;:&quot;archive_program&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;archive_program_link_open_source_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Archive Program</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_dm7d_">REPOSITORIES</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_dm7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/topics" data-analytics-event="{&quot;action&quot;:&quot;topics&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;topics_link_open_source_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Topics</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/trending" data-analytics-event="{&quot;action&quot;:&quot;trending&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;trending_link_open_source_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Trending</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/collections" data-analytics-event="{&quot;action&quot;:&quot;collections&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;collections_link_open_source_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Collections</span></a></li></ul></div></li></ul></div></div></li><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_2nd_">Enterprise<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_2nd_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5mnd_">ENTERPRISE SOLUTIONS</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5mnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/enterprise" data-analytics-event="{&quot;action&quot;:&quot;enterprise_platform&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;enterprise_platform_link_enterprise_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-stack NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M7.122.392a1.75 1.75 0 0 1 1.756 0l5.003 2.902c.83.481.83 1.68 0 2.162L8.878 8.358a1.75 1.75 0 0 1-1.756 0L2.119 5.456a1.251 1.251 0 0 1 0-2.162ZM8.125 1.69a.248.248 0 0 0-.25 0l-4.63 2.685 4.63 2.685a.248.248 0 0 0 .25 0l4.63-2.685ZM1.601 7.789a.75.75 0 0 1 1.025-.273l5.249 3.044a.248.248 0 0 0 .25 0l5.249-3.044a.75.75 0 0 1 .752 1.298l-5.248 3.044a1.75 1.75 0 0 1-1.756 0L1.874 8.814A.75.75 0 0 1 1.6 7.789Zm0 3.5a.75.75 0 0 1 1.025-.273l5.249 3.044a.248.248 0 0 0 .25 0l5.249-3.044a.75.75 0 0 1 .752 1.298l-5.248 3.044a1.75 1.75 0 0 1-1.756 0l-5.248-3.044a.75.75 0 0 1-.273-1.025Z"></path></svg>Enterprise platform</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">AI-powered developer platform</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9mnd_">AVAILABLE ADD-ONS</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9mnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/security/advanced-security" data-analytics-event="{&quot;action&quot;:&quot;github_advanced_security&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_advanced_security_link_enterprise_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-shield-check NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m8.533.133 5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667l5.25-1.68a1.748 1.748 0 0 1 1.066 0Zm-.61 1.429.001.001-5.25 1.68a.251.251 0 0 0-.174.237V7c0 1.36.275 2.666 1.057 3.859.784 1.194 2.121 2.342 4.366 3.298a.196.196 0 0 0 .154 0c2.245-.957 3.582-2.103 4.366-3.297C13.225 9.666 13.5 8.358 13.5 7V3.48a.25.25 0 0 0-.174-.238l-5.25-1.68a.25.25 0 0 0-.153 0ZM11.28 6.28l-3.5 3.5a.75.75 0 0 1-1.06 0l-1.5-1.5a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l.97.97 2.97-2.97a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path></svg>GitHub Advanced Security</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Enterprise-grade security features</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/copilot/copilot-business" data-analytics-event="{&quot;action&quot;:&quot;copilot_for_business&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;copilot_for_business_link_enterprise_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copilot NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M7.998 15.035c-4.562 0-7.873-2.914-7.998-3.749V9.338c.085-.628.677-1.686 1.588-2.065.013-.07.024-.143.036-.218.029-.183.06-.384.126-.612-.201-.508-.254-1.084-.254-1.656 0-.87.128-1.769.693-2.484.579-.733 1.494-1.124 2.724-1.261 1.206-.134 2.262.034 2.944.765.05.053.096.108.139.165.044-.057.094-.112.143-.165.682-.731 1.738-.899 2.944-.765 1.23.137 2.145.528 2.724 1.261.566.715.693 1.614.693 2.484 0 .572-.053 1.148-.254 1.656.066.228.098.429.126.612.012.076.024.148.037.218.924.385 1.522 1.471 1.591 2.095v1.872c0 .766-3.351 3.795-8.002 3.795Zm0-1.485c2.28 0 4.584-1.11 5.002-1.433V7.862l-.023-.116c-.49.21-1.075.291-1.727.291-1.146 0-2.059-.327-2.71-.991A3.222 3.222 0 0 1 8 6.303a3.24 3.24 0 0 1-.544.743c-.65.664-1.563.991-2.71.991-.652 0-1.236-.081-1.727-.291l-.023.116v4.255c.419.323 2.722 1.433 5.002 1.433ZM6.762 2.83c-.193-.206-.637-.413-1.682-.297-1.019.113-1.479.404-1.713.7-.247.312-.369.789-.369 1.554 0 .793.129 1.171.308 1.371.162.181.519.379 1.442.379.853 0 1.339-.235 1.638-.54.315-.322.527-.827.617-1.553.117-.935-.037-1.395-.241-1.614Zm4.155-.297c-1.044-.116-1.488.091-1.681.297-.204.219-.359.679-.242 1.614.091.726.303 1.231.618 1.553.299.305.784.54 1.638.54.922 0 1.28-.198 1.442-.379.179-.2.308-.578.308-1.371 0-.765-.123-1.242-.37-1.554-.233-.296-.693-.587-1.713-.7Z"></path><path d="M6.25 9.037a.75.75 0 0 1 .75.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 .75-.75Zm4.25.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 1.5 0Z"></path></svg>Copilot for Business</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Enterprise-grade AI features</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/enterprise/premium-support" data-analytics-event="{&quot;action&quot;:&quot;premium_support&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;premium_support_link_enterprise_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-comment-discussion NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1h8.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 10.25 10H7.061l-2.574 2.573A1.458 1.458 0 0 1 2 11.543V10h-.25A1.75 1.75 0 0 1 0 8.25v-5.5C0 1.784.784 1 1.75 1ZM1.5 2.75v5.5c0 .138.112.25.25.25h1a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13 2a.25.25 0 0 0-.25-.25h-.5a.75.75 0 0 1 0-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 12H14v1.543a1.458 1.458 0 0 1-2.487 1.03L9.22 12.28a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l2.22 2.22v-2.19a.75.75 0 0 1 .75-.75h1a.25.25 0 0 0 .25-.25Z"></path></svg>Premium Support</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Enterprise-grade 24/7 support</span></span></a></li></ul></div></li></ul></div></div></li><li><a href="https://github.com/pricing" data-analytics-event="{&quot;action&quot;:&quot;pricing&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;pricing&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;pricing_link_pricing_navbar&quot;}" class="MarketingNavigation-module__navLink__hUomM">Pricing</a></li></ul></nav><div class="MarketingHeader-module__ctaContainer__tBmPz"><div class="HeaderSearch-module__searchSlot__oVOUS"><button class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw HeaderSearch-module__trigger__zsF9q" type="button" aria-haspopup="dialog" aria-expanded="false" aria-label="Search or jump to, type / to search" data-analytics-event="{&quot;action&quot;:&quot;searchbar&quot;,&quot;tag&quot;:&quot;input&quot;,&quot;context&quot;:&quot;global&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;searchbar_input_global_navbar&quot;}"><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH"><span class="HeaderSearch-module__content__kMpxU"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-search HeaderSearch-module__icon__wcrHX" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path></svg><span class="HeaderSearch-module__label__d1iWG">Search</span><kbd class="HeaderSearch-module__kbd__HNG0o" aria-hidden="true">/</kbd></span></span></span></button><div class="d-none"></div></div><div class="AuthCTAs-module__signInWrap__q2P60"><a class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw AuthCTAs-module__cta__WpwQq AuthCTAs-module__desktopActionGap__UZuXT AuthCTAs-module__hiddenBelowLg__BfKBw" href="/login?return_to=https%3A%2F%2Fgithub.com%2Fcodewhale-hq%2FCodewhale%2Fblob%2Fmain%2Fdocs%2FTELEMETRY.md" data-analytics-event="{&quot;action&quot;:&quot;sign_in&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;auth_cta&quot;,&quot;location&quot;:&quot;header&quot;,&quot;label&quot;:&quot;sign_in_link_auth_cta_header&quot;}" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/codewhale-hq/Codewhale/blob/main/docs/TELEMETRY.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="4512a6a0748a88cf0189d958d154f077d9da7f0f8d5623516fbf40f6d515b205"><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH">Sign in</span></span></a></div><a class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--secondary___gHnw_ Primer_Brand__Button-module__Button--size-small___zQrEw AuthCTAs-module__cta__WpwQq" href="/signup?ref_cta=Sign+up&amp;ref_loc=header+logged+out&amp;ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fblob%2Fshow&amp;source=header-repo&amp;source_repo=codewhale-hq%2FCodewhale" data-analytics-event="{&quot;action&quot;:&quot;sign_up&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;auth_cta&quot;,&quot;location&quot;:&quot;header&quot;,&quot;label&quot;:&quot;sign_up_link_auth_cta_header&quot;}" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/codewhale-hq/Codewhale/blob/main/docs/TELEMETRY.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="4512a6a0748a88cf0189d958d154f077d9da7f0f8d5623516fbf40f6d515b205"><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-secondary___eJ0_a">Sign up</span></span></a><button class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw HeaderAppearanceSettings-module__trigger__hUheK" type="button" aria-haspopup="dialog" aria-labelledby="_R_fbd_"><span class="Primer_Brand__Button-module__Button__leading-visual___jjtTe" data-testid="Button-leading-visual"><svg data-component="Octicon" focusable="false" aria-hidden="true" class="octicon octicon-sliders Primer_Brand__Button-module__Button__icon-visual____qybb" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M15 2.75a.75.75 0 0 1-.75.75h-4a.75.75 0 0 1 0-1.5h4a.75.75 0 0 1 .75.75Zm-8.5.75v1.25a.75.75 0 0 0 1.5 0v-4a.75.75 0 0 0-1.5 0V2H1.75a.75.75 0 0 0 0 1.5H6.5Zm1.25 5.25a.75.75 0 0 0 0-1.5h-6a.75.75 0 0 0 0 1.5h6ZM15 8a.75.75 0 0 1-.75.75H11.5V10a.75.75 0 1 1-1.5 0V6a.75.75 0 0 1 1.5 0v1.25h2.75A.75.75 0 0 1 15 8Zm-9 5.25v-2a.75.75 0 0 0-1.5 0v1.25H1.75a.75.75 0 0 0 0 1.5H4.5v1.25a.75.75 0 0 0 1.5 0v-2Zm9 0a.75.75 0 0 1-.75.75h-6a.75.75 0 0 1 0-1.5h6a.75.75 0 0 1 .75.75Z"></path></svg></span><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH"></span></span></button><div class="Primer_Brand__Tooltip-module__Tooltip___0Eipx" data-direction="s" aria-hidden="true" id="_R_fbd_">Appearance settings</div></div></div></div></div><div class="MarketingHeader-module__bottomBorder__uZT38" aria-hidden="true"></div></header></div></div>
</react-partial>



      <div hidden="hidden" data-view-component="true" class="js-stale-session-flash stale-session-flash flash flash-warn flash-full">
  
        <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert">
    <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path>
</svg>
        <span class="js-stale-session-flash-signed-in" hidden>You signed in with another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span>
        <span class="js-stale-session-flash-signed-out" hidden>You signed out in another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span>
        <span class="js-stale-session-flash-switched" hidden>You switched accounts on another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span>

    <button id="icon-button-5c95ac77-8cda-4446-8a4a-4f7ad6504d2f" aria-labelledby="tooltip-df8ba9ea-8af3-4faf-902e-82af832a9e8c" type="button" data-view-component="true" class="Button Button--iconOnly Button--invisible Button--medium flash-close js-flash-close">  <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x Button-visual">
    <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path>
</svg>
</button><tool-tip id="tooltip-df8ba9ea-8af3-4faf-902e-82af832a9e8c" for="icon-button-5c95ac77-8cda-4446-8a4a-4f7ad6504d2f" popover="manual" data-direction="s" data-type="label" data-view-component="true" class="sr-only position-absolute">Dismiss alert</tool-tip>


  
</div>
    </div>

  <div id="start-of-content" class="show-on-focus"></div>








    <div id="js-flash-container" class="flash-container" data-turbo-replace>






  <template class="js-flash-template">
    
<div class="flash flash-full   {{ className }}">
  <div >
    <button autofocus class="flash-close js-flash-close" type="button" aria-label="Dismiss this message">
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x">
    <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path>
</svg>
    </button>
    <div aria-atomic="true" role="alert" class="js-flash-alert">
      
      <div>{{ message }}</div>

    </div>
  </div>
</div>
  </template>
</div>


    






  <div
    class="application-main "
    data-commit-hovercards-enabled
    data-discussion-hovercards-enabled
    data-issue-and-pr-hovercards-enabled
    data-project-hovercards-enabled
  >
        <div itemscope itemtype="http://schema.org/SoftwareSourceCode" class="">
    <main id="js-repo-pjax-container" >
      
      
    


    








  

    <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ym-6bc2c9bf8112c038.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/sk2-8deeef9351be3911.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ni-3e194d222c7770bf.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/7x-71d30cb240cd901f.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/wwk-ad869086822937b1.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/a1-9f79841ecac1da8e.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/wzg-40a3213b3e83400b.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/5f-64f8e7d5bcbd4787.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/z5-b53a93078d026f1e.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/8h-cef26f68c1331011.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/fq-3ce13a77e863807a.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/a7-596b507bd20acddc.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/xfx-c82d8352413aea0a.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/j4-b3a9e87fa7878a98.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/global-nav-bar-29c7aef68ee9db41.js" fetchpriority="low" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.2d881b4d4a503d1c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/pj.75627bfeb9ceb1da.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/global-nav-bar.2f2560cba06ab359.module.css" />

<react-partial
  partial-name="global-nav-bar"
  data-ssr="true"
  data-attempted-ssr="true"
  data-react-profiling="false"
>
  
  <script type="application/json" data-target="react-partial.embeddedData">{"props":{"contextRegion":{"crumbs":[{"crumb_type":"organization","label":"codewhale-hq","is_root":false,"href":"/codewhale-hq"},{"crumb_type":"repository","label":"Codewhale","is_root":false,"href":"/codewhale-hq/Codewhale"}],"localNavigation":[{"id":"code","icon":"code","label":"Code","href":"/codewhale-hq/Codewhale","selectedLinks":["repo_source","repo_downloads","repo_commits","repo_releases","repo_tags","repo_branches","repo_packages","repo_deployments","repo_attestations"],"popoverTarget":false,"commandId":"repositories:go-to-code","reactNav":{"appTarget":"code-view","anchor":"code-view-repo-link"},"turboNav":{"frame":"repo-content-turbo-frame"}},{"id":"issues","icon":"issue-opened","label":"Issues","href":"/codewhale-hq/Codewhale/issues","selectedLinks":["repo_issues","repo_labels","repo_milestones"],"count":196,"popoverTarget":false,"commandId":"repositories:go-to-issues","reactNav":{"appTarget":"repo","anchor":null},"turboNav":{"frame":"repo-content-turbo-frame"}},{"id":"pull-requests","icon":"git-pull-request","label":"Pull requests","href":"/codewhale-hq/Codewhale/pulls","selectedLinks":["repo_pulls","checks"],"count":16,"popoverTarget":false,"commandId":"repositories:go-to-pull-requests","reactNav":{"appTarget":null,"anchor":null},"turboNav":{"frame":"repo-content-turbo-frame"}},{"id":"discussions","icon":"comment-discussion","label":"Discussions","href":"/codewhale-hq/Codewhale/discussions","selectedLinks":["repo_discussions"],"popoverTarget":false,"commandId":"repositories:go-to-discussions","reactNav":{"appTarget":null,"anchor":null},"turboNav":{"frame":"repo-content-turbo-frame"}},{"id":"actions","icon":"play","label":"Actions","href":"/codewhale-hq/Codewhale/actions","selectedLinks":["repo_actions"],"popoverTarget":false,"commandId":"repositories:go-to-actions","reactNav":{"appTarget":"actions-workflows","anchor":null},"turboNav":{"frame":"repo-content-turbo-frame"}},{"id":"projects","icon":"table","label":"Projects","href":"/codewhale-hq/Codewhale/projects","selectedLinks":["repo_projects","new_repo_project","repo_project"],"popoverTarget":false,"commandId":"repositories:go-to-projects","reactNav":{"appTarget":"repo","anchor":null},"turboNav":{"frame":"repo-content-turbo-frame"}},{"id":"security-and-quality","icon":"shield","label":"Security and quality","href":"/codewhale-hq/Codewhale/security","selectedLinks":["security","overview","alerts","policy","token_scanning","code_scanning"],"count":13,"popoverTarget":false,"commandId":"repositories:go-to-security","reactNav":{"appTarget":null,"anchor":null},"turboNav":{"frame":"repo-content-turbo-frame"}},{"id":"insights","icon":"graph","label":"Insights","href":"/codewhale-hq/Codewhale/pulse","selectedLinks":["repo_graphs","repo_contributors","dependency_graph","dependabot_updates","pulse","people","community"],"popoverTarget":false,"commandId":"repositories:go-to-insights","reactNav":{"appTarget":null,"anchor":null},"turboNav":{"frame":"repo-content-turbo-frame"}}],"localNavigationUpdateChannel":null,"selectedLink":"repo_source"},"owner":null,"headerLogo":{"href":"/","aria-label":"Homepage "},"notifications":{"indicatorMode":"disabled","websocketChannel":null,"fetchIndicatorSrc":"/notifications/indicator","fetchIndicatorEnabled":false},"issues":{"href":"/issues"},"pulls":{"href":"/pulls"},"contributedRepos":{"href":"/repos"},"copilot":{"show":false,"showAgentsButton":false,"showRelaunchAnnouncement":false,"copilotChatUrl":null,"copilotApiUrl":"https://api.githubcopilot.com"},"search":{"show":true,"showCommandPalette":false,"isSearchPage":false,"isJumpToSearch":false,"searchContext":{"scope":"repo:codewhale-hq/Codewhale","current_repo_name":"Codewhale","current_repo_nwo":"codewhale-hq/Codewhale","current_repo_org":"codewhale-hq","user_id":"codewhale-hq"}},"commandPalette":null,"enterpriseBar":{"show":false},"globalTransactionalMessage":[],"payloadsUrl":"/_global-navigation/payloads.json?can_toggle_site_admin_and_employee_status=0\u0026is_admin_mode_on=0\u0026is_ui_opted_out=0\u0026show_ui_opt_out=0\u0026v=7","contextRegionUrl":"/_global-navigation/context-region.json"}}</script>
  <div data-target="react-partial.reactRoot"><header aria-label="Global navigation menu" data-component="Stack" class="GlobalNav styles-module__appHeader__YzYWk prc-Stack-Stack-UQ9k6" data-gap="none" data-direction="vertical" data-align="stretch" data-wrap="nowrap" data-justify="start" data-padding="none"><div data-component="Stack" class="prc-Stack-Stack-UQ9k6" data-direction="horizontal" data-align="center" data-wrap="nowrap" data-justify="center" data-padding="none"><div data-testid="top-nav-center" data-component="Stack" class="styles-module__center__R3QRv styles-module__withLocalNavigation__rjTJ_ GlobalNavBar-module__loggedOut__Jv1rk prc-Stack-Stack-UQ9k6" data-gap="condensed" data-direction="horizontal" data-align="stretch" data-wrap="nowrap" data-justify="start" data-padding="normal"><nav class="styles-module__contextRegion__VbSp2 prc-Breadcrumbs-BreadcrumbsBase-3Gb-B" aria-label="Breadcrumbs" data-overflow="menu" data-variant="normal" data-component="Breadcrumbs"><ol class="prc-Breadcrumbs-BreadcrumbsList-BKjpe"><li class="prc-Breadcrumbs-ItemWrapper-k0NLn"><a class="styles-module__contextCrumb__IzGIq prc-Breadcrumbs-Item-jcraJ" data-component="Breadcrumbs.Item" href="/codewhale-hq" data-discover="true"><span class="">codewhale-hq</span></a></li><li class="prc-Breadcrumbs-ItemWrapper-k0NLn"><a class="styles-module__contextCrumb__IzGIq prc-Breadcrumbs-Item-jcraJ" data-component="Breadcrumbs.Item" href="/codewhale-hq/Codewhale" data-discover="true"><span class="styles-module__contextCrumbLast__tI2e3">Codewhale</span></a></li></ol></nav></div><div data-testid="top-nav-right" data-component="Stack" class="styles-module__right__mlBQg styles-module__withLocalNavigation__rjTJ_ styles-module__rightWithResponsiveCreateButton__SKn2W prc-Stack-Stack-UQ9k6" data-gap="condensed" data-direction="horizontal" data-align="center" data-wrap="nowrap" data-justify="start" data-padding="normal"></div></div><h2 class="prc-src-InternalVisuallyHidden-2YaI6">Repository navigation</h2><nav class="prc-components-UnderlineWrapper-eT-Yj prc-UnderlineNav-UnderlineWrapper-GWONT LocalNavigation-module__LocalNavigation__b0Xc0" aria-label="Repository" data-variant="inset" data-overflow-mode="wrap" data-hide-icons-breakpoint="medium"><ul class="prc-UnderlineNav-ItemsList-oj8gN prc-components-UnderlineItemList-xKlKC" role="list"><li role="presentation" aria-hidden="true" class="prc-UnderlineNav-WrapSpacer--aLgz"></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a aria-current="page" data-tab-item="code" data-react-nav="code-view" data-react-nav-anchor="code-view-repo-link" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/codewhale-hq/Codewhale" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-code" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path></svg></span><span data-component="text" data-content="Code">Code</span></a></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a data-tab-item="issues" data-react-nav="repo" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/codewhale-hq/Codewhale/issues" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-issue-opened" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"></path></svg></span><span data-component="text" data-content="Issues">Issues</span><span data-component="counter"><span aria-hidden="true" data-variant="secondary" data-component="CounterLabel" class="prc-CounterLabel-CounterLabel-X-kRU">196</span><span class="prc-VisuallyHidden-VisuallyHidden-Q0qSB"> (<!-- -->196<!-- -->)</span></span></a></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a data-tab-item="pull-requests" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/codewhale-hq/Codewhale/pulls" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-git-pull-request" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.25.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Z"></path></svg></span><span data-component="text" data-content="Pull requests">Pull requests</span><span data-component="counter"><span aria-hidden="true" data-variant="secondary" data-component="CounterLabel" class="prc-CounterLabel-CounterLabel-X-kRU">16</span><span class="prc-VisuallyHidden-VisuallyHidden-Q0qSB"> (<!-- -->16<!-- -->)</span></span></a></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a data-tab-item="discussions" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/codewhale-hq/Codewhale/discussions" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-comment-discussion" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1h8.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 10.25 10H7.061l-2.574 2.573A1.458 1.458 0 0 1 2 11.543V10h-.25A1.75 1.75 0 0 1 0 8.25v-5.5C0 1.784.784 1 1.75 1ZM1.5 2.75v5.5c0 .138.112.25.25.25h1a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13 2a.25.25 0 0 0-.25-.25h-.5a.75.75 0 0 1 0-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 12H14v1.543a1.458 1.458 0 0 1-2.487 1.03L9.22 12.28a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l2.22 2.22v-2.19a.75.75 0 0 1 .75-.75h1a.25.25 0 0 0 .25-.25Z"></path></svg></span><span data-component="text" data-content="Discussions">Discussions</span></a></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a data-tab-item="actions" data-react-nav="actions-workflows" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/codewhale-hq/Codewhale/actions" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-play" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"></path></svg></span><span data-component="text" data-content="Actions">Actions</span></a></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a data-tab-item="projects" data-react-nav="repo" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/codewhale-hq/Codewhale/projects" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-table" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25ZM6.5 6.5v8h7.75a.25.25 0 0 0 .25-.25V6.5Zm8-1.5V1.75a.25.25 0 0 0-.25-.25H6.5V5Zm-13 1.5v7.75c0 .138.112.25.25.25H5v-8ZM5 5V1.5H1.75a.25.25 0 0 0-.25.25V5Z"></path></svg></span><span data-component="text" data-content="Projects">Projects</span></a></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a data-tab-item="security-and-quality" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/codewhale-hq/Codewhale/security" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-shield" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M7.467.133a1.748 1.748 0 0 1 1.066 0l5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667Zm.61 1.429a.25.25 0 0 0-.153 0l-5.25 1.68a.25.25 0 0 0-.174.238V7c0 1.358.275 2.666 1.057 3.86.784 1.194 2.121 2.34 4.366 3.297a.196.196 0 0 0 .154 0c2.245-.956 3.582-2.104 4.366-3.298C13.225 9.666 13.5 8.36 13.5 7V3.48a.251.251 0 0 0-.174-.237l-5.25-1.68ZM8.75 4.75v3a.75.75 0 0 1-1.5 0v-3a.75.75 0 0 1 1.5 0ZM9 10.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path></svg></span><span data-component="text" data-content="Security and quality">Security and quality</span><span data-component="counter"><span aria-hidden="true" data-variant="secondary" data-component="CounterLabel" class="prc-CounterLabel-CounterLabel-X-kRU">13</span><span class="prc-VisuallyHidden-VisuallyHidden-Q0qSB"> (<!-- -->13<!-- -->)</span></span></a></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a data-tab-item="insights" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/codewhale-hq/Codewhale/pulse" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-graph" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.5 1.75V13.5h13.75a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1-.75-.75V1.75a.75.75 0 0 1 1.5 0Zm14.28 2.53-5.25 5.25a.75.75 0 0 1-1.06 0L7 7.06 4.28 9.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.25-3.25a.75.75 0 0 1 1.06 0L10 7.94l4.72-4.72a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path></svg></span><span data-component="text" data-content="Insights">Insights</span></a></li></ul><div class="prc-UnderlineNav-MoreButtonContainer-Dnrq6"><div class="prc-UnderlineNav-MoreButtonDivider-dN0a-"></div><button data-component="overflow-menu-button" type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-9n-Xk prc-UnderlineNav-MoreButton-Y8soj" data-loading="false" data-size="medium" data-variant="invisible" id="_R_2ktp_"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="text" class="prc-Button-Label-FWkx3"><span>More<span class="prc-src-InternalVisuallyHidden-2YaI6"> items</span></span></span></span><span data-component="trailingAction" class="prc-Button-Visual-YNt2F prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-down" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path></svg></span></button></div></nav><div class="d-none"></div></header></div>
</react-partial>


  



<turbo-frame id="repo-content-turbo-frame" target="_top" data-turbo-action="advance" class="">
    <div id="repo-content-pjax-container" class="repository-content " >
    



    
      
    








<react-app
  app-name="code-view"
  initial-path="/codewhale-hq/Codewhale/blob/main/docs/TELEMETRY.md"
  style="display: block; min-height: calc(100vh - 64px);"
  data-attempted-ssr="true"
  data-ssr="true"
  data-lazy="false"
  data-alternate="false"
  data-data-router-enabled="true"
  data-react-profiling="false"
>
  
  <script type="application/json" data-target="react-app.embeddedData">{"payload":{"codeViewBlobRoute":{"csv":null,"csvError":null,"headerInfo":{"toc":[{"level":1,"text":"Codewhale product telemetry","anchor":"codewhale-product-telemetry","htmlText":"Codewhale product telemetry"},{"level":2,"text":"Turning it off","anchor":"turning-it-off","htmlText":"Turning it off"},{"level":2,"text":"Where it lives, and how much of your disk it uses","anchor":"where-it-lives-and-how-much-of-your-disk-it-uses","htmlText":"Where it lives, and how much of your disk it uses"},{"level":2,"text":"When anything is sent, and where","anchor":"when-anything-is-sent-and-where","htmlText":"When anything is sent, and where"},{"level":2,"text":"Event schema","anchor":"event-schema","htmlText":"Event schema"},{"level":3,"text":"Batch envelope — sent on every POST","anchor":"batch-envelope--sent-on-every-post","htmlText":"Batch envelope — sent on every POST"},{"level":3,"text":"Which surfaces emit","anchor":"which-surfaces-emit","htmlText":"Which surfaces emit"},{"level":3,"text":"An embedder declares the server it started","anchor":"an-embedder-declares-the-server-it-started","htmlText":"An embedder declares the server it started"},{"level":3,"text":"Event: install_or_upgrade","anchor":"event-install_or_upgrade","htmlText":"Event: install_or_upgrade"},{"level":3,"text":"Event: session_start","anchor":"event-session_start","htmlText":"Event: session_start"},{"level":3,"text":"Event: session_end","anchor":"event-session_end","htmlText":"Event: session_end"},{"level":3,"text":"Event: panic","anchor":"event-panic","htmlText":"Event: panic"},{"level":3,"text":"Event: product_usage","anchor":"event-product_usage","htmlText":"Event: product_usage"},{"level":3,"text":"Event: operations_summary","anchor":"event-operations_summary","htmlText":"Event: operations_summary"},{"level":3,"text":"What the endpoint does — a shipping gate, not a footnote","anchor":"what-the-endpoint-does--a-shipping-gate-not-a-footnote","htmlText":"What the endpoint does — a shipping gate, not a footnote"},{"level":3,"text":"What the owner reads back — observed active installs","anchor":"what-the-owner-reads-back--observed-active-installs","htmlText":"What the owner reads back — observed active installs"},{"level":3,"text":"What is never collected — the public red-line list","anchor":"what-is-never-collected--the-public-red-line-list","htmlText":"What is never collected — the public red-line list"}]},"issueTemplate":null,"discussionTemplate":null,"richText":"\u003carticle class=\"markdown-body entry-content container-lg\" itemprop=\"text\"\u003e\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch1 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCodewhale product telemetry\u003c/h1\u003e\u003ca id=\"user-content-codewhale-product-telemetry\" class=\"anchor\" aria-label=\"Permalink: Codewhale product telemetry\" href=\"#codewhale-product-telemetry\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003e阅读简体中文版：\u003ca href=\"/codewhale-hq/Codewhale/blob/main/docs/zh_hans/TELEMETRY.md\"\u003ezh_hans/TELEMETRY.md\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eUsage analytics are on by default in the current source.\u003c/strong\u003e The first\ninteractive launch gives a localized, nonblocking disclosure naming \u003cstrong\u003eCodewhale\nand PostHog\u003c/strong\u003e, with a direct route to turn counting off. Notice version \u003ccode\u003e5\u003c/code\u003e\ndescribes this policy; displaying it is not recorded as human acceptance.\nMissing an older acceptance record does not turn a fresh installation off.\nExisting explicit opt-outs remain off across upgrades, and unreadable privacy\nstate fails closed. Environment and CLI kill switches still take precedence.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eRead the disclosure with \u003ccode\u003ecodewhale config telemetry\u003c/code\u003e. Turn usage off in\n\u003ccode\u003e/settings\u003c/code\u003e or run \u003ccode\u003ecodewhale config set telemetry false\u003c/code\u003e. Turning it back on\nin Settings or with \u003ccode\u003ecodewhale config set telemetry true\u003c/code\u003e updates the existing\ndurable preference and privacy records for new sessions. The compatibility\ncommand \u003ccode\u003ecodewhale config telemetry --accept-notice 5\u003c/code\u003e remains available, but\nis not required for a fresh installation. Collection never includes work content or credentials.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe PostHog sink is optional and inert until the ingest operator explicitly\nconfigures a project token and approved regional host, and records staging\nproof that the actual egress path does not forward the original client IP.\nSource readiness does not establish a deployment, an activated processor,\nan egress receipt, or a retention setting.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eCodewhale does not collect conversations, code, prompts, files, file/repo/branch\nnames, model content, or credentials. It sends no per-turn or per-tool timeline.\nIt does send the closed, aggregate schema below: version and platform classes,\nsession duration/outcome, feature/error counters, and a random install id that\nrotates every 90 days.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eThere is now a real endpoint.\u003c/strong\u003e An enabled session sends its batches to the\nfirst-party ingest service at \u003ccode\u003ehttps://telemetry.codewhale.net/v1/telemetry\u003c/code\u003e,\nwhich is the shipped default for \u003ccode\u003etelemetry_endpoint\u003c/code\u003e. What that service is,\nwhat it stores, and what it structurally cannot store is spelled out in \"What\nthe endpoint does\" below.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eTo send nothing anywhere, turn telemetry off\u003c/strong\u003e (see \"Turning it off\"). To stay\nenabled but contact nobody, set \u003ccode\u003etelemetry_endpoint = \"\"\u003c/code\u003e: batches are then\nappended to \u003ccode\u003e$CODEWHALE_HOME/telemetry/dryrun.jsonl\u003c/code\u003e on your own machine, byte\nfor byte what the server would have received, and no HTTP client is ever\nconstructed. That file is how you audit this document against reality.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThis document is the schema. It is not a summary of the schema: a test in\n\u003ccode\u003ecrates/telemetry\u003c/code\u003e parses the field names out of this file and asserts set\nequality against the structs the serializer actually uses, so a field that is\nhere and not in the code — or in the code and not here — fails the build.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eLocal saved sessions and \u003ccode\u003ecodewhale metrics\u003c/code\u003e remain available with telemetry\ndisabled and require no account or hosted reporting service. Disabling telemetry\ndoes not disable local usage receipts.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eTurning it off\u003c/h2\u003e\u003ca id=\"user-content-turning-it-off\" class=\"anchor\" aria-label=\"Permalink: Turning it off\" href=\"#turning-it-off\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThere are two off switches and they do different things. Both stop collection\ncompletely; only one of them erases anything.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"codewhale config set telemetry false     # opt out: stops collection and erases state\nCODEWHALE_TELEMETRY=0 codewhale          # kill switch: stops collection, erases nothing\ncodewhale --telemetry false              # the same kill switch, for one command\"\u003e\u003cpre\u003ecodewhale config \u003cspan class=\"pl-c1\"\u003eset\u003c/span\u003e telemetry \u003cspan class=\"pl-c1\"\u003efalse\u003c/span\u003e     \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e opt out: stops collection and erases state\u003c/span\u003e\nCODEWHALE_TELEMETRY=0 codewhale          \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e kill switch: stops collection, erases nothing\u003c/span\u003e\ncodewhale --telemetry \u003cspan class=\"pl-c1\"\u003efalse\u003c/span\u003e              \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e the same kill switch, for one command\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003e\u003ccode\u003etelemetry = false\u003c/code\u003e in the config file is the opt-out.\u003c/strong\u003e It is a floor:\n\u003ccode\u003e--telemetry true\u003c/code\u003e and \u003ccode\u003eCODEWHALE_TELEMETRY=1\u003c/code\u003e both lose to it, because a\nsetting you can undo by accident from a wrapper script is not a setting. It\ndeletes the random install id, truncates every buffered event and every dry-run\nrecord, and writes a tombstone. Appends, identity/state writes, and delivery all\nshare the wipe's ordering lock, so once opt-out returns no pre-opt-out write or\nPOST remains in flight. If any part of that wipe fails, the tombstone is still\nthere and the buffer is undrainable — a failed wipe fails closed. Every later\nrun re-asserts the same tombstone for as long as the setting stands, so it\nsurvives. Turning telemetry back on in \u003ccode\u003e/settings\u003c/code\u003e records that explicit preference\nin both existing privacy registers; a fresh launch can then clear the tombstone. Nothing buffered before that point is\never sent.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eThe environment variable and the flag are kill switches, not opt-outs.\u003c/strong\u003e\nTelemetry is off for the run, nothing is written, nothing is sent — and\nnothing on disk is touched or deleted. That is deliberate: a harness or agent\nthat sets \u003ccode\u003eCODEWHALE_TELEMETRY=0\u003c/code\u003e for one command must not silently discard the\ninstall id and the dry-run records of the person who owns the machine. If you\nwant the erasing kind, use the config file.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003eCODEWHALE_TELEMETRY\u003c/code\u003e (and its \u003ccode\u003eDEEPSEEK_TELEMETRY\u003c/code\u003e alias) accepts\n\u003ccode\u003e0\u003c/code\u003e, \u003ccode\u003e1\u003c/code\u003e, \u003ccode\u003etrue\u003c/code\u003e, \u003ccode\u003efalse\u003c/code\u003e, \u003ccode\u003eyes\u003c/code\u003e, \u003ccode\u003eno\u003c/code\u003e, \u003ccode\u003eon\u003c/code\u003e, \u003ccode\u003eoff\u003c/code\u003e, \u003ccode\u003eenabled\u003c/code\u003e, \u003ccode\u003edisabled\u003c/code\u003e.\nA value this list cannot read also resolves to off — a typo in a kill switch\nmust never resolve to \"on\".\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe first-run notice is not shown when telemetry is already persistently off or\na run-scoped kill switch is active. The notice never rewrites a\n\u003ccode\u003etelemetry = false\u003c/code\u003e you put there yourself.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eA repo-local \u003ccode\u003e.codewhale/config.toml\u003c/code\u003e can set neither \u003ccode\u003etelemetry\u003c/code\u003e nor\n\u003ccode\u003etelemetry_endpoint\u003c/code\u003e, and a workspace \u003ccode\u003e.env\u003c/code\u003e can set neither. Someone else's\nrepository cannot turn your telemetry on or aim it at a host of their choosing.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWhere it lives, and how much of your disk it uses\u003c/h2\u003e\u003ca id=\"user-content-where-it-lives-and-how-much-of-your-disk-it-uses\" class=\"anchor\" aria-label=\"Permalink: Where it lives, and how much of your disk it uses\" href=\"#where-it-lives-and-how-much-of-your-disk-it-uses\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eEverything is under \u003ccode\u003e$CODEWHALE_HOME/telemetry/\u003c/code\u003e (\u003ccode\u003e0700\u003c/code\u003e), every file \u003ccode\u003e0600\u003c/code\u003e:\u003c/p\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003efile\u003c/th\u003e\n\u003cth\u003erole\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ebuffer.jsonl\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003epending events, one JSON object per line\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ebuffer.jsonl.lock\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003ethe sibling ordering lock shared by writes, delivery, arming, and wipe\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003edryrun.jsonl\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003ewhere batches go when the endpoint is configured empty\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003estate.json\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003ethe last app version seen and the last flush attempt\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003einstall_id.json\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003ethe random install id and when it was minted\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003edisabled\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003ethe tombstone; present means nothing is appended or sent\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cp dir=\"auto\"\u003eBoth \u003ccode\u003ebuffer.jsonl\u003c/code\u003e and \u003ccode\u003edryrun.jsonl\u003c/code\u003e are rings capped at 512 records or\n256 KiB, whichever comes first, with the oldest dropped. The documented\nfootprint ceiling for the whole directory is therefore \u003cstrong\u003e512 KiB plus a few\nhundred bytes of metadata\u003c/strong\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe install id is a random v4 UUID. It is never derived from your hostname,\nMAC address, \u003ccode\u003emachine-id\u003c/code\u003e, home directory, username, or executable path — a\nderived id is a device fingerprint that survives reinstall and re-identifies\nyou across your own opt-out. It is regenerated whenever\n\u003ccode\u003e$CODEWHALE_HOME/telemetry/\u003c/code\u003e is cleared, which opting out does automatically,\nand in any case every 90 days.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThere is no factory-reset command in Codewhale, so this document does not\nclaim one.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWhen anything is sent, and where\u003c/h2\u003e\u003ca id=\"user-content-when-anything-is-sent-and-where\" class=\"anchor\" aria-label=\"Permalink: When anything is sent, and where\" href=\"#when-anything-is-sent-and-where\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNothing is collected or sent when a persistent opt-out or run-scoped kill\nswitch is in force, or when privacy state is unreadable. TUI and \u003ccode\u003eexec\u003c/code\u003e sessions have exactly one network flush point: an attempt\nduring shutdown, bounded at three seconds. Short CLI commands such as \u003ccode\u003econfig\u003c/code\u003e,\n\u003ccode\u003edoctor\u003c/code\u003e, and \u003ccode\u003eauth\u003c/code\u003e do not wait for that network request. They record\n\u003ccode\u003esession_end\u003c/code\u003e, seal the event to the local buffer with a much shorter bound, and\nreturn; a configured endpoint sends those buffered events with the next\ninteractive shutdown flush. An explicitly empty endpoint finalizes its local\ndry-run batch immediately.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThere is no startup flush, mid-session flush, per-turn flush, or per-tool-call\nflush. Every network shutdown flush re-resolves your setting from disk\nimmediately beforehand, so \u003ccode\u003ecodewhale config set telemetry false\u003c/code\u003e written from\nanother terminal stops the flush of a session that is already running.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eA flush is \u003cstrong\u003eone \u003ccode\u003ePOST\u003c/code\u003e\u003c/strong\u003e to the resolved endpoint — by default\n\u003ccode\u003ehttps://telemetry.codewhale.net/v1/telemetry\u003c/code\u003e. The request carries a\n\u003ccode\u003econtent-type: application/json\u003c/code\u003e header, a\n\u003ccode\u003euser-agent: codewhale-telemetry/\u0026lt;app_version\u0026gt;\u003c/code\u003e, and the batch body. That is\nall: no cookies (the HTTP client is built without a cookie jar to disable), no\nredirects (refused outright), no \u003ccode\u003eAuthorization\u003c/code\u003e header, no custom headers, and\nno query string. The response body is discarded unread; only the status class is\nlooked at.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003ehttps://\u003c/code\u003e is required. Plain \u003ccode\u003ehttp://\u003c/code\u003e is accepted only for a loopback host, so\nyou can point the client at a recorder of your own and read the wire form\ndirectly; no environment variable overrides that refusal. An endpoint the client\nrefuses turns telemetry off for the run rather than falling back to a different\ndestination.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eAny failure — DNS, connect, TLS, timeout, non-2xx — drops the batch. There is\nno retry, no backoff, and no re-queue. A permanently offline machine attempts at\nmost once per flush point and never grows a queue.\u003c/p\u003e\n\u003chr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eEvent schema\u003c/h2\u003e\u003ca id=\"user-content-event-schema\" class=\"anchor\" aria-label=\"Permalink: Event schema\" href=\"#event-schema\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003eSCHEMA_VERSION = 3\u003c/code\u003e. \u003ccode\u003enotice_version = 5\u003c/code\u003e identifies the disclosed default-on\npolicy; it does not assert human consent or that a notice was seen. The closed\nv2 contract still accepts only \u003ccode\u003econsent_version = 4\u003c/code\u003e, retaining its original\nexplicit opt-in meaning. Fields cannot be mixed between versions. The unchanged\nv1 contract remains first-party only and \u003cstrong\u003enever sent to PostHog\u003c/strong\u003e; it refuses\nnew fields, surfaces, and \u003ccode\u003eproduct_usage\u003c/code\u003e events.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eEvery field is an integer, a boolean, or a \u003cstrong\u003eclosed enum string\u003c/strong\u003e, except exactly three bounded strings: \u003ccode\u003eapp_version\u003c/code\u003e, \u003ccode\u003egit_sha\u003c/code\u003e, \u003ccode\u003epanic_site\u003c/code\u003e. Each of the three has a written rule and a test pinning the rule. \u003cstrong\u003eThere is no free-form string type in this schema, and no open-keyed map.\u003c/strong\u003e That is the property that makes red line 3 enforceable rather than aspirational.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eBatch envelope — sent on every POST\u003c/h3\u003e\u003ca id=\"user-content-batch-envelope--sent-on-every-post\" class=\"anchor\" aria-label=\"Permalink: Batch envelope — sent on every POST\" href=\"#batch-envelope--sent-on-every-post\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-json-comments notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"{\n  \u0026quot;schema_version\u0026quot;: 3,\n  \u0026quot;notice_version\u0026quot;: 5,\n  \u0026quot;sent_at\u0026quot;:     \u0026quot;2026-08-03T18:04:11Z\u0026quot;,   // RFC3339 UTC, second precision\n  \u0026quot;install_id\u0026quot;:  \u0026quot;3f2a…\u0026quot;,                  // uuid v4, rotates every 90 days\n  \u0026quot;app_version\u0026quot;: \u0026quot;0.9.12\u0026quot;,\n  \u0026quot;git_sha\u0026quot;:     null,                     // non-null only for SHA-stamped builds\n  \u0026quot;surface\u0026quot;:     \u0026quot;tui\u0026quot;,\n  \u0026quot;os\u0026quot;:          \u0026quot;macos\u0026quot;,\n  \u0026quot;arch\u0026quot;:        \u0026quot;aarch64\u0026quot;,\n  \u0026quot;libc\u0026quot;:        \u0026quot;none\u0026quot;,\n  \u0026quot;tty\u0026quot;:         true,\n  \u0026quot;events\u0026quot;:      [ … ]\n}\"\u003e\u003cpre\u003e{\n  \u003cspan class=\"pl-ent\"\u003e\"schema_version\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e,\n  \u003cspan class=\"pl-ent\"\u003e\"notice_version\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e5\u003c/span\u003e,\n  \u003cspan class=\"pl-ent\"\u003e\"sent_at\"\u003c/span\u003e:     \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e2026-08-03T18:04:11Z\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,   \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e RFC3339 UTC, second precision\u003c/span\u003e\n  \u003cspan class=\"pl-ent\"\u003e\"install_id\"\u003c/span\u003e:  \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e3f2a…\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,                  \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e uuid v4, rotates every 90 days\u003c/span\u003e\n  \u003cspan class=\"pl-ent\"\u003e\"app_version\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e0.9.12\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n  \u003cspan class=\"pl-ent\"\u003e\"git_sha\"\u003c/span\u003e:     \u003cspan class=\"pl-c1\"\u003enull\u003c/span\u003e,                     \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e non-null only for SHA-stamped builds\u003c/span\u003e\n  \u003cspan class=\"pl-ent\"\u003e\"surface\"\u003c/span\u003e:     \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003etui\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n  \u003cspan class=\"pl-ent\"\u003e\"os\"\u003c/span\u003e:          \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003emacos\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n  \u003cspan class=\"pl-ent\"\u003e\"arch\"\u003c/span\u003e:        \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eaarch64\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n  \u003cspan class=\"pl-ent\"\u003e\"libc\"\u003c/span\u003e:        \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003enone\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n  \u003cspan class=\"pl-ent\"\u003e\"tty\"\u003c/span\u003e:         \u003cspan class=\"pl-c1\"\u003etrue\u003c/span\u003e,\n  \u003cspan class=\"pl-ent\"\u003e\"events\"\u003c/span\u003e:      [ \u003cspan class=\"pl-ii\"\u003e…\u003c/span\u003e ]\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eField\u003c/th\u003e\n\u003cth\u003eType\u003c/th\u003e\n\u003cth\u003eSource anchor\u003c/th\u003e\n\u003cth\u003eRule\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eschema_version\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eu32\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003econst in \u003ccode\u003ecrates/telemetry/src/event.rs\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eBumped on any field add/remove/retype. Never reused. Pinned by a golden snapshot test.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003enotice_version\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eu32\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003epolicy constant in \u003ccode\u003ecrates/telemetry/src/event.rs\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eExactly \u003ccode\u003e5\u003c/code\u003e; identifies the disclosed opt-out policy, not a human acceptance record.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003esent_at\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eRFC3339\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003echrono::Utc::now()\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eSecond precision. Per-\u003cstrong\u003ebatch\u003c/strong\u003e only — events carry no timestamps at all.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003einstall_id\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003euuid v4\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003ecrates/telemetry/src/envelope.rs\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eRandom, never derived, rotated every 90 days. See \"Where it lives\" above.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eapp_version\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eenv!(\"CARGO_PKG_VERSION\")\u003c/code\u003e, as at \u003ccode\u003ecrates/telemetry/src/lib.rs:112\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eMust match \u003ccode\u003e^\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z.]+)?$\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003egit_sha\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003estring | null\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eoption_env!(\"CODEWHALE_RELEASE_BUILD_SHA\")\u003c/code\u003e — a \u003cstrong\u003enew\u003c/strong\u003e rustc-env\u003c/td\u003e\n\u003ctd\u003eFirst 12 hex chars. Emitted \u003cstrong\u003eonly\u003c/strong\u003e when \u003ccode\u003ecodewhale_build_support::release_build_sha\u003c/code\u003e saw a valid full SHA in \u003ccode\u003eCODEWHALE_BUILD_SHA\u003c/code\u003e, the legacy \u003ccode\u003eDEEPSEEK_BUILD_SHA\u003c/code\u003e, or \u003ccode\u003eGITHUB_SHA\u003c/code\u003e, in that precedence order. \u003ccode\u003enull\u003c/code\u003e for every unstamped build, with no runtime lookup of any kind. \u003cstrong\u003eNever\u003c/strong\u003e \u003ccode\u003eCODEWHALE_BUILD_COMMIT\u003c/code\u003e — that falls back to \u003ccode\u003egit_commit\u003c/code\u003e and is the builder's private HEAD. \u003cstrong\u003eNever\u003c/strong\u003e \u003ccode\u003eThread.git_sha\u003c/code\u003e (\u003ccode\u003ecrates/state/src/lib.rs:93\u003c/code\u003e) — that is the user's workspace commit and a red line, one identifier away by name.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003esurface\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eenum\u003c/td\u003e\n\u003ctd\u003eexplicitly set by the emitting client\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003etui | exec | cli | app-server | mcp-server | serve | website | web-app | desktop | control-plane | vscode-extension\u003c/code\u003e. Runtime metrics keep their existing collector. Browser product counts use the same closed envelope. A declared surface is not proof its client is deployed. \u003ccode\u003evscode-extension\u003c/code\u003e is an extension client of this schema, deliberately generic the way \u003ccode\u003eweb-app\u003c/code\u003e and \u003ccode\u003edesktop\u003c/code\u003e are: the editor's own name and version are \u003cstrong\u003enot\u003c/strong\u003e collected. Widening this whitelist changes no field, so the schema version is unchanged.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eos\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eenum\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003estd::env::consts::OS\u003c/code\u003e, as at \u003ccode\u003ecrates/cli/src/update.rs:41\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eWhitelist: \u003ccode\u003elinux | macos | windows | freebsd | android | other\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003earch\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eenum\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003estd::env::consts::ARCH\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003ex86_64 | aarch64 | other\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003elibc\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eenum\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003ecfg!(target_env)\u003c/code\u003e — \u003cstrong\u003ecompile time\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003egnu | musl | none\u003c/code\u003e. Runtime detection reads distro vendor strings; compile-time is free and leaks nothing.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003etty\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003ebool\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003estd::io::IsTerminal\u003c/code\u003e, as at \u003ccode\u003ecrates/telemetry/src/envelope.rs:196\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003estdin().is_terminal() \u0026amp;\u0026amp; stdout().is_terminal()\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eevents\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003earray\u003c/td\u003e\n\u003ctd\u003ethe drained buffer\u003c/td\u003e\n\u003ctd\u003eEvery element is one of the six events below and nothing else. Capped at 200 events or 64 KiB per batch; a batch that would exceed either cap leaves the remainder buffered for the next flush.\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003e\u003ccode\u003eos_major\u003c/code\u003e is not collected.\u003c/strong\u003e Reading it costs unsafe FFI on two platforms plus a file parser on a third, in the one crate whose entire value is being small enough to audit — and \u003ccode\u003eos\u003c/code\u003e, \u003ccode\u003earch\u003c/code\u003e, and \u003ccode\u003elibc\u003c/code\u003e are free and answer the platform question. It may be reconsidered if the stored data ever shows that the OS-version cut is what triage is missing; a hunch is not that evidence.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWhich surfaces emit\u003c/h3\u003e\u003ca id=\"user-content-which-surfaces-emit\" class=\"anchor\" aria-label=\"Permalink: Which surfaces emit\" href=\"#which-surfaces-emit\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eEvery runtime surface uses the same \u003ccode\u003edecide\u003c/code\u003e and flush recheck: readable privacy\nstate, resolvable home, valid endpoint, and no persistent opt-out or run kill\nswitch. Missing preferences default on. The interactive TUI shows the disclosure;\nheadless commands never synthesize consent. Existing runtime events and counters\nare unchanged; adding PostHog does not add a second runtime collector.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eAn embedder declares the server it started\u003c/h3\u003e\u003ca id=\"user-content-an-embedder-declares-the-server-it-started\" class=\"anchor\" aria-label=\"Permalink: An embedder declares the server it started\" href=\"#an-embedder-declares-the-server-it-started\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA client that starts \u003ccode\u003ecodewhale serve\u003c/code\u003e may name itself, so its sessions are not\ncounted as anonymous \u003ccode\u003eserve\u003c/code\u003e traffic from nobody in particular. It sets\n\u003ccode\u003eCODEWHALE_TELEMETRY_SURFACE\u003c/code\u003e to a value in the \u003ccode\u003esurface\u003c/code\u003e whitelist before\nspawning the server; the extension client uses \u003ccode\u003evscode-extension\u003c/code\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThree properties of that read are deliberate:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003eserve\u003c/code\u003e only.\u003c/strong\u003e The variable is inherited by descendant processes, and an\nagent's shell command runs \u003ccode\u003ecodewhale\u003c/code\u003e descendants carrying this environment.\nOnly the branch that \u003cem\u003eis\u003c/em\u003e the embedder's own server consults it, so a nested\n\u003ccode\u003ecodewhale exec\u003c/code\u003e cannot report itself as the embedder.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003etui\u003c/code\u003e is refused\u003c/strong\u003e, and \u003ccode\u003eserve --mcp\u003c/code\u003e still reports \u003ccode\u003emcp-server\u003c/code\u003e: nothing\nstarts the interactive terminal UI on a user's behalf, and a server is not an\nMCP server because an embedder said so.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eAn unrecognised name is dropped, not repaired.\u003c/strong\u003e A value outside the\nwhitelist falls back to \u003ccode\u003eserve\u003c/code\u003e rather than failing startup or being guessed\nat; the field is a label, and the default is the honest one.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eThis changes how an embedder's sessions are \u003cem\u003elabelled\u003c/em\u003e. It does not change\nwhether anything may be collected: the server resolves that itself, from the\nsame durable config, the same setup state, and the same \u003ccode\u003eCODEWHALE_TELEMETRY\u003c/code\u003e\nrun-scoped kill switch. An embedder cannot enable collection where the user has\nturned it off, and a durable opt-out in one client is a durable opt-out for every\nclient on the machine, because they share one home and one install identity.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe extension client is the worked example: it holds a single on/off setting and\npasses \u003ccode\u003eCODEWHALE_TELEMETRY=0\u003c/code\u003e when the user turns reporting off. It contains no\npayload builder, no buffer, and no transport of its own — so its sessions share\nthe home's \u003ccode\u003einstall_id\u003c/code\u003e rather than minting a second one, and one installation is\none install in every count derived from that id.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eBecause that switch is run-scoped rather than a durable opt-out, turning it off\nstops the engine this extension starts and leaves the shared buffer and identity\nalone: those belong to every surface on the machine, not to one window, and\nclearing them would silently change what the user's terminal sessions do. A user\nwho wants reporting stopped and cleared everywhere does that once, with\n\u003ccode\u003ecodewhale config set telemetry false\u003c/code\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eWebsite and application clients use \u003ccode\u003eproduct_usage\u003c/code\u003e, with notice version \u003ccode\u003e5\u003c/code\u003e,\na random browser-local v4 ID rotated after 90 days, \u003ccode\u003eos = other\u003c/code\u003e, \u003ccode\u003earch = other\u003c/code\u003e,\n\u003ccode\u003elibc = none\u003c/code\u003e, \u003ccode\u003etty = false\u003c/code\u003e, and \u003ccode\u003egit_sha = null\u003c/code\u003e. They do not inspect the browser\nfingerprint. Their configured same-origin proxy forwards only this bounded JSON\nto the first-party ingest, with no incoming cookies, headers, URLs, or identities.\nThe browser endpoint is inert if unconfigured. Browser opt-out clears pending\ncounts and local identity; actions taken while disabled are never backfilled.\nProduct usage settings belong in the app and runtime; marketing privacy details\nand any website opt-out belong on the privacy page.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eEvent: \u003ccode\u003einstall_or_upgrade\u003c/code\u003e\u003c/h3\u003e\u003ca id=\"user-content-event-install_or_upgrade\" class=\"anchor\" aria-label=\"Permalink: Event: install_or_upgrade\" href=\"#event-install_or_upgrade\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eEmitted once when \u003ccode\u003estate.json\u003c/code\u003e's \u003ccode\u003elast_version\u003c/code\u003e differs from \u003ccode\u003eapp_version\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-json-comments notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"{ \u0026quot;event\u0026quot;: \u0026quot;install_or_upgrade\u0026quot;, \u0026quot;kind\u0026quot;: \u0026quot;upgrade\u0026quot;, \u0026quot;previous_version\u0026quot;: \u0026quot;0.9.3\u0026quot; }\"\u003e\u003cpre\u003e{ \u003cspan class=\"pl-ent\"\u003e\"event\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003einstall_or_upgrade\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e, \u003cspan class=\"pl-ent\"\u003e\"kind\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eupgrade\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e, \u003cspan class=\"pl-ent\"\u003e\"previous_version\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e0.9.3\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e }\u003c/pre\u003e\u003c/div\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eField\u003c/th\u003e\n\u003cth\u003eType\u003c/th\u003e\n\u003cth\u003eSource\u003c/th\u003e\n\u003cth\u003eRule\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ekind\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eenum\u003c/td\u003e\n\u003ctd\u003ederived\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003einstall\u003c/code\u003e (no prior record) | \u003ccode\u003eupgrade\u003c/code\u003e | \u003ccode\u003edowngrade\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eprevious_version\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003estring | null\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e$CODEWHALE_HOME/telemetry/state.json\u003c/code\u003e \u003cstrong\u003eonly\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eSame regex as \u003ccode\u003eapp_version\u003c/code\u003e. Never derived from session history or config mtimes — those files have a different privacy contract.\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eEvent: \u003ccode\u003esession_start\u003c/code\u003e\u003c/h3\u003e\u003ca id=\"user-content-event-session_start\" class=\"anchor\" aria-label=\"Permalink: Event: session_start\" href=\"#event-session_start\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-json-comments notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"{ \u0026quot;event\u0026quot;: \u0026quot;session_start\u0026quot;, \u0026quot;source\u0026quot;: \u0026quot;interactive\u0026quot; }\"\u003e\u003cpre\u003e{ \u003cspan class=\"pl-ent\"\u003e\"event\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003esession_start\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e, \u003cspan class=\"pl-ent\"\u003e\"source\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003einteractive\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e }\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003esource\u003c/code\u003e is \u003ccode\u003eSessionSource\u003c/code\u003e (\u003ccode\u003ecrates/state/src/lib.rs:34-41\u003c/code\u003e) stringified by \u003ccode\u003esession_source_to_str\u003c/code\u003e (\u003ccode\u003e:1909-1917\u003c/code\u003e): \u003ccode\u003einteractive | resume | fork | api | unknown\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eEvent: \u003ccode\u003esession_end\u003c/code\u003e\u003c/h3\u003e\u003ca id=\"user-content-event-session_end\" class=\"anchor\" aria-label=\"Permalink: Event: session_end\" href=\"#event-session_end\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe workhorse. Everything a session accumulated ships here, once.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-json-comments notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"{\n  \u0026quot;event\u0026quot;: \u0026quot;session_end\u0026quot;,\n  \u0026quot;duration_bucket\u0026quot;: \u0026quot;1m_10m\u0026quot;,\n  \u0026quot;exit_class\u0026quot;: \u0026quot;clean\u0026quot;,\n  \u0026quot;cold_start_bucket\u0026quot;: \u0026quot;250_1000\u0026quot;,\n  \u0026quot;providers\u0026quot;: [\u0026quot;deepseek\u0026quot;, \u0026quot;custom\u0026quot;],\n  \u0026quot;counters\u0026quot;: { \u0026quot;turns\u0026quot;: 14, \u0026quot;tool_calls\u0026quot;: 61, \u0026quot;fleet_dispatch\u0026quot;: 0, \u0026quot;workflow_run\u0026quot;: 0,\n                \u0026quot;subagent_spawn\u0026quot;: 2, \u0026quot;mcp_server_connected\u0026quot;: 0, \u0026quot;memory_search\u0026quot;: 0,\n                \u0026quot;approval_modal_shown\u0026quot;: 0, \u0026quot;approval_auto_allowed\u0026quot;: 0,\n                \u0026quot;command_palette_open\u0026quot;: 3 },\n  \u0026quot;errors\u0026quot;:   { \u0026quot;auth_preflight_failed\u0026quot;: 0, \u0026quot;provider_http_4xx\u0026quot;: 0, \u0026quot;provider_http_5xx\u0026quot;: 1,\n                \u0026quot;tool_denied_by_policy\u0026quot;: 0, \u0026quot;tool_timeout\u0026quot;: 0, \u0026quot;network_error\u0026quot;: 0 },\n  \u0026quot;turn_wall\u0026quot;: { \u0026quot;lt_5s\u0026quot;: 9, \u0026quot;5_30s\u0026quot;: 4, \u0026quot;30_120s\u0026quot;: 1, \u0026quot;gte_120s\u0026quot;: 0 }\n}\"\u003e\u003cpre\u003e{\n  \u003cspan class=\"pl-ent\"\u003e\"event\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003esession_end\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n  \u003cspan class=\"pl-ent\"\u003e\"duration_bucket\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e1m_10m\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n  \u003cspan class=\"pl-ent\"\u003e\"exit_class\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eclean\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n  \u003cspan class=\"pl-ent\"\u003e\"cold_start_bucket\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e250_1000\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n  \u003cspan class=\"pl-ent\"\u003e\"providers\"\u003c/span\u003e: [\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003edeepseek\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e, \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003ecustom\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e],\n  \u003cspan class=\"pl-ent\"\u003e\"counters\"\u003c/span\u003e: { \u003cspan class=\"pl-ent\"\u003e\"turns\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e14\u003c/span\u003e, \u003cspan class=\"pl-ent\"\u003e\"tool_calls\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e61\u003c/span\u003e, \u003cspan class=\"pl-ent\"\u003e\"fleet_dispatch\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e, \u003cspan class=\"pl-ent\"\u003e\"workflow_run\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e,\n                \u003cspan class=\"pl-ent\"\u003e\"subagent_spawn\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e, \u003cspan class=\"pl-ent\"\u003e\"mcp_server_connected\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e, \u003cspan class=\"pl-ent\"\u003e\"memory_search\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e,\n                \u003cspan class=\"pl-ent\"\u003e\"approval_modal_shown\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e, \u003cspan class=\"pl-ent\"\u003e\"approval_auto_allowed\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e,\n                \u003cspan class=\"pl-ent\"\u003e\"command_palette_open\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e },\n  \u003cspan class=\"pl-ent\"\u003e\"errors\"\u003c/span\u003e:   { \u003cspan class=\"pl-ent\"\u003e\"auth_preflight_failed\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e, \u003cspan class=\"pl-ent\"\u003e\"provider_http_4xx\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e, \u003cspan class=\"pl-ent\"\u003e\"provider_http_5xx\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e,\n                \u003cspan class=\"pl-ent\"\u003e\"tool_denied_by_policy\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e, \u003cspan class=\"pl-ent\"\u003e\"tool_timeout\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e, \u003cspan class=\"pl-ent\"\u003e\"network_error\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e },\n  \u003cspan class=\"pl-ent\"\u003e\"turn_wall\"\u003c/span\u003e: { \u003cspan class=\"pl-ent\"\u003e\"lt_5s\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e9\u003c/span\u003e, \u003cspan class=\"pl-ent\"\u003e\"5_30s\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e4\u003c/span\u003e, \u003cspan class=\"pl-ent\"\u003e\"30_120s\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e, \u003cspan class=\"pl-ent\"\u003e\"gte_120s\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e }\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003e\u003ccode\u003ecounters\u003c/code\u003e and \u003ccode\u003eerrors\u003c/code\u003e are \u003ccode\u003e#[derive(Serialize)]\u003c/code\u003e structs of named \u003ccode\u003eu32\u003c/code\u003e fields, not maps.\u003c/strong\u003e Every field is serialized including zeros. The key set is closed by the compiler: adding a counter requires editing \u003ccode\u003ecrates/telemetry/src/event.rs\u003c/code\u003e, which is where the doc-match test lives.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003e\u003ccode\u003eduration_bucket\u003c/code\u003e\u003c/strong\u003e — \u003ccode\u003echrono\u003c/code\u003e delta from \u003ccode\u003eapp.session_started_at\u003c/code\u003e (\u003ccode\u003ecrates/tui/src/tui/app.rs:1889\u003c/code\u003e). Half-open, seconds: \u003ccode\u003elt_1m\u003c/code\u003e (\u003ccode\u003ed \u0026lt; 60\u003c/code\u003e), \u003ccode\u003e1m_10m\u003c/code\u003e (\u003ccode\u003e60 ≤ d \u0026lt; 600\u003c/code\u003e), \u003ccode\u003e10m_60m\u003c/code\u003e (\u003ccode\u003e600 ≤ d \u0026lt; 3600\u003c/code\u003e), \u003ccode\u003egt_60m\u003c/code\u003e (\u003ccode\u003ed ≥ 3600\u003c/code\u003e).\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003e\u003ccode\u003eexit_class\u003c/code\u003e\u003c/strong\u003e — \u003ccode\u003eclean | signal | panic | error\u003c/code\u003e. \u003cstrong\u003eDerived from an explicit \u003ccode\u003eAtomicU8\u003c/code\u003e, never from an exit code.\u003c/strong\u003e \u003ccode\u003eRunTerminationReason::Canceled\u003c/code\u003e maps to exit 130 (\u003ccode\u003ecrates/tui/src/core/runtime_contract/termination.rs:53\u003c/code\u003e), the same value the signal task uses (\u003ccode\u003ecrates/tui/src/lib.rs:682\u003c/code\u003e, 128+SIGINT), so a code-based derivation would report every Esc-cancelled turn as a signal. The atomic is set by the panic hook (\u003ccode\u003ecrates/tui/src/lib.rs:1582\u003c/code\u003e), by the signal task (\u003ccode\u003e:678-696\u003c/code\u003e) before \u003ccode\u003estd::process::exit\u003c/code\u003e, and on the clean path from \u003ccode\u003eRunTerminationReason::is_success()\u003c/code\u003e (\u003ccode\u003ecrates/tui/src/core/runtime_contract/termination.rs:44-46\u003c/code\u003e) — \u003ccode\u003eerror\u003c/code\u003e otherwise. Do \u003cstrong\u003enot\u003c/strong\u003e use \u003ccode\u003eexec_failure_exit_code\u003c/code\u003e (\u003ccode\u003ecrates/tui/src/lib.rs:10432\u003c/code\u003e): it knows only \u003ccode\u003e{75, 1}\u003c/code\u003e and would report an approval-required exit (3) as a generic failure.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003e\u003ccode\u003ecold_start_bucket\u003c/code\u003e\u003c/strong\u003e — from \u003ccode\u003estartup_trace::elapsed_ms()\u003c/code\u003e, which reads \u003ccode\u003ePROCESS_START\u003c/code\u003e directly and is independent of the startup summary's buffer clear (\u003ccode\u003ecrates/runtime/src/startup_trace.rs:39-45\u003c/code\u003e). Boundaries: \u003ccode\u003elt_250\u003c/code\u003e, \u003ccode\u003e250_1000\u003c/code\u003e, \u003ccode\u003e1000_3000\u003c/code\u003e, \u003ccode\u003egte_3000\u003c/code\u003e. Absent on non-TUI surfaces.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003e\u003ccode\u003eproviders\u003c/code\u003e\u003c/strong\u003e — sorted, deduplicated array of \u003ccode\u003eProviderKind::as_str()\u003c/code\u003e (\u003ccode\u003ecrates/config/src/provider_kind.rs:295\u003c/code\u003e, a \u003ccode\u003e\u0026amp;'static str\u003c/code\u003e from a closed enum; \u003ccode\u003eCustom\u003c/code\u003e yields the literal \u003ccode\u003e\"custom\"\u003c/code\u003e). \u003cstrong\u003eThe API takes \u003ccode\u003eProviderKind\u003c/code\u003e by value, never \u003ccode\u003e\u0026amp;str\u003c/code\u003e.\u003c/strong\u003e Do not call \u003ccode\u003eProviderKind::parse\u003c/code\u003e or \u003ccode\u003eparse_config_identity\u003c/code\u003e (\u003ccode\u003e:300\u003c/code\u003e, \u003ccode\u003e:330\u003c/code\u003e) — those are for config-table resolution. \u003cstrong\u003eDo not read\u003c/strong\u003e \u003ccode\u003eprovider_identity_for_persistence()\u003c/code\u003e (\u003ccode\u003ecrates/tui/src/tui/app.rs:5049\u003c/code\u003e), \u003ccode\u003eprovider_id_for_persistence()\u003c/code\u003e (\u003ccode\u003e:5058\u003c/code\u003e), \u003ccode\u003eExecStreamMeta.provider_id\u003c/code\u003e (\u003ccode\u003ecrates/tui/src/lib.rs:10220\u003c/code\u003e), or \u003ccode\u003ePlannedTurnRoute.effective_provider_label\u003c/code\u003e (\u003ccode\u003ecrates/tui/src/turn_route_plan.rs:189-193\u003c/code\u003e) — all four return the customer's own \u003ccode\u003e[providers.\u0026lt;name\u0026gt;]\u003c/code\u003e table key when the route is Custom. This is the single most likely leak in the feature: it is one field away from the natural seam and \u003ccode\u003e/status\u003c/code\u003e already prints it (\u003ccode\u003ecrates/tui/src/commands/groups/config/status.rs:24-28\u003c/code\u003e). \u003cstrong\u003eNo model id is ever sent, for any provider\u003c/strong\u003e — \u003ccode\u003ecrates/runtime/src/safe_label.rs:11-15\u003c/code\u003e documents that a model id can be a path, a URL, or a deployment id that is itself a credential.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003e\u003ccode\u003ecounters\u003c/code\u003e\u003c/strong\u003e — closed field set. Every bump happens at the \u003cstrong\u003ecall site\u003c/strong\u003e, never inside a conditionally-entered handler:\u003c/p\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003efield\u003c/th\u003e\n\u003cth\u003esource anchor\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eturns\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003erun_event_loop\u003c/code\u003e in \u003ccode\u003ecrates/tui/src/tui/ui/event_loop.rs\u003c/code\u003e, immediately before it calls \u003ccode\u003eexecute_turn_end_observer_hook\u003c/code\u003e. Never inside that hook: its first statement is \u003ccode\u003eif !app.hooks.has_hooks_for_event(HookEvent::TurnEnd) { return Ok(()); }\u003c/code\u003e (\u003ccode\u003ecrates/tui/src/tui/ui/observer_hooks.rs\u003c/code\u003e), and the natural future optimization hoists that check to the call site, silently zeroing the counter for every user without hooks.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003etool_calls\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eexecute_tool_with_lock\u003c/code\u003e in \u003ccode\u003ecrates/tui/src/core/engine/tool_execution.rs\u003c/code\u003e — surface-agnostic, fires for exec and CLI too\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003efleet_dispatch\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003ecreate_queued_run_with_descriptor\u003c/code\u003e in \u003ccode\u003ecrates/tui/src/fleet/manager.rs\u003c/code\u003e — the single funnel that \u003ccode\u003ecreate_run\u003c/code\u003e and \u003ccode\u003ecreate_queued_run\u003c/code\u003e both land in; counting at either caller would double-count a plain \u003ccode\u003efleet run\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eworkflow_run\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003ebumped in \u003ccode\u003eWorkflowTool::execute\u003c/code\u003e (\u003ccode\u003ecrates/tui/src/tools/workflow/mod.rs\u003c/code\u003e) only after \u003ccode\u003eparse_workflow_action\u003c/code\u003e returns an \u003ccode\u003eOk(WorkflowAction)\u003c/code\u003e, never from \u003ccode\u003einput[\"action\"]\u003c/code\u003e. The JSON Schema \u003ccode\u003eenum\u003c/code\u003e in \u003ccode\u003eWorkflowTool::input_schema\u003c/code\u003e is what is published \u003cem\u003eto the model\u003c/em\u003e — a declaration, not a guard; the real parse also accepts \u003ccode\u003espawn|wait|list|inspect|stop|abort\u003c/code\u003e, and its reject arm (\u003ccode\u003eInvalid workflow action '…'\u003c/code\u003e) embeds the model string verbatim, so a rejected action is never counted.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003esubagent_spawn\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eapply_agent_spawned_status_and_observer\u003c/code\u003e in \u003ccode\u003ecrates/tui/src/tui/ui/apply.rs\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003emcp_server_connected\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003ebumped when a server snapshot's \u003ccode\u003e.connected\u003c/code\u003e is true, in \u003ccode\u003esnapshot_from_config\u003c/code\u003e (\u003ccode\u003ecrates/tui/src/mcp.rs\u003c/code\u003e); never \u003ccode\u003ename\u003c/code\u003e, \u003ccode\u003ecommand_or_url\u003c/code\u003e, or \u003ccode\u003eerror\u003c/code\u003e — server names are user-chosen and routinely internal infra\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ememory_search\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003etool_name == \"memory_search\"\u003c/code\u003e (the tool registered in \u003ccode\u003ecrates/tui/src/tools/native_memory.rs\u003c/code\u003e), counted at the same \u003ccode\u003eexecute_tool_with_lock\u003c/code\u003e choke point\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eapproval_modal_shown\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003ethe \u003ccode\u003eEvent::ApprovalRequired\u003c/code\u003e arm of \u003ccode\u003erun_event_loop\u003c/code\u003e (\u003ccode\u003ecrates/tui/src/tui/ui/event_loop.rs\u003c/code\u003e; the event is defined in \u003ccode\u003ecrates/tui/src/core/events.rs\u003c/code\u003e)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eapproval_auto_allowed\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003etool_ask_rule_decision_for_context\u003c/code\u003e in \u003ccode\u003ecrates/tui/src/core/engine.rs\u003c/code\u003e. Count only. Never \u003ccode\u003ematched_rule\u003c/code\u003e, \u003ccode\u003ereason()\u003c/code\u003e, the command, or argv — \u003ccode\u003eauto_allow\u003c/code\u003e patterns are user-authored command strings (\u003ccode\u003ecrates/execpolicy/src/command_safety.rs:35/309\u003c/code\u003e)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ecommand_palette_open\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003ethe palette key path in \u003ccode\u003erun_event_loop\u003c/code\u003e (\u003ccode\u003ecrates/tui/src/tui/ui/event_loop.rs\u003c/code\u003e) and \u003ccode\u003ehandle_context_menu_action\u003c/code\u003e in \u003ccode\u003ecrates/tui/src/tui/mouse_ui.rs\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003e\u003ccode\u003eerrors\u003c/code\u003e\u003c/strong\u003e — closed field set. Every value is a \u003cstrong\u003evariant discriminant\u003c/strong\u003e, never \u003ccode\u003eerr.to_string()\u003c/code\u003e:\u003c/p\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003efield\u003c/th\u003e\n\u003cth\u003esource anchor\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eauth_preflight_failed\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003ediscriminant of \u003ccode\u003eCredentialReadiness\u003c/code\u003e (\u003ccode\u003ecrates/workflow/src/fleet_preflight.rs:37-58\u003c/code\u003e) / \u003ccode\u003eProviderAuthClass\u003c/code\u003e (\u003ccode\u003ecrates/tui/src/provider_readiness.rs:32\u003c/code\u003e). Discriminant only — \u003ccode\u003eMissing { detail }\u003c/code\u003e carries free text\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eprovider_http_4xx\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003estatus.as_u16() / 100 == 4\u003c/code\u003e, captured at \u003ccode\u003ecrates/tui/src/client/chat.rs:595\u003c/code\u003e and \u003ccode\u003e:673\u003c/code\u003e \u003cstrong\u003ebefore\u003c/strong\u003e the \u003ccode\u003ebail!\u003c/code\u003e. One row per field, because the doc-match test reads this table field for field\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eprovider_http_5xx\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003estatus.as_u16() / 100 == 5\u003c/code\u003e, same capture points\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003etool_denied_by_policy\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003ethe \u003ccode\u003epermission_denied\u003c/code\u003e arm of the 8-variant match at \u003ccode\u003ecrates/tui/src/core/engine/tool_execution.rs:512-531\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003etool_timeout\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003ethe \u003ccode\u003etimeout\u003c/code\u003e arm, same match\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003enetwork_error\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eretry_reason_label_and_human()\u003c/code\u003e's \u003ccode\u003e\u0026amp;'static str\u003c/code\u003e half, \u003ccode\u003ecrates/tui/src/client.rs:2659\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cp dir=\"auto\"\u003eWhy discriminants and nothing else: \u003ccode\u003eToolError::PathEscape\u003c/code\u003e's \u003ccode\u003eDisplay\u003c/code\u003e \u003cem\u003eis\u003c/em\u003e an absolute path (\u003ccode\u003ecrates/tools/src/lib.rs:61\u003c/code\u003e); \u003ccode\u003efim.rs:48-50\u003c/code\u003e's \u003ccode\u003eDisplay\u003c/code\u003e \u003cem\u003eis\u003c/em\u003e a literal source fragment the model emitted; \u003ccode\u003esecrets/src/lib.rs:50\u003c/code\u003e's \u003ccode\u003eDisplay\u003c/code\u003e carries the secret store's absolute path; every \u003ccode\u003eLlmError\u003c/code\u003e variant carries the raw provider HTTP body verbatim (\u003ccode\u003ecrates/tui/src/llm_client/mod.rs:327\u003c/code\u003e), and a 400 from a content filter routinely echoes the prompt.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003e\u003ccode\u003eturn_wall\u003c/code\u003e\u003c/strong\u003e — a per-session histogram of counts, never per-turn events. \u003ccode\u003elt_5s\u003c/code\u003e, \u003ccode\u003e5_30s\u003c/code\u003e, \u003ccode\u003e30_120s\u003c/code\u003e, \u003ccode\u003egte_120s\u003c/code\u003e. Recorded by \u003ccode\u003eobserve_turn_secs\u003c/code\u003e next to the \u003ccode\u003eturns\u003c/code\u003e bump in \u003ccode\u003erun_event_loop\u003c/code\u003e, which already has the turn duration in hand.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eEvent: \u003ccode\u003epanic\u003c/code\u003e\u003c/h3\u003e\u003ca id=\"user-content-event-panic\" class=\"anchor\" aria-label=\"Permalink: Event: panic\" href=\"#event-panic\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAppended \u003cstrong\u003esynchronously\u003c/strong\u003e by the panic hook, because a \u003ccode\u003esession_end\u003c/code\u003e may never be written.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-json-comments notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"{ \u0026quot;event\u0026quot;: \u0026quot;panic\u0026quot;, \u0026quot;site\u0026quot;: \u0026quot;crates/tui/src/lib.rs:1582:5\u0026quot; }\"\u003e\u003cpre\u003e{ \u003cspan class=\"pl-ent\"\u003e\"event\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003epanic\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e, \u003cspan class=\"pl-ent\"\u003e\"site\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003ecrates/tui/src/lib.rs:1582:5\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e }\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003esite\u003c/code\u003e comes from \u003ccode\u003epanic_info.location()\u003c/code\u003e (\u003ccode\u003ecrates/tui/src/lib.rs:1597-1600\u003c/code\u003e) or \u003ccode\u003eLocation::caller()\u003c/code\u003e (\u003ccode\u003ecrates/tui/src/utils.rs:523\u003c/code\u003e). \u003cstrong\u003eAllowlist reduction, not optional:\u003c/strong\u003e emit verbatim only if \u003ccode\u003efile()\u003c/code\u003e starts with \u003ccode\u003ecrates/\u003c/code\u003e; otherwise emit the literal \u003ccode\u003e\"\u0026lt;dep\u0026gt;\"\u003c/code\u003e. Must match \u003ccode\u003e^crates/[A-Za-z0-9_/.-]+\\.rs:\\d+:\\d+$\u003c/code\u003e or \u003ccode\u003e^\u0026lt;dep\u0026gt;$\u003c/code\u003e. There is no \u003ccode\u003e--remap-path-prefix\u003c/code\u003e in this repo (no \u003ccode\u003e.cargo/config.toml\u003c/code\u003e; \u003ccode\u003eCargo.toml:69-74\u003c/code\u003e sets only \u003ccode\u003elto\u003c/code\u003e/\u003ccode\u003estrip\u003c/code\u003e/\u003ccode\u003ecodegen-units\u003c/code\u003e), so a panic inside a registry dependency yields \u003ccode\u003e/Users/\u0026lt;builder\u0026gt;/.cargo/registry/src/…/ratatui-0.29.0/src/…\u003c/code\u003e — the \u003cstrong\u003ebuild machine's username\u003c/strong\u003e, shipped from every user's binary.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eThe panic message is never sent.\u003c/strong\u003e The hook at \u003ccode\u003ecrates/tui/src/lib.rs:1590-1596\u003c/code\u003e builds \u003ccode\u003emsg\u003c/code\u003e from the payload; telemetry must not read it. A slicing panic embeds the entire string being sliced, and this tree slices user and model text in dozens of places.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eEvent: \u003ccode\u003eproduct_usage\u003c/code\u003e\u003c/h3\u003e\u003ca id=\"user-content-event-product_usage\" class=\"anchor\" aria-label=\"Permalink: Event: product_usage\" href=\"#event-product_usage\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eOne aggregate of explicit product interactions, with every field a saturating\n\u003ccode\u003eu32\u003c/code\u003e, including zero values. No page paths, URLs, referrers, search terms,\naccount/session IDs, text, or action timestamps are permitted. Clients flush\naggregate counts on page exit or when hidden, rather than each action.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-json-comments notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"{\n  \u0026quot;event\u0026quot;: \u0026quot;product_usage\u0026quot;,\n  \u0026quot;counters\u0026quot;: {\n    \u0026quot;page_view\u0026quot;: 1,\n    \u0026quot;docs_view\u0026quot;: 0,\n    \u0026quot;install_copy\u0026quot;: 0,\n    \u0026quot;download\u0026quot;: 0,\n    \u0026quot;signup\u0026quot;: 0,\n    \u0026quot;login\u0026quot;: 0,\n    \u0026quot;session_create\u0026quot;: 0,\n    \u0026quot;session_resume\u0026quot;: 0,\n    \u0026quot;turn_submit\u0026quot;: 0,\n    \u0026quot;turn_complete\u0026quot;: 0,\n    \u0026quot;settings_open\u0026quot;: 0,\n    \u0026quot;integration_connect\u0026quot;: 0,\n    \u0026quot;error_shown\u0026quot;: 0\n  }\n}\"\u003e\u003cpre\u003e{\n  \u003cspan class=\"pl-ent\"\u003e\"event\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eproduct_usage\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n  \u003cspan class=\"pl-ent\"\u003e\"counters\"\u003c/span\u003e: {\n    \u003cspan class=\"pl-ent\"\u003e\"page_view\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e,\n    \u003cspan class=\"pl-ent\"\u003e\"docs_view\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e,\n    \u003cspan class=\"pl-ent\"\u003e\"install_copy\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e,\n    \u003cspan class=\"pl-ent\"\u003e\"download\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e,\n    \u003cspan class=\"pl-ent\"\u003e\"signup\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e,\n    \u003cspan class=\"pl-ent\"\u003e\"login\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e,\n    \u003cspan class=\"pl-ent\"\u003e\"session_create\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e,\n    \u003cspan class=\"pl-ent\"\u003e\"session_resume\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e,\n    \u003cspan class=\"pl-ent\"\u003e\"turn_submit\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e,\n    \u003cspan class=\"pl-ent\"\u003e\"turn_complete\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e,\n    \u003cspan class=\"pl-ent\"\u003e\"settings_open\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e,\n    \u003cspan class=\"pl-ent\"\u003e\"integration_connect\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e,\n    \u003cspan class=\"pl-ent\"\u003e\"error_shown\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e\n  }\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003epage_view\u003c/code\u003e counts a page view and \u003ccode\u003edocs_view\u003c/code\u003e a documentation view; \u003ccode\u003einstall_copy\u003c/code\u003e\nand \u003ccode\u003edownload\u003c/code\u003e count installation actions. \u003ccode\u003esignup\u003c/code\u003e and \u003ccode\u003elogin\u003c/code\u003e count successful\nauthentication actions, never identity. \u003ccode\u003esession_create\u003c/code\u003e, \u003ccode\u003esession_resume\u003c/code\u003e,\n\u003ccode\u003eturn_submit\u003c/code\u003e, and \u003ccode\u003eturn_complete\u003c/code\u003e count their named product actions.\n\u003ccode\u003esettings_open\u003c/code\u003e, \u003ccode\u003eintegration_connect\u003c/code\u003e, and \u003ccode\u003eerror_shown\u003c/code\u003e are counts only:\nnever the selected setting, integration name, error body, or work content.\nAn event's availability depends on the emitting client; zero is not proof a\nfeature was exercised or available.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eEvent: \u003ccode\u003eoperations_summary\u003c/code\u003e\u003c/h3\u003e\u003ca id=\"user-content-event-operations_summary\" class=\"anchor\" aria-label=\"Permalink: Event: operations_summary\" href=\"#event-operations_summary\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAnonymous service health aggregates from the existing control-plane signal ledger.\nExactly these six saturating \u003ccode\u003eu32\u003c/code\u003e fields are accepted, only on \u003ccode\u003econtrol-plane\u003c/code\u003e.\nThis requires an explicit operator delivery/processor configuration, independently\nof the end-user analytics choice. Each batch uses a fresh random v4 \u003ccode\u003einstall_id\u003c/code\u003e;\nthere is no user/account/session join. No per-request rows, routes, request\ndigests, IDs, error text, traces, or timing series are permitted. \u003ccode\u003erequests\u003c/code\u003e and\n\u003ccode\u003eerrors\u003c/code\u003e count requests and failures; \u003ccode\u003eduration_ms_total\u003c/code\u003e and \u003ccode\u003eduration_ms_max\u003c/code\u003e\nare aggregate latency values; \u003ccode\u003eprobes\u003c/code\u003e and \u003ccode\u003eprobes_failed\u003c/code\u003e count health probes.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-json-comments notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"{\n  \u0026quot;event\u0026quot;: \u0026quot;operations_summary\u0026quot;,\n  \u0026quot;requests\u0026quot;: 10,\n  \u0026quot;errors\u0026quot;: 1,\n  \u0026quot;duration_ms_total\u0026quot;: 1500,\n  \u0026quot;duration_ms_max\u0026quot;: 300,\n  \u0026quot;probes\u0026quot;: 2,\n  \u0026quot;probes_failed\u0026quot;: 0\n}\"\u003e\u003cpre\u003e{\n  \u003cspan class=\"pl-ent\"\u003e\"event\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eoperations_summary\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n  \u003cspan class=\"pl-ent\"\u003e\"requests\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e10\u003c/span\u003e,\n  \u003cspan class=\"pl-ent\"\u003e\"errors\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e,\n  \u003cspan class=\"pl-ent\"\u003e\"duration_ms_total\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e1500\u003c/span\u003e,\n  \u003cspan class=\"pl-ent\"\u003e\"duration_ms_max\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e300\u003c/span\u003e,\n  \u003cspan class=\"pl-ent\"\u003e\"probes\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e,\n  \u003cspan class=\"pl-ent\"\u003e\"probes_failed\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWhat the endpoint does — a shipping gate, not a footnote\u003c/h3\u003e\u003ca id=\"user-content-what-the-endpoint-does--a-shipping-gate-not-a-footnote\" class=\"anchor\" aria-label=\"Permalink: What the endpoint does — a shipping gate, not a footnote\" href=\"#what-the-endpoint-does--a-shipping-gate-not-a-footnote\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThis section was a gate on configuring any non-loopback endpoint. The endpoint is now configured by default, so this is a description of a service that exists rather than a promise about one that might.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eWhat it is.\u003c/strong\u003e \u003ccode\u003ehttps://telemetry.codewhale.net/v1/telemetry\u003c/code\u003e — a Cloudflare Worker named \u003ccode\u003ecodewhale-telemetry-ingest\u003c/code\u003e, whose complete source is in this repository at \u003ca href=\"/codewhale-hq/Codewhale/blob/main/telemetry-ingest\"\u003e\u003ccode\u003etelemetry-ingest/\u003c/code\u003e\u003c/a\u003e. It is the single schema and storage authority; browser applications may use a same-origin proxy that forwards only the body. There is no telemetry queue or additional runtime collector. It is write-only: nothing in the Worker can read back what was stored, and querying happens out of band through Cloudflare's SQL API with the owner's token. The hostname is deliberately self-describing, so anyone inspecting their own network traffic can tell what it is from the name alone.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eWhat it stores.\u003c/strong\u003e Everything in this document and nothing else, in Workers Analytics Engine — one row per event. The validator in \u003ccode\u003etelemetry-ingest/src/schema.ts\u003c/code\u003e is a \u003cstrong\u003eclosed\u003c/strong\u003e field set: an unknown key anywhere in a batch rejects the whole batch with \u003ccode\u003e400\u003c/code\u003e. A future client bug that starts attaching a path, a prompt, or a provider table name gets refused by the server rather than quietly stored. \u003ccode\u003etelemetry-ingest/test/schema-doc.test.ts\u003c/code\u003e parses the field names and enum spellings back out of \u003cem\u003ethis file\u003c/em\u003e and asserts set equality against the validator, and \u003ccode\u003etelemetry-ingest/test/ingest.test.ts\u003c/code\u003e posts the Rust client's own pinned golden batch and asserts it is accepted byte for byte — so this document, the client, and the endpoint cannot drift apart without a red test.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eBatches are \u003cstrong\u003eIP-stripped at ingest\u003c/strong\u003e. No IP is stored, logged, or joined to \u003ccode\u003einstall_id\u003c/code\u003e — and that is structural rather than a setting anyone could flip. An Analytics Engine row is exactly \u003ccode\u003e_sample_interval\u003c/code\u003e, \u003ccode\u003eblob1\u003c/code\u003e–\u003ccode\u003eblob20\u003c/code\u003e, \u003ccode\u003edataset\u003c/code\u003e, \u003ccode\u003edouble1\u003c/code\u003e–\u003ccode\u003edouble20\u003c/code\u003e, \u003ccode\u003eindex1\u003c/code\u003e, and \u003ccode\u003etimestamp\u003c/code\u003e. Every one of those columns is written by the Worker's own \u003ccode\u003ewriteDataPoint\u003c/code\u003e call; there is no implicit column, so \u003cstrong\u003ethere is no IP, country, or geo column\u003c/strong\u003e — no slot one could occupy even if the code wanted it there. And the code cannot want it:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eThe handler reads exactly \u003cstrong\u003etwo\u003c/strong\u003e request headers — \u003ccode\u003econtent-type\u003c/code\u003e and \u003ccode\u003econtent-length\u003c/code\u003e. Nothing else, ever.\u003c/li\u003e\n\u003cli\u003eIt never touches the request's \u003ccode\u003ecf\u003c/code\u003e property, so country, colo, city, region, ASN, timezone, and coordinates are never in scope.\u003c/li\u003e\n\u003cli\u003eThe function that builds every stored row cannot see the request at all; its input type is the validated batch body.\u003c/li\u003e\n\u003cli\u003eNothing logs. \u003ccode\u003einvocation_logs\u003c/code\u003e is off in \u003ccode\u003ewrangler.jsonc\u003c/code\u003e — Cloudflare describes those as \"enriched with information available to Cloudflare in the context of the invocation\", which is exactly the class of automatic per-request record this service will not keep — and there is no \u003ccode\u003econsole.*\u003c/code\u003e call in the source.\u003c/li\u003e\n\u003cli\u003eRate limiting is keyed on \u003ccode\u003einstall_id\u003c/code\u003e from the validated body, never on a network address. An IP-keyed limiter would mean this Worker handles IPs. It is the weaker limiter and it is the right trade.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003etelemetry-ingest/test/no-ip.test.ts\u003c/code\u003e reads the shipped source as text and fails the build if any address or geo name appears, if the set of headers read grows past two, if a \u003ccode\u003econsole.*\u003c/code\u003e call is added, or if a \u003ccode\u003eResponse\u003c/code\u003e is ever constructed with a body.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eRetention: three months.\u003c/strong\u003e That is Cloudflare's fixed window for Analytics Engine and it is not configurable, so it is a ceiling rather than a policy — there is no setting that could make it longer.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eOptional PostHog processor.\u003c/strong\u003e After first-party storage, an explicitly\nconfigured ingest may forward validated schema-v3 / notice-v5 batches and\nlegacy schema-v2 / consent-v4 batches to\nPostHog's \u003ca href=\"https://posthog.com/docs/api/capture\" rel=\"nofollow\"\u003ebatch capture API\u003c/a\u003e. The only\npermitted origins are \u003ccode\u003ehttps://us.i.posthog.com\u003c/code\u003e and \u003ccode\u003ehttps://eu.i.posthog.com\u003c/code\u003e.\nLegacy v1 batches cannot reach that path. PostHog receives the same bounded\nenvelope and event fields, the batch timestamp as its event timestamp, and\n\u003ccode\u003ecodewhale:\u0026lt;install_id\u0026gt;\u003c/code\u003e as its anonymous \u003ccode\u003edistinct_id\u003c/code\u003e. Events are named\n\u003ccode\u003ecodewhale_install_or_upgrade\u003c/code\u003e, \u003ccode\u003ecodewhale_session_start\u003c/code\u003e,\n\u003ccode\u003ecodewhale_session_end\u003c/code\u003e, \u003ccode\u003ecodewhale_panic\u003c/code\u003e, \u003ccode\u003ecodewhale_product_usage\u003c/code\u003e, or\n\u003ccode\u003ecodewhale_operations_summary\u003c/code\u003e.\n\u003ccode\u003e$process_person_profile = false\u003c/code\u003e, \u003ccode\u003e$geoip_disable = true\u003c/code\u003e, and \u003ccode\u003e$ip = null\u003c/code\u003e\nare fixed transport controls. No request metadata, profile identification,\nSDK, autocapture, session replay, advertising, or work content is forwarded.\nA fresh server request has no user cookies or authorization headers, cannot\nfollow redirects, and is limited to 1.5 seconds. There are no retries or logs;\na failure does not change a successful first-party ingest response.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe PostHog project's retention and privacy settings are separate deployment\nconfiguration and must be reviewed before activation. The Analytics Engine\nthree-month limit does not establish a PostHog retention period.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eThe edge egress path also requires staging proof.\u003c/strong\u003e \u003ca href=\"https://developers.cloudflare.com/fundamentals/reference/http-headers/#cf-connecting-ip-in-worker-subrequests\" rel=\"nofollow\"\u003eCloudflare documents\u003c/a\u003e\nthat Worker subrequests to non-Cloudflare zones can receive platform-added\nclient-IP headers. Fresh JavaScript headers and local fetch tests cannot prove\nthose headers are removed. \u003ccode\u003ePOSTHOG_IP_SAFE_EGRESS_VERIFIED=\"true\"\u003c/code\u003e is an explicit\noperator prerequisite alongside the host and token, and must remain unset\nuntil a receipt for the actual deployment and regional destination confirms\nno original client IP in any received header, including \u003ccode\u003eCF-Connecting-IP\u003c/code\u003e,\n\u003ccode\u003eX-Forwarded-For\u003c/code\u003e, and \u003ccode\u003eX-Real-IP\u003c/code\u003e. The flag does not strip platform headers.\nRequalify a changed egress path; if it cannot pass, keep the sink disabled or\nrun only its delivery in a detached first-party context. No such live proof\nis established by this source change.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eEvery response is a bare status with an empty body\u003c/strong\u003e — \u003ccode\u003e204\u003c/code\u003e accepted, \u003ccode\u003e400\u003c/code\u003e schema violation, \u003ccode\u003e404\u003c/code\u003e/\u003ccode\u003e405\u003c/code\u003e wrong path or method, \u003ccode\u003e413\u003c/code\u003e oversized, \u003ccode\u003e415\u003c/code\u003e wrong content type, \u003ccode\u003e429\u003c/code\u003e rate-limited, \u003ccode\u003e500\u003c/code\u003e internal. The endpoint cannot echo back what it received or what it holds, and because the client drops the batch on anything that is not 2xx, a rejection is invisible to you by construction and a server error can never surface as a client-visible failure.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003einstall_id\u003c/code\u003e rotates client-side every 90 days (\u003ccode\u003erotated_at\u003c/code\u003e in \u003ccode\u003einstall_id.json\u003c/code\u003e), so no single identifier spans a long history. This costs longitudinal accuracy and the docs say so: \u003cstrong\u003eno count derived from \u003ccode\u003einstall_id\u003c/code\u003e is a user count.\u003c/strong\u003e It is a lower bound on distinct machine-installs in a window, and it undercounts a returning user across a rotation.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eTurning it off deletes what was kept locally, not what was already sent.\u003c/strong\u003e \u003ccode\u003ecodewhale config set telemetry false\u003c/code\u003e erases the install id, the buffer, and the dry-run records on your machine, and stops anything further. Rows already accepted by the endpoint are keyed only by a rotating random id that is now gone; first-party rows age out with the three-month window. If PostHog processing is activated, already-delivered processor records follow that project’s configured retention. The client has no remote deletion API and does not claim that local opt-out erases delivered records.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWhat the owner reads back — observed active installs\u003c/h3\u003e\u003ca id=\"user-content-what-the-owner-reads-back--observed-active-installs\" class=\"anchor\" aria-label=\"Permalink: What the owner reads back — observed active installs\" href=\"#what-the-owner-reads-back--observed-active-installs\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe one product metric derived from this data is \u003cstrong\u003eobserved active installs\u003c/strong\u003e: the number of distinct rotating anonymous install ids that produced a \u003ccode\u003esession_start\u003c/code\u003e event on a UTC day. That is the whole definition. It is not a count of people, not a count of accounts, and not a count of total installs — the id is per installation, rotates every 90 days, and is deleted on opt-out, so no number derived from it can be any of those things.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe exact owner command is checked into the repository, so the routine query is reviewable code rather than SQL pasted from a chat:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"cd telemetry-ingest\nCF_ACCOUNT_ID=... CF_API_TOKEN=... npm run report:active-installs\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c1\"\u003ecd\u003c/span\u003e telemetry-ingest\nCF_ACCOUNT_ID=... CF_API_TOKEN=... npm run report:active-installs\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIt prints the daily series, a 7-day trend over complete UTC days, the freshness of the newest ingested event, and — with the numbers, in both text and \u003ccode\u003e--json\u003c/code\u003e output — the coverage caveats: clients older than the telemetry feature, opted-out installs, and non-emitting environments (kill switches, fleet workers, offline shutdowns, dropped flushes) are invisible, so every count is a lower bound; and because ids rotate, week-over-week comparisons are not a retention metric. The report's read path is itself tested: the install id appears only inside an aggregate, no payload column is selected, and the wording can never drift into calling the result users. (\u003ccode\u003enpm run report:dau\u003c/code\u003e remains as a compatibility alias for the same report.)\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWhat is never collected — the public red-line list\u003c/h3\u003e\u003ca id=\"user-content-what-is-never-collected--the-public-red-line-list\" class=\"anchor\" aria-label=\"Permalink: What is never collected — the public red-line list\" href=\"#what-is-never-collected--the-public-red-line-list\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ePrompts; completions; tool arguments; diffs; patches; file contents; filenames; absolute or relative paths; git remotes; repo names; branch names; workspace commit SHAs; memory entries; chat history; API keys, tokens, cookies, or \u003ccode\u003eAuthorization\u003c/code\u003e headers (including any boolean asserting a key exists); model ids of any kind; custom provider table names; MCP server names, commands, or URLs; approval rule text; error message bodies; panic message text; per-event timestamps; keystrokes; clipboard; screenshots; microphone; camera; location; and any third-party ad or analytics SDK — there are none in the runtime binary and none may be added.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTwo named traps for the implementer. \u003ccode\u003ecrates/state/src/lib.rs\u003c/code\u003e persists \u003ccode\u003egit_sha\u003c/code\u003e, \u003ccode\u003egit_branch\u003c/code\u003e, \u003ccode\u003egit_origin_url\u003c/code\u003e, \u003ccode\u003ecwd\u003c/code\u003e, and \u003ccode\u003epath\u003c/code\u003e on the threads table (\u003ccode\u003e:93, :399, :653\u003c/code\u003e): a payload builder that accepts a \u003ccode\u003eThread\u003c/code\u003e or \u003ccode\u003eThreadMeta\u003c/code\u003e and derives \u003ccode\u003eSerialize\u003c/code\u003e breaches the contract in one line. \u003cstrong\u003eNever derive \u003ccode\u003eSerialize\u003c/code\u003e over an existing state type\u003c/strong\u003e — build every telemetry struct from scratch with explicit fields. And \u003ccode\u003ecrates/core/src/lib.rs:1389-1398\u003c/code\u003e is the one place in the tree where the word \u003ccode\u003etelemetry\u003c/code\u003e sits inside a JSON object next to \u003ccode\u003eprompt\u003c/code\u003e, \u003ccode\u003ebase_url\u003c/code\u003e, and \u003ccode\u003ehas_api_key\u003c/code\u003e. It is the object someone will copy. Do not.\u003c/p\u003e\n\u003chr\u003e\n\u003c/article\u003e","richTextTruncated":false,"renderedFileInfo":null,"symbols":{"timed_out":false,"not_analyzed":false,"symbols":[{"name":"Codewhale product telemetry","fully_qualified_name":"Codewhale product telemetry","kind":"section_1","ident_start":2,"ident_end":29,"extent_start":0,"extent_end":38987,"ident_utf16":{"start":{"line_number":0,"utf16_col":2},"end":{"line_number":0,"utf16_col":29}},"extent_utf16":{"start":{"line_number":0,"utf16_col":0},"end":{"line_number":499,"utf16_col":0}}},{"name":"Turning it off","fully_qualified_name":"Turning it off","kind":"section_2","ident_start":3030,"ident_end":3044,"extent_start":3027,"extent_end":5450,"ident_utf16":{"start":{"line_number":52,"utf16_col":3},"end":{"line_number":52,"utf16_col":17}},"extent_utf16":{"start":{"line_number":52,"utf16_col":0},"end":{"line_number":96,"utf16_col":0}}},{"name":"Where it lives, and how much of your disk it uses","fully_qualified_name":"Where it lives, and how much of your disk it uses","kind":"section_2","ident_start":5453,"ident_end":5502,"extent_start":5450,"extent_end":6795,"ident_utf16":{"start":{"line_number":96,"utf16_col":3},"end":{"line_number":96,"utf16_col":52}},"extent_utf16":{"start":{"line_number":96,"utf16_col":0},"end":{"line_number":124,"utf16_col":0}}},{"name":"When anything is sent, and where","fully_qualified_name":"When anything is sent, and where","kind":"section_2","ident_start":6798,"ident_end":6830,"extent_start":6795,"extent_end":8804,"ident_utf16":{"start":{"line_number":124,"utf16_col":3},"end":{"line_number":124,"utf16_col":35}},"extent_utf16":{"start":{"line_number":124,"utf16_col":0},"end":{"line_number":161,"utf16_col":0}}},{"name":"Event schema","fully_qualified_name":"Event schema","kind":"section_2","ident_start":8807,"ident_end":8819,"extent_start":8804,"extent_end":38987,"ident_utf16":{"start":{"line_number":161,"utf16_col":3},"end":{"line_number":161,"utf16_col":15}},"extent_utf16":{"start":{"line_number":161,"utf16_col":0},"end":{"line_number":499,"utf16_col":0}}},{"name":"Batch envelope — sent on every POST","fully_qualified_name":"Batch envelope — sent on every POST","kind":"section_3","ident_start":9641,"ident_end":9678,"extent_start":9637,"extent_end":13356,"ident_utf16":{"start":{"line_number":172,"utf16_col":4},"end":{"line_number":172,"utf16_col":39}},"extent_utf16":{"start":{"line_number":172,"utf16_col":0},"end":{"line_number":208,"utf16_col":0}}},{"name":"Which surfaces emit","fully_qualified_name":"Which surfaces emit","kind":"section_3","ident_start":13360,"ident_end":13379,"extent_start":13356,"extent_end":13775,"ident_utf16":{"start":{"line_number":208,"utf16_col":4},"end":{"line_number":208,"utf16_col":23}},"extent_utf16":{"start":{"line_number":208,"utf16_col":0},"end":{"line_number":216,"utf16_col":0}}},{"name":"An embedder declares the server it started","fully_qualified_name":"An embedder declares the server it started","kind":"section_3","ident_start":13779,"ident_end":13821,"extent_start":13775,"extent_end":16848,"ident_utf16":{"start":{"line_number":216,"utf16_col":4},"end":{"line_number":216,"utf16_col":46}},"extent_utf16":{"start":{"line_number":216,"utf16_col":0},"end":{"line_number":266,"utf16_col":0}}},{"name":"Event: `install_or_upgrade`","fully_qualified_name":"Event: `install_or_upgrade`","kind":"section_3","ident_start":16852,"ident_end":16879,"extent_start":16848,"extent_end":17417,"ident_utf16":{"start":{"line_number":266,"utf16_col":4},"end":{"line_number":266,"utf16_col":31}},"extent_utf16":{"start":{"line_number":266,"utf16_col":0},"end":{"line_number":279,"utf16_col":0}}},{"name":"Event: `session_start`","fully_qualified_name":"Event: `session_start`","kind":"section_3","ident_start":17421,"ident_end":17443,"extent_start":17417,"extent_end":17678,"ident_utf16":{"start":{"line_number":279,"utf16_col":4},"end":{"line_number":279,"utf16_col":26}},"extent_utf16":{"start":{"line_number":279,"utf16_col":0},"end":{"line_number":287,"utf16_col":0}}},{"name":"Event: `session_end`","fully_qualified_name":"Event: `session_end`","kind":"section_3","ident_start":17682,"ident_end":17702,"extent_start":17678,"extent_end":25587,"ident_utf16":{"start":{"line_number":287,"utf16_col":4},"end":{"line_number":287,"utf16_col":24}},"extent_utf16":{"start":{"line_number":287,"utf16_col":0},"end":{"line_number":348,"utf16_col":0}}},{"name":"Event: `panic`","fully_qualified_name":"Event: `panic`","kind":"section_3","ident_start":25591,"ident_end":25605,"extent_start":25587,"extent_end":26686,"ident_utf16":{"start":{"line_number":348,"utf16_col":4},"end":{"line_number":348,"utf16_col":18}},"extent_utf16":{"start":{"line_number":348,"utf16_col":0},"end":{"line_number":360,"utf16_col":0}}},{"name":"Event: `product_usage`","fully_qualified_name":"Event: `product_usage`","kind":"section_3","ident_start":26690,"ident_end":26712,"extent_start":26686,"extent_end":27943,"ident_utf16":{"start":{"line_number":360,"utf16_col":4},"end":{"line_number":360,"utf16_col":26}},"extent_utf16":{"start":{"line_number":360,"utf16_col":0},"end":{"line_number":397,"utf16_col":0}}},{"name":"Event: `operations_summary`","fully_qualified_name":"Event: `operations_summary`","kind":"section_3","ident_start":27947,"ident_end":27974,"extent_start":27943,"extent_end":28798,"ident_utf16":{"start":{"line_number":397,"utf16_col":4},"end":{"line_number":397,"utf16_col":31}},"extent_utf16":{"start":{"line_number":397,"utf16_col":0},"end":{"line_number":420,"utf16_col":0}}},{"name":"What the endpoint does — a shipping gate, not a footnote","fully_qualified_name":"What the endpoint does — a shipping gate, not a footnote","kind":"section_3","ident_start":28802,"ident_end":28860,"extent_start":28798,"extent_end":36171,"ident_utf16":{"start":{"line_number":420,"utf16_col":4},"end":{"line_number":420,"utf16_col":60}},"extent_utf16":{"start":{"line_number":420,"utf16_col":0},"end":{"line_number":479,"utf16_col":0}}},{"name":"What the owner reads back — observed active installs","fully_qualified_name":"What the owner reads back — observed active installs","kind":"section_3","ident_start":36175,"ident_end":36229,"extent_start":36171,"extent_end":37647,"ident_utf16":{"start":{"line_number":479,"utf16_col":4},"end":{"line_number":479,"utf16_col":56}},"extent_utf16":{"start":{"line_number":479,"utf16_col":0},"end":{"line_number":492,"utf16_col":0}}},{"name":"What is never collected — the public red-line list","fully_qualified_name":"What is never collected — the public red-line list","kind":"section_3","ident_start":37651,"ident_end":37703,"extent_start":37647,"extent_end":38987,"ident_utf16":{"start":{"line_number":492,"utf16_col":4},"end":{"line_number":492,"utf16_col":54}},"extent_utf16":{"start":{"line_number":492,"utf16_col":0},"end":{"line_number":499,"utf16_col":0}}}]}},"codeViewLayoutRoute":{"repo":{"id":1137711311,"defaultBranch":"main","name":"Codewhale","ownerLogin":"codewhale-hq","currentUserCanPush":false,"isFork":false,"isEmpty":false,"createdAt":"2026-01-19T18:21:01.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/326694313?v=4","public":true,"private":false,"isOrgOwned":true,"isArchived":false},"currentUser":null,"uploadToken":"m6SEfkzgOhQ0cwyEqshiLFp3X_xnqhibTgiSuKZamUFnctOsK6viZOescThKzQ2v0lUiZew0DOF1V427ooDiLw","allShortcutsEnabled":false,"treeExpanded":true,"path":"docs/TELEMETRY.md","symbolsExpanded":false,"refInfo":{"name":"main","listCacheKey":"v0:1791608600.0","canEdit":false,"currentOid":"406d17ee5f38b643d9f703cfdf8a6906920835dc"},"helpUrl":"https://docs.github.com","githubDevUrl":null},"codeViewFileTreeLayoutRoute":{"fileTree":{"docs":{"items":[{"name":"architecture","path":"docs/architecture","contentType":"directory"},{"name":"assets","path":"docs/assets","contentType":"directory"},{"name":"cloud-facts","path":"docs/cloud-facts","contentType":"directory"},{"name":"decisions","path":"docs/decisions","contentType":"directory"},{"name":"design","path":"docs/design","contentType":"directory"},{"name":"examples","path":"docs/examples","contentType":"directory"},{"name":"id","path":"docs/id","contentType":"directory"},{"name":"images","path":"docs/images","contentType":"directory"},{"name":"releases","path":"docs/releases","contentType":"directory"},{"name":"rfcs","path":"docs/rfcs","contentType":"directory"},{"name":"schemas","path":"docs/schemas","contentType":"directory"},{"name":"skills","path":"docs/skills","contentType":"directory"},{"name":"zh_hans","path":"docs/zh_hans","contentType":"directory"},{"name":"ACCESSIBILITY.md","path":"docs/ACCESSIBILITY.md","contentType":"file"},{"name":"AGENT_ETHOS.md","path":"docs/AGENT_ETHOS.md","contentType":"file"},{"name":"AGENT_RUNTIME.md","path":"docs/AGENT_RUNTIME.md","contentType":"file"},{"name":"ARCHITECTURE.md","path":"docs/ARCHITECTURE.md","contentType":"file"},{"name":"AUTHORIZATION_ORDER.md","path":"docs/AUTHORIZATION_ORDER.md","contentType":"file"},{"name":"AUTOMATIC_WORKFLOWS.md","path":"docs/AUTOMATIC_WORKFLOWS.md","contentType":"file"},{"name":"BUILD_PERFORMANCE.md","path":"docs/BUILD_PERFORMANCE.md","contentType":"file"},{"name":"CACHE.md","path":"docs/CACHE.md","contentType":"file"},{"name":"CATALOG_REFRESH.md","path":"docs/CATALOG_REFRESH.md","contentType":"file"},{"name":"CHANGELOG_ARCHIVE.md","path":"docs/CHANGELOG_ARCHIVE.md","contentType":"file"},{"name":"CLASSROOM_INSTALL.md","path":"docs/CLASSROOM_INSTALL.md","contentType":"file"},{"name":"CLAUDE_PLUGIN_COMPAT.md","path":"docs/CLAUDE_PLUGIN_COMPAT.md","contentType":"file"},{"name":"CLOUD_FACTS.md","path":"docs/CLOUD_FACTS.md","contentType":"file"},{"name":"CNB_MIRROR.md","path":"docs/CNB_MIRROR.md","contentType":"file"},{"name":"CODEWHALE_AGENT.md","path":"docs/CODEWHALE_AGENT.md","contentType":"file"},{"name":"COMMAND_CONTROL_PLANE.md","path":"docs/COMMAND_CONTROL_PLANE.md","contentType":"file"},{"name":"CONFIGURATION.id.md","path":"docs/CONFIGURATION.id.md","contentType":"file"},{"name":"CONFIGURATION.md","path":"docs/CONFIGURATION.md","contentType":"file"},{"name":"CONTRIBUTORS.md","path":"docs/CONTRIBUTORS.md","contentType":"file"},{"name":"CONVERSATION_LIFECYCLE_CONTRACT_PROPOSAL.md","path":"docs/CONVERSATION_LIFECYCLE_CONTRACT_PROPOSAL.md","contentType":"file"},{"name":"DOCKER.md","path":"docs/DOCKER.md","contentType":"file"},{"name":"ENVIRONMENTS.md","path":"docs/ENVIRONMENTS.md","contentType":"file"},{"name":"EXTENSIONS.md","path":"docs/EXTENSIONS.md","contentType":"file"},{"name":"FLEET.id.md","path":"docs/FLEET.id.md","contentType":"file"},{"name":"FLEET.md","path":"docs/FLEET.md","contentType":"file"},{"name":"FLEET_WORKFLOW_TUTORIAL.md","path":"docs/FLEET_WORKFLOW_TUTORIAL.md","contentType":"file"},{"name":"GITHUB_ACTION.md","path":"docs/GITHUB_ACTION.md","contentType":"file"},{"name":"GITHUB_APP.md","path":"docs/GITHUB_APP.md","contentType":"file"},{"name":"GUIDE.md","path":"docs/GUIDE.md","contentType":"file"},{"name":"HOOKS.md","path":"docs/HOOKS.md","contentType":"file"},{"name":"HarmonyOS.md","path":"docs/HarmonyOS.md","contentType":"file"},{"name":"INSTALL.id.md","path":"docs/INSTALL.id.md","contentType":"file"},{"name":"INSTALL.md","path":"docs/INSTALL.md","contentType":"file"},{"name":"INTEGRATIONS_DSH.md","path":"docs/INTEGRATIONS_DSH.md","contentType":"file"},{"name":"ISSUE_TRIAGE.md","path":"docs/ISSUE_TRIAGE.md","contentType":"file"},{"name":"KEYBINDINGS.id.md","path":"docs/KEYBINDINGS.id.md","contentType":"file"},{"name":"KEYBINDINGS.md","path":"docs/KEYBINDINGS.md","contentType":"file"},{"name":"LEGACY_PATHS.md","path":"docs/LEGACY_PATHS.md","contentType":"file"},{"name":"LIVE_SMOKE.md","path":"docs/LIVE_SMOKE.md","contentType":"file"},{"name":"LOCALIZATION.id.md","path":"docs/LOCALIZATION.id.md","contentType":"file"},{"name":"LOCALIZATION.md","path":"docs/LOCALIZATION.md","contentType":"file"},{"name":"LSP_PHP_CUSTOM.md","path":"docs/LSP_PHP_CUSTOM.md","contentType":"file"},{"name":"MCP.id.md","path":"docs/MCP.id.md","contentType":"file"},{"name":"MCP.md","path":"docs/MCP.md","contentType":"file"},{"name":"MEDIA_MODELS.md","path":"docs/MEDIA_MODELS.md","contentType":"file"},{"name":"MEMORY.md","path":"docs/MEMORY.md","contentType":"file"},{"name":"MODEL_LAB.md","path":"docs/MODEL_LAB.md","contentType":"file"},{"name":"MODES.id.md","path":"docs/MODES.id.md","contentType":"file"},{"name":"MODES.md","path":"docs/MODES.md","contentType":"file"},{"name":"MOTION_CONTRACT.md","path":"docs/MOTION_CONTRACT.md","contentType":"file"},{"name":"OPERATIONS_RUNBOOK.md","path":"docs/OPERATIONS_RUNBOOK.md","contentType":"file"},{"name":"PLUGINS.md","path":"docs/PLUGINS.md","contentType":"file"},{"name":"PLUGIN_AUTHORING.md","path":"docs/PLUGIN_AUTHORING.md","contentType":"file"},{"name":"PLUGIN_BUNDLES.md","path":"docs/PLUGIN_BUNDLES.md","contentType":"file"},{"name":"PLUGIN_MARKETPLACE.md","path":"docs/PLUGIN_MARKETPLACE.md","contentType":"file"},{"name":"PLUGIN_PROVIDERS.md","path":"docs/PLUGIN_PROVIDERS.md","contentType":"file"},{"name":"POST_0_9_1_SEAMS.md","path":"docs/POST_0_9_1_SEAMS.md","contentType":"file"},{"name":"PREVIEW_REQUEST.md","path":"docs/PREVIEW_REQUEST.md","contentType":"file"},{"name":"PRODUCT.md","path":"docs/PRODUCT.md","contentType":"file"},{"name":"PROVIDERS.id.md","path":"docs/PROVIDERS.id.md","contentType":"file"},{"name":"PROVIDERS.md","path":"docs/PROVIDERS.md","contentType":"file"},{"name":"README.md","path":"docs/README.md","contentType":"file"},{"name":"READ_MEDIA.md","path":"docs/READ_MEDIA.md","contentType":"file"},{"name":"REBRAND.id.md","path":"docs/REBRAND.id.md","contentType":"file"},{"name":"REBRAND.md","path":"docs/REBRAND.md","contentType":"file"},{"name":"RECEIPTS.md","path":"docs/RECEIPTS.md","contentType":"file"},{"name":"RELEASE_CHECKLIST.md","path":"docs/RELEASE_CHECKLIST.md","contentType":"file"},{"name":"RELEASE_RUNBOOK.md","path":"docs/RELEASE_RUNBOOK.md","contentType":"file"},{"name":"RUNTIME_API.md","path":"docs/RUNTIME_API.md","contentType":"file"},{"name":"RUNTIME_SIMPLIFICATION_DESIGN.md","path":"docs/RUNTIME_SIMPLIFICATION_DESIGN.md","contentType":"file"},{"name":"SANDBOX.md","path":"docs/SANDBOX.md","contentType":"file"},{"name":"SETTINGS_PICKER_FRAMEWORK.md","path":"docs/SETTINGS_PICKER_FRAMEWORK.md","contentType":"file"},{"name":"SKILLS.md","path":"docs/SKILLS.md","contentType":"file"},{"name":"SKILL_EVALUATION.md","path":"docs/SKILL_EVALUATION.md","contentType":"file"},{"name":"SUBAGENTS.md","path":"docs/SUBAGENTS.md","contentType":"file"},{"name":"TELEMETRY.md","path":"docs/TELEMETRY.md","contentType":"file"},{"name":"TERMUX.md","path":"docs/TERMUX.md","contentType":"file"},{"name":"THIRD_PARTY_NOTICES.md","path":"docs/THIRD_PARTY_NOTICES.md","contentType":"file"},{"name":"TOOL_LIFECYCLE.md","path":"docs/TOOL_LIFECYCLE.md","contentType":"file"},{"name":"TOOL_SURFACE.md","path":"docs/TOOL_SURFACE.md","contentType":"file"},{"name":"TUI_MODULARIZATION.md","path":"docs/TUI_MODULARIZATION.md","contentType":"file"},{"name":"VOICE.md","path":"docs/VOICE.md","contentType":"file"},{"name":"WEB.id.md","path":"docs/WEB.id.md","contentType":"file"},{"name":"WEB.md","path":"docs/WEB.md","contentType":"file"},{"name":"WORKFLOW_AUTHORING.md","path":"docs/WORKFLOW_AUTHORING.md","contentType":"file"},{"name":"WORKFLOW_EXPERIMENTAL_SEARCH.md","path":"docs/WORKFLOW_EXPERIMENTAL_SEARCH.md","contentType":"file"},{"name":"WORKROOM_ARCHITECTURE.md","path":"docs/WORKROOM_ARCHITECTURE.md","contentType":"file"},{"name":"WORKROOM_SECURITY.md","path":"docs/WORKROOM_SECURITY.md","contentType":"file"},{"name":"changelog-lifecycle-outbox.md","path":"docs/changelog-lifecycle-outbox.md","contentType":"file"},{"name":"dependency-maintenance.md","path":"docs/dependency-maintenance.md","contentType":"file"},{"name":"features.toml","path":"docs/features.toml","contentType":"file"},{"name":"public-surface-facts.json","path":"docs/public-surface-facts.json","contentType":"file"}],"totalCount":105},"":{"items":[{"name":".cargo","path":".cargo","contentType":"directory"},{"name":".codewhale","path":".codewhale","contentType":"directory"},{"name":".config","path":".config","contentType":"directory"},{"name":".devcontainer","path":".devcontainer","contentType":"directory"},{"name":".github","path":".github","contentType":"directory"},{"name":".winget","path":".winget","contentType":"directory"},{"name":"brand","path":"brand","contentType":"directory"},{"name":"crates","path":"crates","contentType":"directory"},{"name":"deploy","path":"deploy","contentType":"directory"},{"name":"docs","path":"docs","contentType":"directory"},{"name":"extensions","path":"extensions","contentType":"directory"},{"name":"fleets","path":"fleets","contentType":"directory"},{"name":"integrations","path":"integrations","contentType":"directory"},{"name":"nix","path":"nix","contentType":"directory"},{"name":"npm","path":"npm","contentType":"directory"},{"name":"packaging","path":"packaging","contentType":"directory"},{"name":"patches","path":"patches","contentType":"directory"},{"name":"pet","path":"pet","contentType":"directory"},{"name":"plugins","path":"plugins","contentType":"directory"},{"name":"scripts","path":"scripts","contentType":"directory"},{"name":"telemetry-ingest","path":"telemetry-ingest","contentType":"directory"},{"name":"tests","path":"tests","contentType":"directory"},{"name":"vendor","path":"vendor","contentType":"directory"},{"name":"web","path":"web","contentType":"directory"},{"name":"workflows","path":"workflows","contentType":"directory"},{"name":".cnb.yml","path":".cnb.yml","contentType":"file"},{"name":".dockerignore","path":".dockerignore","contentType":"file"},{"name":".env.example","path":".env.example","contentType":"file"},{"name":".gitattributes","path":".gitattributes","contentType":"file"},{"name":".gitguardian.yml","path":".gitguardian.yml","contentType":"file"},{"name":".gitignore","path":".gitignore","contentType":"file"},{"name":".mailmap","path":".mailmap","contentType":"file"},{"name":"AGENTS.md","path":"AGENTS.md","contentType":"file"},{"name":"CHANGELOG.md","path":"CHANGELOG.md","contentType":"file"},{"name":"CLAUDE.md","path":"CLAUDE.md","contentType":"file"},{"name":"CONTRIBUTING.md","path":"CONTRIBUTING.md","contentType":"file"},{"name":"Cargo.lock","path":"Cargo.lock","contentType":"file"},{"name":"Cargo.toml","path":"Cargo.toml","contentType":"file"},{"name":"Dockerfile","path":"Dockerfile","contentType":"file"},{"name":"LICENSE","path":"LICENSE","contentType":"file"},{"name":"README.ar.md","path":"README.ar.md","contentType":"file"},{"name":"README.ca.md","path":"README.ca.md","contentType":"file"},{"name":"README.de.md","path":"README.de.md","contentType":"file"},{"name":"README.es-419.md","path":"README.es-419.md","contentType":"file"},{"name":"README.fr.md","path":"README.fr.md","contentType":"file"},{"name":"README.hi.md","path":"README.hi.md","contentType":"file"},{"name":"README.id.md","path":"README.id.md","contentType":"file"},{"name":"README.it.md","path":"README.it.md","contentType":"file"},{"name":"README.ja-JP.md","path":"README.ja-JP.md","contentType":"file"},{"name":"README.ko-KR.md","path":"README.ko-KR.md","contentType":"file"},{"name":"README.md","path":"README.md","contentType":"file"},{"name":"README.pl.md","path":"README.pl.md","contentType":"file"},{"name":"README.pt-BR.md","path":"README.pt-BR.md","contentType":"file"},{"name":"README.ru.md","path":"README.ru.md","contentType":"file"},{"name":"README.tr.md","path":"README.tr.md","contentType":"file"},{"name":"README.uk.md","path":"README.uk.md","contentType":"file"},{"name":"README.vi.md","path":"README.vi.md","contentType":"file"},{"name":"README.zh-CN.md","path":"README.zh-CN.md","contentType":"file"},{"name":"README.zh-TW.md","path":"README.zh-TW.md","contentType":"file"},{"name":"SECURITY.md","path":"SECURITY.md","contentType":"file"},{"name":"THIRD_PARTY_NOTICES.md","path":"THIRD_PARTY_NOTICES.md","contentType":"file"},{"name":"action.yml","path":"action.yml","contentType":"file"},{"name":"config.example.toml","path":"config.example.toml","contentType":"file"},{"name":"deny.toml","path":"deny.toml","contentType":"file"},{"name":"flake.lock","path":"flake.lock","contentType":"file"},{"name":"flake.nix","path":"flake.nix","contentType":"file"},{"name":"package-lock.json","path":"package-lock.json","contentType":"file"},{"name":"package.json","path":"package.json","contentType":"file"},{"name":"rust-toolchain.toml","path":"rust-toolchain.toml","contentType":"file"}],"totalCount":69}},"fileTreeProcessingTime":33.628524999999996,"foldersToFetch":[]},"codeViewBlobLayoutRoute":{"codeLineWrapEnabled":false,"refInfo":{"name":"main","listCacheKey":"v0:1791608600.0","canEdit":false,"refType":"branch","currentOid":"406d17ee5f38b643d9f703cfdf8a6906920835dc","canEditOnDefaultBranch":false,"fileExistsOnDefault":true},"path":"docs/TELEMETRY.md","blob":{"copilotSWEAgentEnabled":false,"dependabotInfo":{"showConfigurationBanner":false,"configFilePath":null,"networkDependabotPath":"/codewhale-hq/Codewhale/network/updates","dismissConfigurationNoticePath":"/settings/dismiss-notice/dependabot_configuration_notice","configurationNoticeDismissed":null},"displayName":"TELEMETRY.md","displayUrl":"https://github.com/codewhale-hq/Codewhale/blob/main/docs/TELEMETRY.md?raw=true","headerInfo":{"blobSize":"38.1 KB","deleteTooltip":"You must be signed in to make or propose changes","editTooltip":"You must be signed in to make or propose changes","ghDesktopPath":"https://desktop.github.com","isGitLfs":false,"onBranch":true,"shortPath":"6ec1548","siteNavLoginPath":"/login?return_to=https%3A%2F%2Fgithub.com%2Fcodewhale-hq%2FCodewhale%2Fblob%2Fmain%2Fdocs%2FTELEMETRY.md","isCSV":false,"isRichtext":true,"lineInfo":{"truncatedLoc":"499","truncatedSloc":"397"},"mode":"file"},"image":false,"isCodeownersFile":null,"isPlain":false,"isValidLegacyIssueTemplate":false,"isIssueTemplate":false,"isDiscussionTemplate":false,"language":"Markdown","languageID":222,"large":false,"planSupportInfo":{"repoIsFork":null,"repoOwnedByCurrentUser":null,"requestFullPath":"/codewhale-hq/Codewhale/blob/main/docs/TELEMETRY.md","showFreeOrgGatedFeatureMessage":null,"showPlanSupportBanner":null,"upgradeDataAttributes":null,"upgradePath":null},"publishBannersInfo":{"dismissActionNoticePath":"/settings/dismiss-notice/publish_action_from_dockerfile","releasePath":"/codewhale-hq/Codewhale/releases/new?marketplace=true","showPublishActionBanner":false},"rawBlobUrl":"https://github.com/codewhale-hq/Codewhale/raw/refs/heads/main/docs/TELEMETRY.md","renderImageOrRaw":false,"shortPath":null,"symbolsEnabled":true,"tabSize":4,"topBannersInfo":{"overridingGlobalFundingFile":false,"globalPreferredFundingPath":null,"showInvalidCitationWarning":false,"citationHelpUrl":"https://docs.github.com/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-citation-files","actionsOnboardingTip":null},"truncated":false,"viewable":true,"workflowRedirectUrl":null},"copilotInfo":null,"copilotAccessAllowed":false,"copilotSpacesEnabled":false,"modelsAccessAllowed":false,"modelsRepoIntegrationEnabled":false,"isMarketplaceEnabled":true},"codeViewBlobLayoutRoute.StyledBlob":{"rawLines":["# Codewhale product telemetry","","\u003e 阅读简体中文版：[zh_hans/TELEMETRY.md](zh_hans/TELEMETRY.md)","","**Usage analytics are on by default in the current source.** The first","interactive launch gives a localized, nonblocking disclosure naming **Codewhale","and PostHog**, with a direct route to turn counting off. Notice version `5`","describes this policy; displaying it is not recorded as human acceptance.","Missing an older acceptance record does not turn a fresh installation off.","Existing explicit opt-outs remain off across upgrades, and unreadable privacy","state fails closed. Environment and CLI kill switches still take precedence.","","Read the disclosure with `codewhale config telemetry`. Turn usage off in","`/settings` or run `codewhale config set telemetry false`. Turning it back on","in Settings or with `codewhale config set telemetry true` updates the existing","durable preference and privacy records for new sessions. The compatibility","command `codewhale config telemetry --accept-notice 5` remains available, but","is not required for a fresh installation. Collection never includes work content or credentials.","","The PostHog sink is optional and inert until the ingest operator explicitly","configures a project token and approved regional host, and records staging","proof that the actual egress path does not forward the original client IP.","Source readiness does not establish a deployment, an activated processor,","an egress receipt, or a retention setting.","","Codewhale does not collect conversations, code, prompts, files, file/repo/branch","names, model content, or credentials. It sends no per-turn or per-tool timeline.","It does send the closed, aggregate schema below: version and platform classes,","session duration/outcome, feature/error counters, and a random install id that","rotates every 90 days.","","**There is now a real endpoint.** An enabled session sends its batches to the","first-party ingest service at `https://telemetry.codewhale.net/v1/telemetry`,","which is the shipped default for `telemetry_endpoint`. What that service is,","what it stores, and what it structurally cannot store is spelled out in \"What","the endpoint does\" below.","","**To send nothing anywhere, turn telemetry off** (see \"Turning it off\"). To stay","enabled but contact nobody, set `telemetry_endpoint = \"\"`: batches are then","appended to `$CODEWHALE_HOME/telemetry/dryrun.jsonl` on your own machine, byte","for byte what the server would have received, and no HTTP client is ever","constructed. That file is how you audit this document against reality.","","This document is the schema. It is not a summary of the schema: a test in","`crates/telemetry` parses the field names out of this file and asserts set","equality against the structs the serializer actually uses, so a field that is","here and not in the code — or in the code and not here — fails the build.","","Local saved sessions and `codewhale metrics` remain available with telemetry","disabled and require no account or hosted reporting service. Disabling telemetry","does not disable local usage receipts.","","## Turning it off","","There are two off switches and they do different things. Both stop collection","completely; only one of them erases anything.","","```sh","codewhale config set telemetry false     # opt out: stops collection and erases state","CODEWHALE_TELEMETRY=0 codewhale          # kill switch: stops collection, erases nothing","codewhale --telemetry false              # the same kill switch, for one command","```","","**`telemetry = false` in the config file is the opt-out.** It is a floor:","`--telemetry true` and `CODEWHALE_TELEMETRY=1` both lose to it, because a","setting you can undo by accident from a wrapper script is not a setting. It","deletes the random install id, truncates every buffered event and every dry-run","record, and writes a tombstone. Appends, identity/state writes, and delivery all","share the wipe's ordering lock, so once opt-out returns no pre-opt-out write or","POST remains in flight. If any part of that wipe fails, the tombstone is still","there and the buffer is undrainable — a failed wipe fails closed. Every later","run re-asserts the same tombstone for as long as the setting stands, so it","survives. Turning telemetry back on in `/settings` records that explicit preference","in both existing privacy registers; a fresh launch can then clear the tombstone. Nothing buffered before that point is","ever sent.","","**The environment variable and the flag are kill switches, not opt-outs.**","Telemetry is off for the run, nothing is written, nothing is sent — and","nothing on disk is touched or deleted. That is deliberate: a harness or agent","that sets `CODEWHALE_TELEMETRY=0` for one command must not silently discard the","install id and the dry-run records of the person who owns the machine. If you","want the erasing kind, use the config file.","","`CODEWHALE_TELEMETRY` (and its `DEEPSEEK_TELEMETRY` alias) accepts","`0`, `1`, `true`, `false`, `yes`, `no`, `on`, `off`, `enabled`, `disabled`.","A value this list cannot read also resolves to off — a typo in a kill switch","must never resolve to \"on\".","","The first-run notice is not shown when telemetry is already persistently off or","a run-scoped kill switch is active. The notice never rewrites a","`telemetry = false` you put there yourself.","","A repo-local `.codewhale/config.toml` can set neither `telemetry` nor","`telemetry_endpoint`, and a workspace `.env` can set neither. Someone else's","repository cannot turn your telemetry on or aim it at a host of their choosing.","","## Where it lives, and how much of your disk it uses","","Everything is under `$CODEWHALE_HOME/telemetry/` (`0700`), every file `0600`:","","| file | role |","|---|---|","| `buffer.jsonl` | pending events, one JSON object per line |","| `buffer.jsonl.lock` | the sibling ordering lock shared by writes, delivery, arming, and wipe |","| `dryrun.jsonl` | where batches go when the endpoint is configured empty |","| `state.json` | the last app version seen and the last flush attempt |","| `install_id.json` | the random install id and when it was minted |","| `disabled` | the tombstone; present means nothing is appended or sent |","","Both `buffer.jsonl` and `dryrun.jsonl` are rings capped at 512 records or","256 KiB, whichever comes first, with the oldest dropped. The documented","footprint ceiling for the whole directory is therefore **512 KiB plus a few","hundred bytes of metadata**.","","The install id is a random v4 UUID. It is never derived from your hostname,","MAC address, `machine-id`, home directory, username, or executable path — a","derived id is a device fingerprint that survives reinstall and re-identifies","you across your own opt-out. It is regenerated whenever","`$CODEWHALE_HOME/telemetry/` is cleared, which opting out does automatically,","and in any case every 90 days.","","There is no factory-reset command in Codewhale, so this document does not","claim one.","","## When anything is sent, and where","","Nothing is collected or sent when a persistent opt-out or run-scoped kill","switch is in force, or when privacy state is unreadable. TUI and `exec` sessions have exactly one network flush point: an attempt","during shutdown, bounded at three seconds. Short CLI commands such as `config`,","`doctor`, and `auth` do not wait for that network request. They record","`session_end`, seal the event to the local buffer with a much shorter bound, and","return; a configured endpoint sends those buffered events with the next","interactive shutdown flush. An explicitly empty endpoint finalizes its local","dry-run batch immediately.","","There is no startup flush, mid-session flush, per-turn flush, or per-tool-call","flush. Every network shutdown flush re-resolves your setting from disk","immediately beforehand, so `codewhale config set telemetry false` written from","another terminal stops the flush of a session that is already running.","","A flush is **one `POST`** to the resolved endpoint — by default","`https://telemetry.codewhale.net/v1/telemetry`. The request carries a","`content-type: application/json` header, a","`user-agent: codewhale-telemetry/\u003capp_version\u003e`, and the batch body. That is","all: no cookies (the HTTP client is built without a cookie jar to disable), no","redirects (refused outright), no `Authorization` header, no custom headers, and","no query string. The response body is discarded unread; only the status class is","looked at.","","`https://` is required. Plain `http://` is accepted only for a loopback host, so","you can point the client at a recorder of your own and read the wire form","directly; no environment variable overrides that refusal. An endpoint the client","refuses turns telemetry off for the run rather than falling back to a different","destination.","","Any failure — DNS, connect, TLS, timeout, non-2xx — drops the batch. There is","no retry, no backoff, and no re-queue. A permanently offline machine attempts at","most once per flush point and never grows a queue.","","---","","## Event schema","","`SCHEMA_VERSION = 3`. `notice_version = 5` identifies the disclosed default-on","policy; it does not assert human consent or that a notice was seen. The closed","v2 contract still accepts only `consent_version = 4`, retaining its original","explicit opt-in meaning. Fields cannot be mixed between versions. The unchanged","v1 contract remains first-party only and **never sent to PostHog**; it refuses","new fields, surfaces, and `product_usage` events.",""," Every field is an integer, a boolean, or a **closed enum string**, except exactly three bounded strings: `app_version`, `git_sha`, `panic_site`. Each of the three has a written rule and a test pinning the rule. **There is no free-form string type in this schema, and no open-keyed map.** That is the property that makes red line 3 enforceable rather than aspirational.","","### Batch envelope — sent on every POST","","```jsonc","{","  \"schema_version\": 3,","  \"notice_version\": 5,","  \"sent_at\":     \"2026-08-03T18:04:11Z\",   // RFC3339 UTC, second precision","  \"install_id\":  \"3f2a…\",                  // uuid v4, rotates every 90 days","  \"app_version\": \"0.9.12\",","  \"git_sha\":     null,                     // non-null only for SHA-stamped builds","  \"surface\":     \"tui\",","  \"os\":          \"macos\",","  \"arch\":        \"aarch64\",","  \"libc\":        \"none\",","  \"tty\":         true,","  \"events\":      [ … ]","}","```","","| Field | Type | Source anchor | Rule |","|---|---|---|---|","| `schema_version` | `u32` | const in `crates/telemetry/src/event.rs` | Bumped on any field add/remove/retype. Never reused. Pinned by a golden snapshot test. |","| `notice_version` | `u32` | policy constant in `crates/telemetry/src/event.rs` | Exactly `5`; identifies the disclosed opt-out policy, not a human acceptance record. |","| `sent_at` | RFC3339 | `chrono::Utc::now()` | Second precision. Per-**batch** only — events carry no timestamps at all. |","| `install_id` | uuid v4 | `crates/telemetry/src/envelope.rs` | Random, never derived, rotated every 90 days. See \"Where it lives\" above. |","| `app_version` | string | `env!(\"CARGO_PKG_VERSION\")`, as at `crates/telemetry/src/lib.rs:112` | Must match `^\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z.]+)?$`. |","| `git_sha` | string \\| null | `option_env!(\"CODEWHALE_RELEASE_BUILD_SHA\")` — a **new** rustc-env | First 12 hex chars. Emitted **only** when `codewhale_build_support::release_build_sha` saw a valid full SHA in `CODEWHALE_BUILD_SHA`, the legacy `DEEPSEEK_BUILD_SHA`, or `GITHUB_SHA`, in that precedence order. `null` for every unstamped build, with no runtime lookup of any kind. **Never** `CODEWHALE_BUILD_COMMIT` — that falls back to `git_commit` and is the builder's private HEAD. **Never** `Thread.git_sha` (`crates/state/src/lib.rs:93`) — that is the user's workspace commit and a red line, one identifier away by name. |","| `surface` | enum | explicitly set by the emitting client | `tui \\| exec \\| cli \\| app-server \\| mcp-server \\| serve \\| website \\| web-app \\| desktop \\| control-plane \\| vscode-extension`. Runtime metrics keep their existing collector. Browser product counts use the same closed envelope. A declared surface is not proof its client is deployed. `vscode-extension` is an extension client of this schema, deliberately generic the way `web-app` and `desktop` are: the editor's own name and version are **not** collected. Widening this whitelist changes no field, so the schema version is unchanged. |","| `os` | enum | `std::env::consts::OS`, as at `crates/cli/src/update.rs:41` | Whitelist: `linux \\| macos \\| windows \\| freebsd \\| android \\| other`. |","| `arch` | enum | `std::env::consts::ARCH` | `x86_64 \\| aarch64 \\| other`. |","| `libc` | enum | `cfg!(target_env)` — **compile time** | `gnu \\| musl \\| none`. Runtime detection reads distro vendor strings; compile-time is free and leaks nothing. |","| `tty` | bool | `std::io::IsTerminal`, as at `crates/telemetry/src/envelope.rs:196` | `stdin().is_terminal() \u0026\u0026 stdout().is_terminal()`. |","| `events` | array | the drained buffer | Every element is one of the six events below and nothing else. Capped at 200 events or 64 KiB per batch; a batch that would exceed either cap leaves the remainder buffered for the next flush. |","","**`os_major` is not collected.** Reading it costs unsafe FFI on two platforms plus a file parser on a third, in the one crate whose entire value is being small enough to audit — and `os`, `arch`, and `libc` are free and answer the platform question. It may be reconsidered if the stored data ever shows that the OS-version cut is what triage is missing; a hunch is not that evidence.","","### Which surfaces emit","","Every runtime surface uses the same `decide` and flush recheck: readable privacy","state, resolvable home, valid endpoint, and no persistent opt-out or run kill","switch. Missing preferences default on. The interactive TUI shows the disclosure;","headless commands never synthesize consent. Existing runtime events and counters","are unchanged; adding PostHog does not add a second runtime collector.","","### An embedder declares the server it started","","A client that starts `codewhale serve` may name itself, so its sessions are not","counted as anonymous `serve` traffic from nobody in particular. It sets","`CODEWHALE_TELEMETRY_SURFACE` to a value in the `surface` whitelist before","spawning the server; the extension client uses `vscode-extension`.","","Three properties of that read are deliberate:","","- **`serve` only.** The variable is inherited by descendant processes, and an","  agent's shell command runs `codewhale` descendants carrying this environment.","  Only the branch that *is* the embedder's own server consults it, so a nested","  `codewhale exec` cannot report itself as the embedder.","- **`tui` is refused**, and `serve --mcp` still reports `mcp-server`: nothing","  starts the interactive terminal UI on a user's behalf, and a server is not an","  MCP server because an embedder said so.","- **An unrecognised name is dropped, not repaired.** A value outside the","  whitelist falls back to `serve` rather than failing startup or being guessed","  at; the field is a label, and the default is the honest one.","","This changes how an embedder's sessions are *labelled*. It does not change","whether anything may be collected: the server resolves that itself, from the","same durable config, the same setup state, and the same `CODEWHALE_TELEMETRY`","run-scoped kill switch. An embedder cannot enable collection where the user has","turned it off, and a durable opt-out in one client is a durable opt-out for every","client on the machine, because they share one home and one install identity.","","The extension client is the worked example: it holds a single on/off setting and","passes `CODEWHALE_TELEMETRY=0` when the user turns reporting off. It contains no","payload builder, no buffer, and no transport of its own — so its sessions share","the home's `install_id` rather than minting a second one, and one installation is","one install in every count derived from that id.","","Because that switch is run-scoped rather than a durable opt-out, turning it off","stops the engine this extension starts and leaves the shared buffer and identity","alone: those belong to every surface on the machine, not to one window, and","clearing them would silently change what the user's terminal sessions do. A user","who wants reporting stopped and cleared everywhere does that once, with","`codewhale config set telemetry false`.","","Website and application clients use `product_usage`, with notice version `5`,","a random browser-local v4 ID rotated after 90 days, `os = other`, `arch = other`,","`libc = none`, `tty = false`, and `git_sha = null`. They do not inspect the browser","fingerprint. Their configured same-origin proxy forwards only this bounded JSON","to the first-party ingest, with no incoming cookies, headers, URLs, or identities.","The browser endpoint is inert if unconfigured. Browser opt-out clears pending","counts and local identity; actions taken while disabled are never backfilled.","Product usage settings belong in the app and runtime; marketing privacy details","and any website opt-out belong on the privacy page.","","### Event: `install_or_upgrade`","","Emitted once when `state.json`'s `last_version` differs from `app_version`.","","```jsonc","{ \"event\": \"install_or_upgrade\", \"kind\": \"upgrade\", \"previous_version\": \"0.9.3\" }","```","","| Field | Type | Source | Rule |","|---|---|---|---|","| `kind` | enum | derived | `install` (no prior record) \\| `upgrade` \\| `downgrade`. |","| `previous_version` | string \\| null | `$CODEWHALE_HOME/telemetry/state.json` **only** | Same regex as `app_version`. Never derived from session history or config mtimes — those files have a different privacy contract. |","","### Event: `session_start`","","```jsonc","{ \"event\": \"session_start\", \"source\": \"interactive\" }","```","","`source` is `SessionSource` (`crates/state/src/lib.rs:34-41`) stringified by `session_source_to_str` (`:1909-1917`): `interactive | resume | fork | api | unknown`.","","### Event: `session_end`","","The workhorse. Everything a session accumulated ships here, once.","","```jsonc","{","  \"event\": \"session_end\",","  \"duration_bucket\": \"1m_10m\",","  \"exit_class\": \"clean\",","  \"cold_start_bucket\": \"250_1000\",","  \"providers\": [\"deepseek\", \"custom\"],","  \"counters\": { \"turns\": 14, \"tool_calls\": 61, \"fleet_dispatch\": 0, \"workflow_run\": 0,","                \"subagent_spawn\": 2, \"mcp_server_connected\": 0, \"memory_search\": 0,","                \"approval_modal_shown\": 0, \"approval_auto_allowed\": 0,","                \"command_palette_open\": 3 },","  \"errors\":   { \"auth_preflight_failed\": 0, \"provider_http_4xx\": 0, \"provider_http_5xx\": 1,","                \"tool_denied_by_policy\": 0, \"tool_timeout\": 0, \"network_error\": 0 },","  \"turn_wall\": { \"lt_5s\": 9, \"5_30s\": 4, \"30_120s\": 1, \"gte_120s\": 0 }","}","```","","**`counters` and `errors` are `#[derive(Serialize)]` structs of named `u32` fields, not maps.** Every field is serialized including zeros. The key set is closed by the compiler: adding a counter requires editing `crates/telemetry/src/event.rs`, which is where the doc-match test lives.","","**`duration_bucket`** — `chrono` delta from `app.session_started_at` (`crates/tui/src/tui/app.rs:1889`). Half-open, seconds: `lt_1m` (`d \u003c 60`), `1m_10m` (`60 ≤ d \u003c 600`), `10m_60m` (`600 ≤ d \u003c 3600`), `gt_60m` (`d ≥ 3600`).","","**`exit_class`** — `clean | signal | panic | error`. **Derived from an explicit `AtomicU8`, never from an exit code.** `RunTerminationReason::Canceled` maps to exit 130 (`crates/tui/src/core/runtime_contract/termination.rs:53`), the same value the signal task uses (`crates/tui/src/lib.rs:682`, 128+SIGINT), so a code-based derivation would report every Esc-cancelled turn as a signal. The atomic is set by the panic hook (`crates/tui/src/lib.rs:1582`), by the signal task (`:678-696`) before `std::process::exit`, and on the clean path from `RunTerminationReason::is_success()` (`crates/tui/src/core/runtime_contract/termination.rs:44-46`) — `error` otherwise. Do **not** use `exec_failure_exit_code` (`crates/tui/src/lib.rs:10432`): it knows only `{75, 1}` and would report an approval-required exit (3) as a generic failure.","","**`cold_start_bucket`** — from `startup_trace::elapsed_ms()`, which reads `PROCESS_START` directly and is independent of the startup summary's buffer clear (`crates/runtime/src/startup_trace.rs:39-45`). Boundaries: `lt_250`, `250_1000`, `1000_3000`, `gte_3000`. Absent on non-TUI surfaces.","","**`providers`** — sorted, deduplicated array of `ProviderKind::as_str()` (`crates/config/src/provider_kind.rs:295`, a `\u0026'static str` from a closed enum; `Custom` yields the literal `\"custom\"`). **The API takes `ProviderKind` by value, never `\u0026str`.** Do not call `ProviderKind::parse` or `parse_config_identity` (`:300`, `:330`) — those are for config-table resolution. **Do not read** `provider_identity_for_persistence()` (`crates/tui/src/tui/app.rs:5049`), `provider_id_for_persistence()` (`:5058`), `ExecStreamMeta.provider_id` (`crates/tui/src/lib.rs:10220`), or `PlannedTurnRoute.effective_provider_label` (`crates/tui/src/turn_route_plan.rs:189-193`) — all four return the customer's own `[providers.\u003cname\u003e]` table key when the route is Custom. This is the single most likely leak in the feature: it is one field away from the natural seam and `/status` already prints it (`crates/tui/src/commands/groups/config/status.rs:24-28`). **No model id is ever sent, for any provider** — `crates/runtime/src/safe_label.rs:11-15` documents that a model id can be a path, a URL, or a deployment id that is itself a credential.","","**`counters`** — closed field set. Every bump happens at the **call site**, never inside a conditionally-entered handler:","","| field | source anchor |","|---|---|","| `turns` | `run_event_loop` in `crates/tui/src/tui/ui/event_loop.rs`, immediately before it calls `execute_turn_end_observer_hook`. Never inside that hook: its first statement is `if !app.hooks.has_hooks_for_event(HookEvent::TurnEnd) { return Ok(()); }` (`crates/tui/src/tui/ui/observer_hooks.rs`), and the natural future optimization hoists that check to the call site, silently zeroing the counter for every user without hooks. |","| `tool_calls` | `execute_tool_with_lock` in `crates/tui/src/core/engine/tool_execution.rs` — surface-agnostic, fires for exec and CLI too |","| `fleet_dispatch` | `create_queued_run_with_descriptor` in `crates/tui/src/fleet/manager.rs` — the single funnel that `create_run` and `create_queued_run` both land in; counting at either caller would double-count a plain `fleet run`. |","| `workflow_run` | bumped in `WorkflowTool::execute` (`crates/tui/src/tools/workflow/mod.rs`) only after `parse_workflow_action` returns an `Ok(WorkflowAction)`, never from `input[\"action\"]`. The JSON Schema `enum` in `WorkflowTool::input_schema` is what is published *to the model* — a declaration, not a guard; the real parse also accepts `spawn\\|wait\\|list\\|inspect\\|stop\\|abort`, and its reject arm (`Invalid workflow action '…'`) embeds the model string verbatim, so a rejected action is never counted. |","| `subagent_spawn` | `apply_agent_spawned_status_and_observer` in `crates/tui/src/tui/ui/apply.rs` |","| `mcp_server_connected` | bumped when a server snapshot's `.connected` is true, in `snapshot_from_config` (`crates/tui/src/mcp.rs`); never `name`, `command_or_url`, or `error` — server names are user-chosen and routinely internal infra |","| `memory_search` | `tool_name == \"memory_search\"` (the tool registered in `crates/tui/src/tools/native_memory.rs`), counted at the same `execute_tool_with_lock` choke point |","| `approval_modal_shown` | the `Event::ApprovalRequired` arm of `run_event_loop` (`crates/tui/src/tui/ui/event_loop.rs`; the event is defined in `crates/tui/src/core/events.rs`) |","| `approval_auto_allowed` | `tool_ask_rule_decision_for_context` in `crates/tui/src/core/engine.rs`. Count only. Never `matched_rule`, `reason()`, the command, or argv — `auto_allow` patterns are user-authored command strings (`crates/execpolicy/src/command_safety.rs:35/309`) |","| `command_palette_open` | the palette key path in `run_event_loop` (`crates/tui/src/tui/ui/event_loop.rs`) and `handle_context_menu_action` in `crates/tui/src/tui/mouse_ui.rs` |","","**`errors`** — closed field set. Every value is a **variant discriminant**, never `err.to_string()`:","","| field | source anchor |","|---|---|","| `auth_preflight_failed` | discriminant of `CredentialReadiness` (`crates/workflow/src/fleet_preflight.rs:37-58`) / `ProviderAuthClass` (`crates/tui/src/provider_readiness.rs:32`). Discriminant only — `Missing { detail }` carries free text |","| `provider_http_4xx` | `status.as_u16() / 100 == 4`, captured at `crates/tui/src/client/chat.rs:595` and `:673` **before** the `bail!`. One row per field, because the doc-match test reads this table field for field |","| `provider_http_5xx` | `status.as_u16() / 100 == 5`, same capture points |","| `tool_denied_by_policy` | the `permission_denied` arm of the 8-variant match at `crates/tui/src/core/engine/tool_execution.rs:512-531` |","| `tool_timeout` | the `timeout` arm, same match |","| `network_error` | `retry_reason_label_and_human()`'s `\u0026'static str` half, `crates/tui/src/client.rs:2659` |","","Why discriminants and nothing else: `ToolError::PathEscape`'s `Display` *is* an absolute path (`crates/tools/src/lib.rs:61`); `fim.rs:48-50`'s `Display` *is* a literal source fragment the model emitted; `secrets/src/lib.rs:50`'s `Display` carries the secret store's absolute path; every `LlmError` variant carries the raw provider HTTP body verbatim (`crates/tui/src/llm_client/mod.rs:327`), and a 400 from a content filter routinely echoes the prompt.","","**`turn_wall`** — a per-session histogram of counts, never per-turn events. `lt_5s`, `5_30s`, `30_120s`, `gte_120s`. Recorded by `observe_turn_secs` next to the `turns` bump in `run_event_loop`, which already has the turn duration in hand.","","### Event: `panic`","","Appended **synchronously** by the panic hook, because a `session_end` may never be written.","","```jsonc","{ \"event\": \"panic\", \"site\": \"crates/tui/src/lib.rs:1582:5\" }","```","","`site` comes from `panic_info.location()` (`crates/tui/src/lib.rs:1597-1600`) or `Location::caller()` (`crates/tui/src/utils.rs:523`). **Allowlist reduction, not optional:** emit verbatim only if `file()` starts with `crates/`; otherwise emit the literal `\"\u003cdep\u003e\"`. Must match `^crates/[A-Za-z0-9_/.-]+\\.rs:\\d+:\\d+$` or `^\u003cdep\u003e$`. There is no `--remap-path-prefix` in this repo (no `.cargo/config.toml`; `Cargo.toml:69-74` sets only `lto`/`strip`/`codegen-units`), so a panic inside a registry dependency yields `/Users/\u003cbuilder\u003e/.cargo/registry/src/…/ratatui-0.29.0/src/…` — the **build machine's username**, shipped from every user's binary.","","**The panic message is never sent.** The hook at `crates/tui/src/lib.rs:1590-1596` builds `msg` from the payload; telemetry must not read it. A slicing panic embeds the entire string being sliced, and this tree slices user and model text in dozens of places.","","### Event: `product_usage`","","One aggregate of explicit product interactions, with every field a saturating","`u32`, including zero values. No page paths, URLs, referrers, search terms,","account/session IDs, text, or action timestamps are permitted. Clients flush","aggregate counts on page exit or when hidden, rather than each action.","","```jsonc","{","  \"event\": \"product_usage\",","  \"counters\": {","    \"page_view\": 1,","    \"docs_view\": 0,","    \"install_copy\": 0,","    \"download\": 0,","    \"signup\": 0,","    \"login\": 0,","    \"session_create\": 0,","    \"session_resume\": 0,","    \"turn_submit\": 0,","    \"turn_complete\": 0,","    \"settings_open\": 0,","    \"integration_connect\": 0,","    \"error_shown\": 0","  }","}","```","","`page_view` counts a page view and `docs_view` a documentation view; `install_copy`","and `download` count installation actions. `signup` and `login` count successful","authentication actions, never identity. `session_create`, `session_resume`,","`turn_submit`, and `turn_complete` count their named product actions.","`settings_open`, `integration_connect`, and `error_shown` are counts only:","never the selected setting, integration name, error body, or work content.","An event's availability depends on the emitting client; zero is not proof a","feature was exercised or available.","","### Event: `operations_summary`","","Anonymous service health aggregates from the existing control-plane signal ledger.","Exactly these six saturating `u32` fields are accepted, only on `control-plane`.","This requires an explicit operator delivery/processor configuration, independently","of the end-user analytics choice. Each batch uses a fresh random v4 `install_id`;","there is no user/account/session join. No per-request rows, routes, request","digests, IDs, error text, traces, or timing series are permitted. `requests` and","`errors` count requests and failures; `duration_ms_total` and `duration_ms_max`","are aggregate latency values; `probes` and `probes_failed` count health probes.","","```jsonc","{","  \"event\": \"operations_summary\",","  \"requests\": 10,","  \"errors\": 1,","  \"duration_ms_total\": 1500,","  \"duration_ms_max\": 300,","  \"probes\": 2,","  \"probes_failed\": 0","}","```","","### What the endpoint does — a shipping gate, not a footnote","","This section was a gate on configuring any non-loopback endpoint. The endpoint is now configured by default, so this is a description of a service that exists rather than a promise about one that might.","","**What it is.** `https://telemetry.codewhale.net/v1/telemetry` — a Cloudflare Worker named `codewhale-telemetry-ingest`, whose complete source is in this repository at [`telemetry-ingest/`](../telemetry-ingest/). It is the single schema and storage authority; browser applications may use a same-origin proxy that forwards only the body. There is no telemetry queue or additional runtime collector. It is write-only: nothing in the Worker can read back what was stored, and querying happens out of band through Cloudflare's SQL API with the owner's token. The hostname is deliberately self-describing, so anyone inspecting their own network traffic can tell what it is from the name alone.","","**What it stores.** Everything in this document and nothing else, in Workers Analytics Engine — one row per event. The validator in `telemetry-ingest/src/schema.ts` is a **closed** field set: an unknown key anywhere in a batch rejects the whole batch with `400`. A future client bug that starts attaching a path, a prompt, or a provider table name gets refused by the server rather than quietly stored. `telemetry-ingest/test/schema-doc.test.ts` parses the field names and enum spellings back out of *this file* and asserts set equality against the validator, and `telemetry-ingest/test/ingest.test.ts` posts the Rust client's own pinned golden batch and asserts it is accepted byte for byte — so this document, the client, and the endpoint cannot drift apart without a red test.","","Batches are **IP-stripped at ingest**. No IP is stored, logged, or joined to `install_id` — and that is structural rather than a setting anyone could flip. An Analytics Engine row is exactly `_sample_interval`, `blob1`–`blob20`, `dataset`, `double1`–`double20`, `index1`, and `timestamp`. Every one of those columns is written by the Worker's own `writeDataPoint` call; there is no implicit column, so **there is no IP, country, or geo column** — no slot one could occupy even if the code wanted it there. And the code cannot want it:","","- The handler reads exactly **two** request headers — `content-type` and `content-length`. Nothing else, ever.","- It never touches the request's `cf` property, so country, colo, city, region, ASN, timezone, and coordinates are never in scope.","- The function that builds every stored row cannot see the request at all; its input type is the validated batch body.","- Nothing logs. `invocation_logs` is off in `wrangler.jsonc` — Cloudflare describes those as \"enriched with information available to Cloudflare in the context of the invocation\", which is exactly the class of automatic per-request record this service will not keep — and there is no `console.*` call in the source.","- Rate limiting is keyed on `install_id` from the validated body, never on a network address. An IP-keyed limiter would mean this Worker handles IPs. It is the weaker limiter and it is the right trade.","- `telemetry-ingest/test/no-ip.test.ts` reads the shipped source as text and fails the build if any address or geo name appears, if the set of headers read grows past two, if a `console.*` call is added, or if a `Response` is ever constructed with a body.","","**Retention: three months.** That is Cloudflare's fixed window for Analytics Engine and it is not configurable, so it is a ceiling rather than a policy — there is no setting that could make it longer.","","**Optional PostHog processor.** After first-party storage, an explicitly","configured ingest may forward validated schema-v3 / notice-v5 batches and","legacy schema-v2 / consent-v4 batches to","PostHog's [batch capture API](https://posthog.com/docs/api/capture). The only","permitted origins are `https://us.i.posthog.com` and `https://eu.i.posthog.com`.","Legacy v1 batches cannot reach that path. PostHog receives the same bounded","envelope and event fields, the batch timestamp as its event timestamp, and","`codewhale:\u003cinstall_id\u003e` as its anonymous `distinct_id`. Events are named","`codewhale_install_or_upgrade`, `codewhale_session_start`,","`codewhale_session_end`, `codewhale_panic`, `codewhale_product_usage`, or","`codewhale_operations_summary`.","`$process_person_profile = false`, `$geoip_disable = true`, and `$ip = null`","are fixed transport controls. No request metadata, profile identification,","SDK, autocapture, session replay, advertising, or work content is forwarded.","A fresh server request has no user cookies or authorization headers, cannot","follow redirects, and is limited to 1.5 seconds. There are no retries or logs;","a failure does not change a successful first-party ingest response.","","The PostHog project's retention and privacy settings are separate deployment","configuration and must be reviewed before activation. The Analytics Engine","three-month limit does not establish a PostHog retention period.","","**The edge egress path also requires staging proof.** [Cloudflare documents](https://developers.cloudflare.com/fundamentals/reference/http-headers/#cf-connecting-ip-in-worker-subrequests)","that Worker subrequests to non-Cloudflare zones can receive platform-added","client-IP headers. Fresh JavaScript headers and local fetch tests cannot prove","those headers are removed. `POSTHOG_IP_SAFE_EGRESS_VERIFIED=\"true\"` is an explicit","operator prerequisite alongside the host and token, and must remain unset","until a receipt for the actual deployment and regional destination confirms","no original client IP in any received header, including `CF-Connecting-IP`,","`X-Forwarded-For`, and `X-Real-IP`. The flag does not strip platform headers.","Requalify a changed egress path; if it cannot pass, keep the sink disabled or","run only its delivery in a detached first-party context. No such live proof","is established by this source change.","","**Every response is a bare status with an empty body** — `204` accepted, `400` schema violation, `404`/`405` wrong path or method, `413` oversized, `415` wrong content type, `429` rate-limited, `500` internal. The endpoint cannot echo back what it received or what it holds, and because the client drops the batch on anything that is not 2xx, a rejection is invisible to you by construction and a server error can never surface as a client-visible failure.","","`install_id` rotates client-side every 90 days (`rotated_at` in `install_id.json`), so no single identifier spans a long history. This costs longitudinal accuracy and the docs say so: **no count derived from `install_id` is a user count.** It is a lower bound on distinct machine-installs in a window, and it undercounts a returning user across a rotation.","","**Turning it off deletes what was kept locally, not what was already sent.** `codewhale config set telemetry false` erases the install id, the buffer, and the dry-run records on your machine, and stops anything further. Rows already accepted by the endpoint are keyed only by a rotating random id that is now gone; first-party rows age out with the three-month window. If PostHog processing is activated, already-delivered processor records follow that project’s configured retention. The client has no remote deletion API and does not claim that local opt-out erases delivered records.","","### What the owner reads back — observed active installs","","The one product metric derived from this data is **observed active installs**: the number of distinct rotating anonymous install ids that produced a `session_start` event on a UTC day. That is the whole definition. It is not a count of people, not a count of accounts, and not a count of total installs — the id is per installation, rotates every 90 days, and is deleted on opt-out, so no number derived from it can be any of those things.","","The exact owner command is checked into the repository, so the routine query is reviewable code rather than SQL pasted from a chat:","","```sh","cd telemetry-ingest","CF_ACCOUNT_ID=... CF_API_TOKEN=... npm run report:active-installs","```","","It prints the daily series, a 7-day trend over complete UTC days, the freshness of the newest ingested event, and — with the numbers, in both text and `--json` output — the coverage caveats: clients older than the telemetry feature, opted-out installs, and non-emitting environments (kill switches, fleet workers, offline shutdowns, dropped flushes) are invisible, so every count is a lower bound; and because ids rotate, week-over-week comparisons are not a retention metric. The report's read path is itself tested: the install id appears only inside an aggregate, no payload column is selected, and the wording can never drift into calling the result users. (`npm run report:dau` remains as a compatibility alias for the same report.)","","### What is never collected — the public red-line list","","Prompts; completions; tool arguments; diffs; patches; file contents; filenames; absolute or relative paths; git remotes; repo names; branch names; workspace commit SHAs; memory entries; chat history; API keys, tokens, cookies, or `Authorization` headers (including any boolean asserting a key exists); model ids of any kind; custom provider table names; MCP server names, commands, or URLs; approval rule text; error message bodies; panic message text; per-event timestamps; keystrokes; clipboard; screenshots; microphone; camera; location; and any third-party ad or analytics SDK — there are none in the runtime binary and none may be added.","","Two named traps for the implementer. `crates/state/src/lib.rs` persists `git_sha`, `git_branch`, `git_origin_url`, `cwd`, and `path` on the threads table (`:93, :399, :653`): a payload builder that accepts a `Thread` or `ThreadMeta` and derives `Serialize` breaches the contract in one line. **Never derive `Serialize` over an existing state type** — build every telemetry struct from scratch with explicit fields. And `crates/core/src/lib.rs:1389-1398` is the one place in the tree where the word `telemetry` sits inside a JSON object next to `prompt`, `base_url`, and `has_api_key`. It is the object someone will copy. Do not.","","---"],"stylingDirectives":[[[0,29,"pl-mh"],[2,29,"pl-en"]],[],[[0,54,"pl-ent"],[0,2,"pl-ent"],[10,11,"pl-s"],[31,32,"pl-s"],[32,33,"pl-s"],[33,53,"pl-corl"],[53,54,"pl-s"]],[[0,0,"pl-ent"]],[[0,2,"pl-s"],[58,60,"pl-s"]],[[68,70,"pl-s"]],[[11,13,"pl-s"],[72,73,"pl-s"],[73,74,"pl-c1"],[74,75,"pl-s"]],[],[],[],[],[],[[25,26,"pl-s"],[26,52,"pl-c1"],[52,53,"pl-s"]],[[0,1,"pl-s"],[1,10,"pl-c1"],[10,11,"pl-s"],[19,20,"pl-s"],[20,56,"pl-c1"],[56,57,"pl-s"]],[[20,21,"pl-s"],[21,56,"pl-c1"],[56,57,"pl-s"]],[],[[8,9,"pl-s"],[9,53,"pl-c1"],[53,54,"pl-s"]],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[[0,2,"pl-s"],[31,33,"pl-s"]],[[30,31,"pl-s"],[31,75,"pl-c1"],[75,76,"pl-s"]],[[33,34,"pl-s"],[34,52,"pl-c1"],[52,53,"pl-s"]],[],[],[],[[0,2,"pl-s"],[46,48,"pl-s"]],[[32,33,"pl-s"],[33,56,"pl-c1"],[56,57,"pl-s"]],[[12,13,"pl-s"],[13,51,"pl-c1"],[51,52,"pl-s"]],[],[],[],[],[[0,1,"pl-s"],[1,17,"pl-c1"],[17,18,"pl-s"]],[],[],[],[[25,26,"pl-s"],[26,43,"pl-c1"],[43,44,"pl-s"]],[],[],[],[[0,17,"pl-mh"],[3,17,"pl-en"]],[],[],[],[],[[0,3,"pl-s"],[3,5,"pl-en"]],[[17,20,"pl-c1"],[31,36,"pl-c1"],[41,85,"pl-c"],[41,42,"pl-c"]],[[41,88,"pl-c"],[41,42,"pl-c"]],[[22,27,"pl-c1"],[41,80,"pl-c"],[41,42,"pl-c"]],[[0,3,"pl-s"]],[],[[0,2,"pl-s"],[2,3,"pl-s"],[3,20,"pl-c1"],[20,21,"pl-s"],[56,58,"pl-s"]],[[0,1,"pl-s"],[1,17,"pl-c1"],[17,18,"pl-s"],[23,24,"pl-s"],[24,45,"pl-c1"],[45,46,"pl-s"]],[],[],[],[],[],[],[],[[39,40,"pl-s"],[40,49,"pl-c1"],[49,50,"pl-s"]],[],[],[],[[0,2,"pl-s"],[72,74,"pl-s"]],[],[],[[10,11,"pl-s"],[11,32,"pl-c1"],[32,33,"pl-s"]],[],[],[],[[0,1,"pl-s"],[1,20,"pl-c1"],[20,21,"pl-s"],[31,32,"pl-s"],[32,50,"pl-c1"],[50,51,"pl-s"]],[[0,1,"pl-s"],[1,2,"pl-c1"],[2,3,"pl-s"],[5,6,"pl-s"],[6,7,"pl-c1"],[7,8,"pl-s"],[10,11,"pl-s"],[11,15,"pl-c1"],[15,16,"pl-s"],[18,19,"pl-s"],[19,24,"pl-c1"],[24,25,"pl-s"],[27,28,"pl-s"],[28,31,"pl-c1"],[31,32,"pl-s"],[34,35,"pl-s"],[35,37,"pl-c1"],[37,38,"pl-s"],[40,41,"pl-s"],[41,43,"pl-c1"],[43,44,"pl-s"],[46,47,"pl-s"],[47,50,"pl-c1"],[50,51,"pl-s"],[53,54,"pl-s"],[54,61,"pl-c1"],[61,62,"pl-s"],[64,65,"pl-s"],[65,73,"pl-c1"],[73,74,"pl-s"]],[],[],[],[],[],[[0,1,"pl-s"],[1,18,"pl-c1"],[18,19,"pl-s"]],[],[[13,14,"pl-s"],[14,36,"pl-c1"],[36,37,"pl-s"],[54,55,"pl-s"],[55,64,"pl-c1"],[64,65,"pl-s"]],[[0,1,"pl-s"],[1,19,"pl-c1"],[19,20,"pl-s"],[38,39,"pl-s"],[39,43,"pl-c1"],[43,44,"pl-s"]],[],[],[[0,52,"pl-mh"],[3,52,"pl-en"]],[],[[20,21,"pl-s"],[21,47,"pl-c1"],[47,48,"pl-s"],[50,51,"pl-s"],[51,55,"pl-c1"],[55,56,"pl-s"],[70,71,"pl-s"],[71,75,"pl-c1"],[75,76,"pl-s"]],[],[[0,1,"pl-ml"],[7,8,"pl-ml"],[14,15,"pl-ml"]],[[0,1,"pl-ml"],[4,5,"pl-ml"],[8,9,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,15,"pl-c1"],[15,16,"pl-s"],[17,18,"pl-ml"],[60,61,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,20,"pl-c1"],[20,21,"pl-s"],[22,23,"pl-ml"],[95,96,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,15,"pl-c1"],[15,16,"pl-s"],[17,18,"pl-ml"],[74,75,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,13,"pl-c1"],[13,14,"pl-s"],[15,16,"pl-ml"],[70,71,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,18,"pl-c1"],[18,19,"pl-s"],[20,21,"pl-ml"],[67,68,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,11,"pl-c1"],[11,12,"pl-s"],[13,14,"pl-ml"],[72,73,"pl-ml"]],[],[[5,6,"pl-s"],[6,18,"pl-c1"],[18,19,"pl-s"],[24,25,"pl-s"],[25,37,"pl-c1"],[37,38,"pl-s"]],[],[[55,57,"pl-s"]],[[25,27,"pl-s"]],[],[],[[13,14,"pl-s"],[14,24,"pl-c1"],[24,25,"pl-s"]],[],[],[[0,1,"pl-s"],[1,27,"pl-c1"],[27,28,"pl-s"]],[],[],[],[],[],[[0,35,"pl-mh"],[3,35,"pl-en"]],[],[],[[65,66,"pl-s"],[66,70,"pl-c1"],[70,71,"pl-s"]],[[70,71,"pl-s"],[71,77,"pl-c1"],[77,78,"pl-s"]],[[0,1,"pl-s"],[1,7,"pl-c1"],[7,8,"pl-s"],[14,15,"pl-s"],[15,19,"pl-c1"],[19,20,"pl-s"]],[[0,1,"pl-s"],[1,12,"pl-c1"],[12,13,"pl-s"]],[],[],[],[],[],[],[[27,28,"pl-s"],[28,64,"pl-c1"],[64,65,"pl-s"]],[],[],[[11,13,"pl-s"],[17,18,"pl-s"],[18,22,"pl-c1"],[22,23,"pl-s"],[23,25,"pl-s"]],[[0,1,"pl-s"],[1,45,"pl-c1"],[45,46,"pl-s"]],[[0,1,"pl-s"],[1,31,"pl-c1"],[31,32,"pl-s"]],[[0,1,"pl-s"],[1,46,"pl-c1"],[46,47,"pl-s"]],[],[[33,34,"pl-s"],[34,47,"pl-c1"],[47,48,"pl-s"]],[],[],[],[[0,1,"pl-s"],[1,9,"pl-c1"],[9,10,"pl-s"],[30,31,"pl-s"],[31,38,"pl-c1"],[38,39,"pl-s"]],[],[],[],[],[],[],[],[],[],[[0,3,"pl-ms"]],[],[[0,15,"pl-mh"],[3,15,"pl-en"]],[],[[0,1,"pl-s"],[1,19,"pl-c1"],[19,20,"pl-s"],[22,23,"pl-s"],[23,41,"pl-c1"],[41,42,"pl-s"]],[],[[31,32,"pl-s"],[32,51,"pl-c1"],[51,52,"pl-s"]],[],[[41,43,"pl-s"],[64,66,"pl-s"]],[[26,27,"pl-s"],[27,40,"pl-c1"],[40,41,"pl-s"]],[],[[44,46,"pl-s"],[64,66,"pl-s"],[106,107,"pl-s"],[107,118,"pl-c1"],[118,119,"pl-s"],[121,122,"pl-s"],[122,129,"pl-c1"],[129,130,"pl-s"],[132,133,"pl-s"],[133,143,"pl-c1"],[143,144,"pl-s"],[212,214,"pl-s"],[286,288,"pl-s"]],[],[[0,39,"pl-mh"],[4,39,"pl-en"]],[],[[0,3,"pl-s"],[3,8,"pl-en"]],[],[[2,18,"pl-s"],[2,3,"pl-pds"],[17,18,"pl-pds"],[18,19,"pl-k"],[20,21,"pl-c1"]],[[2,18,"pl-s"],[2,3,"pl-pds"],[17,18,"pl-pds"],[18,19,"pl-k"],[20,21,"pl-c1"]],[[2,11,"pl-s"],[2,3,"pl-pds"],[10,11,"pl-pds"],[11,12,"pl-k"],[17,39,"pl-s"],[17,18,"pl-pds"],[38,39,"pl-pds"],[43,75,"pl-c"],[43,45,"pl-c"]],[[2,14,"pl-s"],[2,3,"pl-pds"],[13,14,"pl-pds"],[14,15,"pl-k"],[17,24,"pl-s"],[17,18,"pl-pds"],[23,24,"pl-pds"],[43,76,"pl-c"],[43,45,"pl-c"]],[[2,15,"pl-s"],[2,3,"pl-pds"],[14,15,"pl-pds"],[15,16,"pl-k"],[17,25,"pl-s"],[17,18,"pl-pds"],[24,25,"pl-pds"]],[[2,11,"pl-s"],[2,3,"pl-pds"],[10,11,"pl-pds"],[11,12,"pl-k"],[17,21,"pl-c1"],[43,82,"pl-c"],[43,45,"pl-c"]],[[2,11,"pl-s"],[2,3,"pl-pds"],[10,11,"pl-pds"],[11,12,"pl-k"],[17,22,"pl-s"],[17,18,"pl-pds"],[21,22,"pl-pds"]],[[2,6,"pl-s"],[2,3,"pl-pds"],[5,6,"pl-pds"],[6,7,"pl-k"],[17,24,"pl-s"],[17,18,"pl-pds"],[23,24,"pl-pds"]],[[2,8,"pl-s"],[2,3,"pl-pds"],[7,8,"pl-pds"],[8,9,"pl-k"],[17,26,"pl-s"],[17,18,"pl-pds"],[25,26,"pl-pds"]],[[2,8,"pl-s"],[2,3,"pl-pds"],[7,8,"pl-pds"],[8,9,"pl-k"],[17,23,"pl-s"],[17,18,"pl-pds"],[22,23,"pl-pds"]],[[2,7,"pl-s"],[2,3,"pl-pds"],[6,7,"pl-pds"],[7,8,"pl-k"],[17,21,"pl-c1"]],[[2,10,"pl-s"],[2,3,"pl-pds"],[9,10,"pl-pds"],[10,11,"pl-k"]],[],[[0,3,"pl-s"]],[],[[0,1,"pl-ml"],[8,9,"pl-ml"],[15,16,"pl-ml"],[31,32,"pl-ml"],[38,39,"pl-ml"]],[[0,1,"pl-ml"],[4,5,"pl-ml"],[8,9,"pl-ml"],[12,13,"pl-ml"],[16,17,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,17,"pl-c1"],[17,18,"pl-s"],[19,20,"pl-ml"],[21,22,"pl-s"],[22,25,"pl-c1"],[25,26,"pl-s"],[27,28,"pl-ml"],[38,39,"pl-s"],[39,68,"pl-c1"],[68,69,"pl-s"],[70,71,"pl-ml"],[159,160,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,17,"pl-c1"],[17,18,"pl-s"],[19,20,"pl-ml"],[21,22,"pl-s"],[22,25,"pl-c1"],[25,26,"pl-s"],[27,28,"pl-ml"],[48,49,"pl-s"],[49,78,"pl-c1"],[78,79,"pl-s"],[80,81,"pl-ml"],[90,91,"pl-s"],[91,92,"pl-c1"],[92,93,"pl-s"],[167,168,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,10,"pl-c1"],[10,11,"pl-s"],[12,13,"pl-ml"],[22,23,"pl-ml"],[24,25,"pl-s"],[25,43,"pl-c1"],[43,44,"pl-s"],[45,46,"pl-ml"],[69,71,"pl-s"],[76,78,"pl-s"],[121,122,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,13,"pl-c1"],[13,14,"pl-s"],[15,16,"pl-ml"],[25,26,"pl-ml"],[27,28,"pl-s"],[28,60,"pl-c1"],[60,61,"pl-s"],[62,63,"pl-ml"],[138,139,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,14,"pl-c1"],[14,15,"pl-s"],[16,17,"pl-ml"],[25,26,"pl-ml"],[27,28,"pl-s"],[28,53,"pl-c1"],[53,54,"pl-s"],[62,63,"pl-s"],[63,94,"pl-c1"],[94,95,"pl-s"],[96,97,"pl-ml"],[109,110,"pl-s"],[110,142,"pl-c1"],[142,143,"pl-s"],[145,146,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,10,"pl-c1"],[10,11,"pl-s"],[12,13,"pl-ml"],[21,23,"pl-c1"],[29,30,"pl-ml"],[31,32,"pl-s"],[32,74,"pl-c1"],[74,75,"pl-s"],[80,82,"pl-s"],[85,87,"pl-s"],[98,99,"pl-ml"],[128,130,"pl-s"],[134,136,"pl-s"],[142,143,"pl-s"],[143,185,"pl-c1"],[185,186,"pl-s"],[211,212,"pl-s"],[212,231,"pl-c1"],[231,232,"pl-s"],[245,246,"pl-s"],[246,264,"pl-c1"],[264,265,"pl-s"],[270,271,"pl-s"],[271,281,"pl-c1"],[281,282,"pl-s"],[310,311,"pl-s"],[311,315,"pl-c1"],[315,316,"pl-s"],[380,382,"pl-s"],[387,389,"pl-s"],[390,391,"pl-s"],[391,413,"pl-c1"],[413,414,"pl-s"],[436,437,"pl-s"],[437,447,"pl-c1"],[447,448,"pl-s"],[484,486,"pl-s"],[491,493,"pl-s"],[494,495,"pl-s"],[495,509,"pl-c1"],[509,510,"pl-s"],[512,513,"pl-s"],[513,539,"pl-c1"],[539,540,"pl-s"],[625,626,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,10,"pl-c1"],[10,11,"pl-s"],[12,13,"pl-ml"],[19,20,"pl-ml"],[59,60,"pl-ml"],[61,62,"pl-s"],[62,187,"pl-c1"],[187,188,"pl-s"],[346,347,"pl-s"],[347,363,"pl-c1"],[363,364,"pl-s"],[433,434,"pl-s"],[434,441,"pl-c1"],[441,442,"pl-s"],[447,448,"pl-s"],[448,455,"pl-c1"],[455,456,"pl-s"],[500,502,"pl-s"],[505,507,"pl-s"],[597,598,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,5,"pl-c1"],[5,6,"pl-s"],[7,8,"pl-ml"],[14,15,"pl-ml"],[16,17,"pl-s"],[17,37,"pl-c1"],[37,38,"pl-s"],[46,47,"pl-s"],[47,74,"pl-c1"],[74,75,"pl-s"],[76,77,"pl-ml"],[89,90,"pl-s"],[90,146,"pl-c1"],[146,147,"pl-s"],[149,150,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,7,"pl-c1"],[7,8,"pl-s"],[9,10,"pl-ml"],[16,17,"pl-ml"],[18,19,"pl-s"],[19,41,"pl-c1"],[41,42,"pl-s"],[43,44,"pl-ml"],[45,46,"pl-s"],[46,72,"pl-c1"],[72,73,"pl-s"],[75,76,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,7,"pl-c1"],[7,8,"pl-s"],[9,10,"pl-ml"],[16,17,"pl-ml"],[18,19,"pl-s"],[19,35,"pl-c1"],[35,36,"pl-s"],[39,41,"pl-s"],[53,55,"pl-s"],[56,57,"pl-ml"],[58,59,"pl-s"],[59,78,"pl-c1"],[78,79,"pl-s"],[168,169,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,6,"pl-c1"],[6,7,"pl-s"],[8,9,"pl-ml"],[15,16,"pl-ml"],[17,18,"pl-s"],[18,37,"pl-c1"],[37,38,"pl-s"],[46,47,"pl-s"],[47,83,"pl-c1"],[83,84,"pl-s"],[85,86,"pl-ml"],[87,88,"pl-s"],[88,135,"pl-c1"],[135,136,"pl-s"],[138,139,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,9,"pl-c1"],[9,10,"pl-s"],[11,12,"pl-ml"],[19,20,"pl-ml"],[40,41,"pl-ml"],[234,235,"pl-ml"]],[],[[0,2,"pl-s"],[2,3,"pl-s"],[3,11,"pl-c1"],[11,12,"pl-s"],[30,32,"pl-s"],[182,183,"pl-s"],[183,185,"pl-c1"],[185,186,"pl-s"],[188,189,"pl-s"],[189,193,"pl-c1"],[193,194,"pl-s"],[200,201,"pl-s"],[201,205,"pl-c1"],[205,206,"pl-s"]],[],[[0,23,"pl-mh"],[4,23,"pl-en"]],[],[[36,37,"pl-s"],[37,43,"pl-c1"],[43,44,"pl-s"]],[],[],[],[],[],[[0,46,"pl-mh"],[4,46,"pl-en"]],[],[[21,22,"pl-s"],[22,37,"pl-c1"],[37,38,"pl-s"]],[[21,22,"pl-s"],[22,27,"pl-c1"],[27,28,"pl-s"]],[[0,1,"pl-s"],[1,28,"pl-c1"],[28,29,"pl-s"],[48,49,"pl-s"],[49,56,"pl-c1"],[56,57,"pl-s"]],[[47,48,"pl-s"],[48,64,"pl-c1"],[64,65,"pl-s"]],[],[],[],[[0,1,"pl-v"],[2,4,"pl-s"],[4,5,"pl-s"],[5,10,"pl-c1"],[10,11,"pl-s"],[17,19,"pl-s"]],[[29,30,"pl-s"],[30,39,"pl-c1"],[39,40,"pl-s"]],[[23,24,"pl-s"],[26,27,"pl-s"]],[[2,3,"pl-s"],[3,17,"pl-c1"],[17,18,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[4,5,"pl-s"],[5,8,"pl-c1"],[8,9,"pl-s"],[20,22,"pl-s"],[28,29,"pl-s"],[29,40,"pl-c1"],[40,41,"pl-s"],[56,57,"pl-s"],[57,67,"pl-c1"],[67,68,"pl-s"]],[],[],[[0,1,"pl-v"],[2,4,"pl-s"],[50,52,"pl-s"]],[[26,27,"pl-s"],[27,32,"pl-c1"],[32,33,"pl-s"]],[],[],[[44,45,"pl-s"],[53,54,"pl-s"]],[],[[56,57,"pl-s"],[57,76,"pl-c1"],[76,77,"pl-s"]],[],[],[],[],[],[[7,8,"pl-s"],[8,29,"pl-c1"],[29,30,"pl-s"]],[],[[11,12,"pl-s"],[12,22,"pl-c1"],[22,23,"pl-s"]],[],[],[],[],[],[],[],[[0,1,"pl-s"],[1,37,"pl-c1"],[37,38,"pl-s"]],[],[[36,37,"pl-s"],[37,50,"pl-c1"],[50,51,"pl-s"],[73,74,"pl-s"],[74,75,"pl-c1"],[75,76,"pl-s"]],[[52,53,"pl-s"],[53,63,"pl-c1"],[63,64,"pl-s"],[66,67,"pl-s"],[67,79,"pl-c1"],[79,80,"pl-s"]],[[0,1,"pl-s"],[1,12,"pl-c1"],[12,13,"pl-s"],[15,16,"pl-s"],[16,27,"pl-c1"],[27,28,"pl-s"],[34,35,"pl-s"],[35,49,"pl-c1"],[49,50,"pl-s"]],[],[],[],[],[],[],[],[[0,31,"pl-mh"],[4,31,"pl-en"],[11,12,"pl-s"],[12,30,"pl-c1"],[30,31,"pl-s"]],[],[[18,19,"pl-s"],[19,29,"pl-c1"],[29,30,"pl-s"],[33,34,"pl-s"],[34,46,"pl-c1"],[46,47,"pl-s"],[61,62,"pl-s"],[62,73,"pl-c1"],[73,74,"pl-s"]],[],[[0,3,"pl-s"],[3,8,"pl-en"]],[[2,9,"pl-s"],[2,3,"pl-pds"],[8,9,"pl-pds"],[9,10,"pl-k"],[11,31,"pl-s"],[11,12,"pl-pds"],[30,31,"pl-pds"],[33,39,"pl-s"],[33,34,"pl-pds"],[38,39,"pl-pds"],[39,40,"pl-k"],[41,50,"pl-s"],[41,42,"pl-pds"],[49,50,"pl-pds"],[52,70,"pl-s"],[52,53,"pl-pds"],[69,70,"pl-pds"],[70,71,"pl-k"],[72,79,"pl-s"],[72,73,"pl-pds"],[78,79,"pl-pds"]],[[0,3,"pl-s"]],[],[[0,1,"pl-ml"],[8,9,"pl-ml"],[15,16,"pl-ml"],[24,25,"pl-ml"],[31,32,"pl-ml"]],[[0,1,"pl-ml"],[4,5,"pl-ml"],[8,9,"pl-ml"],[12,13,"pl-ml"],[16,17,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,7,"pl-c1"],[7,8,"pl-s"],[9,10,"pl-ml"],[16,17,"pl-ml"],[26,27,"pl-ml"],[28,29,"pl-s"],[29,36,"pl-c1"],[36,37,"pl-s"],[56,58,"pl-c1"],[59,60,"pl-s"],[60,67,"pl-c1"],[67,68,"pl-s"],[69,71,"pl-c1"],[72,73,"pl-s"],[73,82,"pl-c1"],[82,83,"pl-s"],[85,86,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,19,"pl-c1"],[19,20,"pl-s"],[21,22,"pl-ml"],[30,32,"pl-c1"],[38,39,"pl-ml"],[40,41,"pl-s"],[41,77,"pl-c1"],[77,78,"pl-s"],[79,81,"pl-s"],[85,87,"pl-s"],[88,89,"pl-ml"],[104,105,"pl-s"],[105,116,"pl-c1"],[116,117,"pl-s"],[220,221,"pl-ml"]],[],[[0,26,"pl-mh"],[4,26,"pl-en"],[11,12,"pl-s"],[12,25,"pl-c1"],[25,26,"pl-s"]],[],[[0,3,"pl-s"],[3,8,"pl-en"]],[[2,9,"pl-s"],[2,3,"pl-pds"],[8,9,"pl-pds"],[9,10,"pl-k"],[11,26,"pl-s"],[11,12,"pl-pds"],[25,26,"pl-pds"],[28,36,"pl-s"],[28,29,"pl-pds"],[35,36,"pl-pds"],[36,37,"pl-k"],[38,51,"pl-s"],[38,39,"pl-pds"],[50,51,"pl-pds"]],[[0,3,"pl-s"]],[],[[0,1,"pl-s"],[1,7,"pl-c1"],[7,8,"pl-s"],[12,13,"pl-s"],[13,26,"pl-c1"],[26,27,"pl-s"],[29,30,"pl-s"],[30,59,"pl-c1"],[59,60,"pl-s"],[77,78,"pl-s"],[78,99,"pl-c1"],[99,100,"pl-s"],[102,103,"pl-s"],[103,113,"pl-c1"],[113,114,"pl-s"],[117,118,"pl-s"],[118,161,"pl-c1"],[161,162,"pl-s"]],[],[[0,24,"pl-mh"],[4,24,"pl-en"],[11,12,"pl-s"],[12,23,"pl-c1"],[23,24,"pl-s"]],[],[],[],[[0,3,"pl-s"],[3,8,"pl-en"]],[],[[2,9,"pl-s"],[2,3,"pl-pds"],[8,9,"pl-pds"],[9,10,"pl-k"],[11,24,"pl-s"],[11,12,"pl-pds"],[23,24,"pl-pds"]],[[2,19,"pl-s"],[2,3,"pl-pds"],[18,19,"pl-pds"],[19,20,"pl-k"],[21,29,"pl-s"],[21,22,"pl-pds"],[28,29,"pl-pds"]],[[2,14,"pl-s"],[2,3,"pl-pds"],[13,14,"pl-pds"],[14,15,"pl-k"],[16,23,"pl-s"],[16,17,"pl-pds"],[22,23,"pl-pds"]],[[2,21,"pl-s"],[2,3,"pl-pds"],[20,21,"pl-pds"],[21,22,"pl-k"],[23,33,"pl-s"],[23,24,"pl-pds"],[32,33,"pl-pds"]],[[2,13,"pl-s"],[2,3,"pl-pds"],[12,13,"pl-pds"],[13,14,"pl-k"],[16,26,"pl-s"],[16,17,"pl-pds"],[25,26,"pl-pds"],[28,36,"pl-s"],[28,29,"pl-pds"],[35,36,"pl-pds"]],[[2,12,"pl-s"],[2,3,"pl-pds"],[11,12,"pl-pds"],[12,13,"pl-k"],[16,23,"pl-s"],[16,17,"pl-pds"],[22,23,"pl-pds"],[23,24,"pl-k"],[25,27,"pl-c1"],[29,41,"pl-s"],[29,30,"pl-pds"],[40,41,"pl-pds"],[41,42,"pl-k"],[43,45,"pl-c1"],[47,63,"pl-s"],[47,48,"pl-pds"],[62,63,"pl-pds"],[63,64,"pl-k"],[65,66,"pl-c1"],[68,82,"pl-s"],[68,69,"pl-pds"],[81,82,"pl-pds"],[82,83,"pl-k"],[84,85,"pl-c1"]],[[16,32,"pl-s"],[16,17,"pl-pds"],[31,32,"pl-pds"],[32,33,"pl-k"],[34,35,"pl-c1"],[37,59,"pl-s"],[37,38,"pl-pds"],[58,59,"pl-pds"],[59,60,"pl-k"],[61,62,"pl-c1"],[64,79,"pl-s"],[64,65,"pl-pds"],[78,79,"pl-pds"],[79,80,"pl-k"],[81,82,"pl-c1"]],[[16,38,"pl-s"],[16,17,"pl-pds"],[37,38,"pl-pds"],[38,39,"pl-k"],[40,41,"pl-c1"],[43,66,"pl-s"],[43,44,"pl-pds"],[65,66,"pl-pds"],[66,67,"pl-k"],[68,69,"pl-c1"]],[[16,38,"pl-s"],[16,17,"pl-pds"],[37,38,"pl-pds"],[38,39,"pl-k"],[40,41,"pl-c1"]],[[2,10,"pl-s"],[2,3,"pl-pds"],[9,10,"pl-pds"],[10,11,"pl-k"],[16,39,"pl-s"],[16,17,"pl-pds"],[38,39,"pl-pds"],[39,40,"pl-k"],[41,42,"pl-c1"],[44,63,"pl-s"],[44,45,"pl-pds"],[62,63,"pl-pds"],[63,64,"pl-k"],[65,66,"pl-c1"],[68,87,"pl-s"],[68,69,"pl-pds"],[86,87,"pl-pds"],[87,88,"pl-k"],[89,90,"pl-c1"]],[[16,39,"pl-s"],[16,17,"pl-pds"],[38,39,"pl-pds"],[39,40,"pl-k"],[41,42,"pl-c1"],[44,58,"pl-s"],[44,45,"pl-pds"],[57,58,"pl-pds"],[58,59,"pl-k"],[60,61,"pl-c1"],[63,78,"pl-s"],[63,64,"pl-pds"],[77,78,"pl-pds"],[78,79,"pl-k"],[80,81,"pl-c1"]],[[2,13,"pl-s"],[2,3,"pl-pds"],[12,13,"pl-pds"],[13,14,"pl-k"],[17,24,"pl-s"],[17,18,"pl-pds"],[23,24,"pl-pds"],[24,25,"pl-k"],[26,27,"pl-c1"],[29,36,"pl-s"],[29,30,"pl-pds"],[35,36,"pl-pds"],[36,37,"pl-k"],[38,39,"pl-c1"],[41,50,"pl-s"],[41,42,"pl-pds"],[49,50,"pl-pds"],[50,51,"pl-k"],[52,53,"pl-c1"],[55,65,"pl-s"],[55,56,"pl-pds"],[64,65,"pl-pds"],[65,66,"pl-k"],[67,68,"pl-c1"]],[],[[0,3,"pl-s"]],[],[[0,2,"pl-s"],[2,3,"pl-s"],[3,11,"pl-c1"],[11,12,"pl-s"],[17,18,"pl-s"],[18,24,"pl-c1"],[24,25,"pl-s"],[30,31,"pl-s"],[31,51,"pl-c1"],[51,52,"pl-s"],[70,71,"pl-s"],[71,74,"pl-c1"],[74,75,"pl-s"],[93,95,"pl-s"],[212,213,"pl-s"],[213,242,"pl-c1"],[242,243,"pl-s"]],[],[[0,2,"pl-s"],[2,3,"pl-s"],[3,18,"pl-c1"],[18,19,"pl-s"],[19,21,"pl-s"],[24,25,"pl-s"],[25,31,"pl-c1"],[31,32,"pl-s"],[44,45,"pl-s"],[45,67,"pl-c1"],[67,68,"pl-s"],[70,71,"pl-s"],[71,101,"pl-c1"],[101,102,"pl-s"],[125,126,"pl-s"],[126,131,"pl-c1"],[131,132,"pl-s"],[134,135,"pl-s"],[135,141,"pl-c1"],[141,142,"pl-s"],[145,146,"pl-s"],[146,152,"pl-c1"],[152,153,"pl-s"],[155,156,"pl-s"],[156,168,"pl-c1"],[168,169,"pl-s"],[172,173,"pl-s"],[173,180,"pl-c1"],[180,181,"pl-s"],[183,184,"pl-s"],[184,198,"pl-c1"],[198,199,"pl-s"],[202,203,"pl-s"],[203,209,"pl-c1"],[209,210,"pl-s"],[212,213,"pl-s"],[213,221,"pl-c1"],[221,222,"pl-s"]],[],[[0,2,"pl-s"],[2,3,"pl-s"],[3,13,"pl-c1"],[13,14,"pl-s"],[14,16,"pl-s"],[19,20,"pl-s"],[20,50,"pl-c1"],[50,51,"pl-s"],[53,55,"pl-s"],[80,81,"pl-s"],[81,89,"pl-c1"],[89,90,"pl-s"],[116,118,"pl-s"],[119,120,"pl-s"],[120,150,"pl-c1"],[150,151,"pl-s"],[170,171,"pl-s"],[171,225,"pl-c1"],[225,226,"pl-s"],[266,267,"pl-s"],[267,292,"pl-c1"],[292,293,"pl-s"],[423,424,"pl-s"],[424,450,"pl-c1"],[450,451,"pl-s"],[474,475,"pl-s"],[475,483,"pl-c1"],[483,484,"pl-s"],[493,494,"pl-s"],[494,512,"pl-c1"],[512,513,"pl-s"],[542,543,"pl-s"],[543,577,"pl-c1"],[577,578,"pl-s"],[580,581,"pl-s"],[581,638,"pl-c1"],[638,639,"pl-s"],[643,644,"pl-s"],[644,649,"pl-c1"],[649,650,"pl-s"],[665,667,"pl-s"],[670,672,"pl-s"],[677,678,"pl-s"],[678,700,"pl-c1"],[700,701,"pl-s"],[703,704,"pl-s"],[704,731,"pl-c1"],[731,732,"pl-s"],[749,750,"pl-s"],[750,757,"pl-c1"],[757,758,"pl-s"]],[],[[0,2,"pl-s"],[2,3,"pl-s"],[3,20,"pl-c1"],[20,21,"pl-s"],[21,23,"pl-s"],[31,32,"pl-s"],[32,59,"pl-c1"],[59,60,"pl-s"],[74,75,"pl-s"],[75,88,"pl-c1"],[88,89,"pl-s"],[157,158,"pl-s"],[158,199,"pl-c1"],[199,200,"pl-s"],[215,216,"pl-s"],[216,222,"pl-c1"],[222,223,"pl-s"],[225,226,"pl-s"],[226,234,"pl-c1"],[234,235,"pl-s"],[237,238,"pl-s"],[238,247,"pl-c1"],[247,248,"pl-s"],[250,251,"pl-s"],[251,259,"pl-c1"],[259,260,"pl-s"]],[],[],[],[[0,2,"pl-s"],[2,3,"pl-s"],[3,11,"pl-c1"],[11,12,"pl-s"],[12,14,"pl-s"],[61,63,"pl-s"],[72,74,"pl-s"]],[],[[0,1,"pl-ml"],[8,9,"pl-ml"],[24,25,"pl-ml"]],[[0,1,"pl-ml"],[4,5,"pl-ml"],[8,9,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,8,"pl-c1"],[8,9,"pl-s"],[10,11,"pl-ml"],[12,13,"pl-s"],[13,27,"pl-c1"],[27,28,"pl-s"],[32,33,"pl-s"],[33,68,"pl-c1"],[68,69,"pl-s"],[99,100,"pl-s"],[100,130,"pl-c1"],[130,131,"pl-s"],[180,181,"pl-s"],[181,253,"pl-c1"],[253,254,"pl-s"],[256,257,"pl-s"],[257,296,"pl-c1"],[296,297,"pl-s"],[431,432,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,13,"pl-c1"],[13,14,"pl-s"],[15,16,"pl-ml"],[17,18,"pl-s"],[18,40,"pl-c1"],[40,41,"pl-s"],[45,46,"pl-s"],[46,90,"pl-c1"],[90,91,"pl-s"],[139,140,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,17,"pl-c1"],[17,18,"pl-s"],[19,20,"pl-ml"],[21,22,"pl-s"],[22,55,"pl-c1"],[55,56,"pl-s"],[60,61,"pl-s"],[61,92,"pl-c1"],[92,93,"pl-s"],[119,120,"pl-s"],[120,130,"pl-c1"],[130,131,"pl-s"],[136,137,"pl-s"],[137,154,"pl-c1"],[154,155,"pl-s"],[223,224,"pl-s"],[224,233,"pl-c1"],[233,234,"pl-s"],[236,237,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,15,"pl-c1"],[15,16,"pl-s"],[17,18,"pl-ml"],[29,30,"pl-s"],[30,51,"pl-c1"],[51,52,"pl-s"],[54,55,"pl-s"],[55,91,"pl-c1"],[91,92,"pl-s"],[105,106,"pl-s"],[106,127,"pl-c1"],[127,128,"pl-s"],[140,141,"pl-s"],[141,159,"pl-c1"],[159,160,"pl-s"],[173,174,"pl-s"],[174,189,"pl-c1"],[189,190,"pl-s"],[208,209,"pl-s"],[209,213,"pl-c1"],[213,214,"pl-s"],[218,219,"pl-s"],[219,245,"pl-c1"],[245,246,"pl-s"],[268,269,"pl-s"],[281,282,"pl-s"],[341,342,"pl-s"],[342,381,"pl-c1"],[381,382,"pl-s"],[404,405,"pl-s"],[405,432,"pl-c1"],[432,433,"pl-s"],[508,509,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,17,"pl-c1"],[17,18,"pl-s"],[19,20,"pl-ml"],[21,22,"pl-s"],[22,61,"pl-c1"],[61,62,"pl-s"],[66,67,"pl-s"],[67,97,"pl-c1"],[97,98,"pl-s"],[99,100,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,23,"pl-c1"],[23,24,"pl-s"],[25,26,"pl-ml"],[59,60,"pl-s"],[60,70,"pl-c1"],[70,71,"pl-s"],[84,85,"pl-s"],[85,105,"pl-c1"],[105,106,"pl-s"],[108,109,"pl-s"],[109,130,"pl-c1"],[130,131,"pl-s"],[140,141,"pl-s"],[141,145,"pl-c1"],[145,146,"pl-s"],[148,149,"pl-s"],[149,163,"pl-c1"],[163,164,"pl-s"],[169,170,"pl-s"],[170,175,"pl-c1"],[175,176,"pl-s"],[237,238,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,16,"pl-c1"],[16,17,"pl-s"],[18,19,"pl-ml"],[20,21,"pl-s"],[21,49,"pl-c1"],[49,50,"pl-s"],[75,76,"pl-s"],[76,113,"pl-c1"],[113,114,"pl-s"],[137,138,"pl-s"],[138,160,"pl-c1"],[160,161,"pl-s"],[174,175,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,23,"pl-c1"],[23,24,"pl-s"],[25,26,"pl-ml"],[31,32,"pl-s"],[32,55,"pl-c1"],[55,56,"pl-s"],[64,65,"pl-s"],[65,79,"pl-c1"],[79,80,"pl-s"],[82,83,"pl-s"],[83,118,"pl-c1"],[118,119,"pl-s"],[145,146,"pl-s"],[146,175,"pl-c1"],[175,176,"pl-s"],[178,179,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,24,"pl-c1"],[24,25,"pl-s"],[26,27,"pl-ml"],[28,29,"pl-s"],[29,63,"pl-c1"],[63,64,"pl-s"],[68,69,"pl-s"],[69,98,"pl-c1"],[98,99,"pl-s"],[119,120,"pl-s"],[120,132,"pl-c1"],[132,133,"pl-s"],[135,136,"pl-s"],[136,144,"pl-c1"],[144,145,"pl-s"],[170,171,"pl-s"],[171,181,"pl-c1"],[181,182,"pl-s"],[227,228,"pl-s"],[228,274,"pl-c1"],[274,275,"pl-s"],[277,278,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,23,"pl-c1"],[23,24,"pl-s"],[25,26,"pl-ml"],[51,52,"pl-s"],[52,66,"pl-c1"],[66,67,"pl-s"],[69,70,"pl-s"],[70,105,"pl-c1"],[105,106,"pl-s"],[112,113,"pl-s"],[113,139,"pl-c1"],[139,140,"pl-s"],[144,145,"pl-s"],[145,175,"pl-c1"],[175,176,"pl-s"],[177,178,"pl-ml"]],[],[[0,2,"pl-s"],[2,3,"pl-s"],[3,9,"pl-c1"],[9,10,"pl-s"],[10,12,"pl-s"],[50,52,"pl-s"],[72,74,"pl-s"],[82,83,"pl-s"],[83,98,"pl-c1"],[98,99,"pl-s"]],[],[[0,1,"pl-ml"],[8,9,"pl-ml"],[24,25,"pl-ml"]],[[0,1,"pl-ml"],[4,5,"pl-ml"],[8,9,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,24,"pl-c1"],[24,25,"pl-s"],[26,27,"pl-ml"],[44,45,"pl-s"],[45,64,"pl-c1"],[64,65,"pl-s"],[67,68,"pl-s"],[68,112,"pl-c1"],[112,113,"pl-s"],[117,118,"pl-s"],[118,135,"pl-c1"],[135,136,"pl-s"],[138,139,"pl-s"],[139,178,"pl-c1"],[178,179,"pl-s"],[202,203,"pl-s"],[203,221,"pl-c1"],[221,222,"pl-s"],[241,242,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,20,"pl-c1"],[20,21,"pl-s"],[22,23,"pl-ml"],[24,25,"pl-s"],[25,51,"pl-c1"],[51,52,"pl-s"],[66,67,"pl-s"],[67,100,"pl-c1"],[100,101,"pl-s"],[106,107,"pl-s"],[107,111,"pl-c1"],[111,112,"pl-s"],[113,115,"pl-s"],[121,123,"pl-s"],[128,129,"pl-s"],[129,134,"pl-c1"],[134,135,"pl-s"],[216,217,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,20,"pl-c1"],[20,21,"pl-s"],[22,23,"pl-ml"],[24,25,"pl-s"],[25,51,"pl-c1"],[51,52,"pl-s"],[74,75,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,24,"pl-c1"],[24,25,"pl-s"],[26,27,"pl-ml"],[32,33,"pl-s"],[33,50,"pl-c1"],[50,51,"pl-s"],[82,83,"pl-s"],[83,135,"pl-c1"],[135,136,"pl-s"],[137,138,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,15,"pl-c1"],[15,16,"pl-s"],[17,18,"pl-ml"],[23,24,"pl-s"],[24,31,"pl-c1"],[31,32,"pl-s"],[49,50,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,16,"pl-c1"],[16,17,"pl-s"],[18,19,"pl-ml"],[20,21,"pl-s"],[21,51,"pl-c1"],[51,52,"pl-s"],[55,56,"pl-s"],[56,68,"pl-c1"],[68,69,"pl-s"],[76,77,"pl-s"],[77,106,"pl-c1"],[106,107,"pl-s"],[108,109,"pl-ml"]],[],[[36,37,"pl-s"],[37,58,"pl-c1"],[58,59,"pl-s"],[62,63,"pl-s"],[63,70,"pl-c1"],[70,71,"pl-s"],[72,73,"pl-s"],[75,76,"pl-s"],[95,96,"pl-s"],[96,122,"pl-c1"],[122,123,"pl-s"],[126,127,"pl-s"],[127,139,"pl-c1"],[139,140,"pl-s"],[143,144,"pl-s"],[144,151,"pl-c1"],[151,152,"pl-s"],[153,154,"pl-s"],[156,157,"pl-s"],[203,204,"pl-s"],[204,225,"pl-c1"],[225,226,"pl-s"],[229,230,"pl-s"],[230,237,"pl-c1"],[237,238,"pl-s"],[287,288,"pl-s"],[288,296,"pl-c1"],[296,297,"pl-s"],[351,352,"pl-s"],[352,388,"pl-c1"],[388,389,"pl-s"]],[],[[0,2,"pl-s"],[2,3,"pl-s"],[3,12,"pl-c1"],[12,13,"pl-s"],[13,15,"pl-s"],[76,77,"pl-s"],[77,82,"pl-c1"],[82,83,"pl-s"],[85,86,"pl-s"],[86,91,"pl-c1"],[91,92,"pl-s"],[94,95,"pl-s"],[95,102,"pl-c1"],[102,103,"pl-s"],[105,106,"pl-s"],[106,114,"pl-c1"],[114,115,"pl-s"],[129,130,"pl-s"],[130,147,"pl-c1"],[147,148,"pl-s"],[161,162,"pl-s"],[162,167,"pl-c1"],[167,168,"pl-s"],[177,178,"pl-s"],[178,192,"pl-c1"],[192,193,"pl-s"]],[],[[0,18,"pl-mh"],[4,18,"pl-en"],[11,12,"pl-s"],[12,17,"pl-c1"],[17,18,"pl-s"]],[],[[9,11,"pl-s"],[24,26,"pl-s"],[56,57,"pl-s"],[57,68,"pl-c1"],[68,69,"pl-s"]],[],[[0,3,"pl-s"],[3,8,"pl-en"]],[[2,9,"pl-s"],[2,3,"pl-pds"],[8,9,"pl-pds"],[9,10,"pl-k"],[11,18,"pl-s"],[11,12,"pl-pds"],[17,18,"pl-pds"],[20,26,"pl-s"],[20,21,"pl-pds"],[25,26,"pl-pds"],[26,27,"pl-k"],[28,58,"pl-s"],[28,29,"pl-pds"],[57,58,"pl-pds"]],[[0,3,"pl-s"]],[],[[0,1,"pl-s"],[1,5,"pl-c1"],[5,6,"pl-s"],[18,19,"pl-s"],[19,40,"pl-c1"],[40,41,"pl-s"],[43,44,"pl-s"],[44,75,"pl-c1"],[75,76,"pl-s"],[81,82,"pl-s"],[82,100,"pl-c1"],[100,101,"pl-s"],[103,104,"pl-s"],[104,131,"pl-c1"],[131,132,"pl-s"],[135,137,"pl-s"],[171,173,"pl-s"],[196,197,"pl-s"],[197,203,"pl-c1"],[203,204,"pl-s"],[217,218,"pl-s"],[218,225,"pl-c1"],[225,226,"pl-s"],[255,256,"pl-s"],[256,263,"pl-c1"],[263,264,"pl-s"],[277,278,"pl-s"],[278,315,"pl-c1"],[315,316,"pl-s"],[320,321,"pl-s"],[321,328,"pl-c1"],[328,329,"pl-s"],[343,344,"pl-s"],[344,363,"pl-c1"],[363,364,"pl-s"],[382,383,"pl-s"],[383,401,"pl-c1"],[401,402,"pl-s"],[404,405,"pl-s"],[405,421,"pl-c1"],[421,422,"pl-s"],[433,434,"pl-s"],[434,437,"pl-c1"],[437,438,"pl-s"],[439,440,"pl-s"],[440,445,"pl-c1"],[445,446,"pl-s"],[447,448,"pl-s"],[448,461,"pl-c1"],[461,462,"pl-s"],[512,513,"pl-s"],[513,572,"pl-c1"],[572,573,"pl-s"],[580,582,"pl-s"],[606,608,"pl-s"]],[],[[0,2,"pl-s"],[34,36,"pl-s"],[49,50,"pl-s"],[50,81,"pl-c1"],[81,82,"pl-s"],[90,91,"pl-s"],[91,94,"pl-c1"],[94,95,"pl-s"]],[],[[0,26,"pl-mh"],[4,26,"pl-en"],[11,12,"pl-s"],[12,25,"pl-c1"],[25,26,"pl-s"]],[],[],[[0,1,"pl-s"],[1,4,"pl-c1"],[4,5,"pl-s"]],[],[],[],[[0,3,"pl-s"],[3,8,"pl-en"]],[],[[2,9,"pl-s"],[2,3,"pl-pds"],[8,9,"pl-pds"],[9,10,"pl-k"],[11,26,"pl-s"],[11,12,"pl-pds"],[25,26,"pl-pds"]],[[2,12,"pl-s"],[2,3,"pl-pds"],[11,12,"pl-pds"],[12,13,"pl-k"]],[[4,15,"pl-s"],[4,5,"pl-pds"],[14,15,"pl-pds"],[15,16,"pl-k"],[17,18,"pl-c1"]],[[4,15,"pl-s"],[4,5,"pl-pds"],[14,15,"pl-pds"],[15,16,"pl-k"],[17,18,"pl-c1"]],[[4,18,"pl-s"],[4,5,"pl-pds"],[17,18,"pl-pds"],[18,19,"pl-k"],[20,21,"pl-c1"]],[[4,14,"pl-s"],[4,5,"pl-pds"],[13,14,"pl-pds"],[14,15,"pl-k"],[16,17,"pl-c1"]],[[4,12,"pl-s"],[4,5,"pl-pds"],[11,12,"pl-pds"],[12,13,"pl-k"],[14,15,"pl-c1"]],[[4,11,"pl-s"],[4,5,"pl-pds"],[10,11,"pl-pds"],[11,12,"pl-k"],[13,14,"pl-c1"]],[[4,20,"pl-s"],[4,5,"pl-pds"],[19,20,"pl-pds"],[20,21,"pl-k"],[22,23,"pl-c1"]],[[4,20,"pl-s"],[4,5,"pl-pds"],[19,20,"pl-pds"],[20,21,"pl-k"],[22,23,"pl-c1"]],[[4,17,"pl-s"],[4,5,"pl-pds"],[16,17,"pl-pds"],[17,18,"pl-k"],[19,20,"pl-c1"]],[[4,19,"pl-s"],[4,5,"pl-pds"],[18,19,"pl-pds"],[19,20,"pl-k"],[21,22,"pl-c1"]],[[4,19,"pl-s"],[4,5,"pl-pds"],[18,19,"pl-pds"],[19,20,"pl-k"],[21,22,"pl-c1"]],[[4,25,"pl-s"],[4,5,"pl-pds"],[24,25,"pl-pds"],[25,26,"pl-k"],[27,28,"pl-c1"]],[[4,17,"pl-s"],[4,5,"pl-pds"],[16,17,"pl-pds"],[17,18,"pl-k"],[19,20,"pl-c1"]],[],[],[[0,3,"pl-s"]],[],[[0,1,"pl-s"],[1,10,"pl-c1"],[10,11,"pl-s"],[35,36,"pl-s"],[36,45,"pl-c1"],[45,46,"pl-s"],[69,70,"pl-s"],[70,82,"pl-c1"],[82,83,"pl-s"]],[[4,5,"pl-s"],[5,13,"pl-c1"],[13,14,"pl-s"],[43,44,"pl-s"],[44,50,"pl-c1"],[50,51,"pl-s"],[56,57,"pl-s"],[57,62,"pl-c1"],[62,63,"pl-s"]],[[40,41,"pl-s"],[41,55,"pl-c1"],[55,56,"pl-s"],[58,59,"pl-s"],[59,73,"pl-c1"],[73,74,"pl-s"]],[[0,1,"pl-s"],[1,12,"pl-c1"],[12,13,"pl-s"],[19,20,"pl-s"],[20,33,"pl-c1"],[33,34,"pl-s"]],[[0,1,"pl-s"],[1,14,"pl-c1"],[14,15,"pl-s"],[17,18,"pl-s"],[18,37,"pl-c1"],[37,38,"pl-s"],[44,45,"pl-s"],[45,56,"pl-c1"],[56,57,"pl-s"]],[],[],[],[],[[0,31,"pl-mh"],[4,31,"pl-en"],[11,12,"pl-s"],[12,30,"pl-c1"],[30,31,"pl-s"]],[],[],[[29,30,"pl-s"],[30,33,"pl-c1"],[33,34,"pl-s"],[64,65,"pl-s"],[65,78,"pl-c1"],[78,79,"pl-s"]],[],[[68,69,"pl-s"],[69,79,"pl-c1"],[79,80,"pl-s"]],[],[[66,67,"pl-s"],[67,75,"pl-c1"],[75,76,"pl-s"]],[[0,1,"pl-s"],[1,7,"pl-c1"],[7,8,"pl-s"],[38,39,"pl-s"],[39,56,"pl-c1"],[56,57,"pl-s"],[62,63,"pl-s"],[63,78,"pl-c1"],[78,79,"pl-s"]],[[30,31,"pl-s"],[31,37,"pl-c1"],[37,38,"pl-s"],[43,44,"pl-s"],[44,57,"pl-c1"],[57,58,"pl-s"]],[],[[0,3,"pl-s"],[3,8,"pl-en"]],[],[[2,9,"pl-s"],[2,3,"pl-pds"],[8,9,"pl-pds"],[9,10,"pl-k"],[11,31,"pl-s"],[11,12,"pl-pds"],[30,31,"pl-pds"]],[[2,12,"pl-s"],[2,3,"pl-pds"],[11,12,"pl-pds"],[12,13,"pl-k"],[14,16,"pl-c1"]],[[2,10,"pl-s"],[2,3,"pl-pds"],[9,10,"pl-pds"],[10,11,"pl-k"],[12,13,"pl-c1"]],[[2,21,"pl-s"],[2,3,"pl-pds"],[20,21,"pl-pds"],[21,22,"pl-k"],[23,27,"pl-c1"]],[[2,19,"pl-s"],[2,3,"pl-pds"],[18,19,"pl-pds"],[19,20,"pl-k"],[21,24,"pl-c1"]],[[2,10,"pl-s"],[2,3,"pl-pds"],[9,10,"pl-pds"],[10,11,"pl-k"],[12,13,"pl-c1"]],[[2,17,"pl-s"],[2,3,"pl-pds"],[16,17,"pl-pds"],[17,18,"pl-k"],[19,20,"pl-c1"]],[],[[0,3,"pl-s"]],[],[[0,60,"pl-mh"],[4,60,"pl-en"]],[],[],[],[[0,2,"pl-s"],[13,15,"pl-s"],[16,17,"pl-s"],[17,61,"pl-c1"],[61,62,"pl-s"],[91,92,"pl-s"],[92,118,"pl-c1"],[118,119,"pl-s"],[168,169,"pl-s"],[169,170,"pl-s"],[170,187,"pl-c1"],[187,188,"pl-s"],[188,189,"pl-s"],[189,190,"pl-s"],[190,210,"pl-corl"],[210,211,"pl-s"]],[],[[0,2,"pl-s"],[17,19,"pl-s"],[132,133,"pl-s"],[133,163,"pl-c1"],[163,164,"pl-s"],[170,172,"pl-s"],[178,180,"pl-s"],[256,257,"pl-s"],[257,260,"pl-c1"],[260,261,"pl-s"],[403,404,"pl-s"],[404,444,"pl-c1"],[444,445,"pl-s"],[500,501,"pl-s"],[510,511,"pl-s"],[564,565,"pl-s"],[565,601,"pl-c1"],[601,602,"pl-s"]],[],[[12,14,"pl-s"],[35,37,"pl-s"],[77,78,"pl-s"],[78,88,"pl-c1"],[88,89,"pl-s"],[191,192,"pl-s"],[192,208,"pl-c1"],[208,209,"pl-s"],[211,212,"pl-s"],[212,217,"pl-c1"],[217,218,"pl-s"],[219,220,"pl-s"],[220,226,"pl-c1"],[226,227,"pl-s"],[229,230,"pl-s"],[230,237,"pl-c1"],[237,238,"pl-s"],[240,241,"pl-s"],[241,248,"pl-c1"],[248,249,"pl-s"],[250,251,"pl-s"],[251,259,"pl-c1"],[259,260,"pl-s"],[262,263,"pl-s"],[263,269,"pl-c1"],[269,270,"pl-s"],[276,277,"pl-s"],[277,286,"pl-c1"],[286,287,"pl-s"],[347,348,"pl-s"],[348,362,"pl-c1"],[362,363,"pl-s"],[402,404,"pl-s"],[442,444,"pl-s"]],[],[[0,1,"pl-v"],[28,30,"pl-s"],[33,35,"pl-s"],[54,55,"pl-s"],[55,67,"pl-c1"],[67,68,"pl-s"],[73,74,"pl-s"],[74,88,"pl-c1"],[88,89,"pl-s"]],[[0,1,"pl-v"],[33,34,"pl-s"],[34,36,"pl-c1"],[36,37,"pl-s"]],[[0,1,"pl-v"]],[[0,1,"pl-v"],[16,17,"pl-s"],[17,32,"pl-c1"],[32,33,"pl-s"],[44,45,"pl-s"],[45,59,"pl-c1"],[59,60,"pl-s"],[283,284,"pl-s"],[284,293,"pl-c1"],[293,294,"pl-s"]],[[0,1,"pl-v"],[28,29,"pl-s"],[29,39,"pl-c1"],[39,40,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,38,"pl-c1"],[38,39,"pl-s"],[177,178,"pl-s"],[178,187,"pl-c1"],[187,188,"pl-s"],[212,213,"pl-s"],[213,221,"pl-c1"],[221,222,"pl-s"]],[],[[0,2,"pl-s"],[26,28,"pl-s"]],[],[[0,2,"pl-s"],[29,31,"pl-s"]],[],[],[[10,11,"pl-s"],[28,29,"pl-s"],[29,30,"pl-s"],[30,66,"pl-corl"],[66,67,"pl-s"]],[[22,23,"pl-s"],[23,47,"pl-c1"],[47,48,"pl-s"],[53,54,"pl-s"],[54,78,"pl-c1"],[78,79,"pl-s"]],[],[],[[0,1,"pl-s"],[1,23,"pl-c1"],[23,24,"pl-s"],[42,43,"pl-s"],[43,54,"pl-c1"],[54,55,"pl-s"]],[[0,1,"pl-s"],[1,29,"pl-c1"],[29,30,"pl-s"],[32,33,"pl-s"],[33,56,"pl-c1"],[56,57,"pl-s"]],[[0,1,"pl-s"],[1,22,"pl-c1"],[22,23,"pl-s"],[25,26,"pl-s"],[26,41,"pl-c1"],[41,42,"pl-s"],[44,45,"pl-s"],[45,68,"pl-c1"],[68,69,"pl-s"]],[[0,1,"pl-s"],[1,29,"pl-c1"],[29,30,"pl-s"]],[[0,1,"pl-s"],[1,32,"pl-c1"],[32,33,"pl-s"],[35,36,"pl-s"],[36,57,"pl-c1"],[57,58,"pl-s"],[64,65,"pl-s"],[65,75,"pl-c1"],[75,76,"pl-s"]],[],[],[],[],[],[],[],[],[],[],[[0,2,"pl-s"],[51,53,"pl-s"],[54,55,"pl-s"],[75,76,"pl-s"],[76,77,"pl-s"],[77,186,"pl-corl"],[186,187,"pl-s"]],[],[],[[27,28,"pl-s"],[28,66,"pl-c1"],[66,67,"pl-s"]],[],[],[[56,57,"pl-s"],[57,73,"pl-c1"],[73,74,"pl-s"]],[[0,1,"pl-s"],[1,16,"pl-c1"],[16,17,"pl-s"],[23,24,"pl-s"],[24,33,"pl-c1"],[33,34,"pl-s"]],[],[],[],[],[[0,2,"pl-s"],[52,54,"pl-s"],[57,58,"pl-s"],[58,61,"pl-c1"],[61,62,"pl-s"],[73,74,"pl-s"],[74,77,"pl-c1"],[77,78,"pl-s"],[97,98,"pl-s"],[98,101,"pl-c1"],[101,102,"pl-s"],[103,104,"pl-s"],[104,107,"pl-c1"],[107,108,"pl-s"],[131,132,"pl-s"],[132,135,"pl-c1"],[135,136,"pl-s"],[148,149,"pl-s"],[149,152,"pl-c1"],[152,153,"pl-s"],[174,175,"pl-s"],[175,178,"pl-c1"],[178,179,"pl-s"],[194,195,"pl-s"],[195,198,"pl-c1"],[198,199,"pl-s"]],[],[[0,1,"pl-s"],[1,11,"pl-c1"],[11,12,"pl-s"],[48,49,"pl-s"],[49,59,"pl-c1"],[59,60,"pl-s"],[64,65,"pl-s"],[65,80,"pl-c1"],[80,81,"pl-s"],[184,186,"pl-s"],[208,209,"pl-s"],[209,219,"pl-c1"],[219,220,"pl-s"],[237,239,"pl-s"]],[],[[0,2,"pl-s"],[74,76,"pl-s"],[77,78,"pl-s"],[78,114,"pl-c1"],[114,115,"pl-s"]],[],[[0,56,"pl-mh"],[4,56,"pl-en"]],[],[[49,51,"pl-s"],[75,77,"pl-s"],[149,150,"pl-s"],[150,163,"pl-c1"],[163,164,"pl-s"]],[],[],[],[[0,3,"pl-s"],[3,5,"pl-en"]],[[0,2,"pl-c1"]],[],[[0,3,"pl-s"]],[],[[151,152,"pl-s"],[152,158,"pl-c1"],[158,159,"pl-s"],[662,663,"pl-s"],[663,681,"pl-c1"],[681,682,"pl-s"]],[],[[0,54,"pl-mh"],[4,54,"pl-en"]],[],[[230,231,"pl-s"],[231,244,"pl-c1"],[244,245,"pl-s"]],[],[[37,38,"pl-s"],[38,61,"pl-c1"],[61,62,"pl-s"],[72,73,"pl-s"],[73,80,"pl-c1"],[80,81,"pl-s"],[83,84,"pl-s"],[84,94,"pl-c1"],[94,95,"pl-s"],[97,98,"pl-s"],[98,112,"pl-c1"],[112,113,"pl-s"],[115,116,"pl-s"],[116,119,"pl-c1"],[119,120,"pl-s"],[126,127,"pl-s"],[127,131,"pl-c1"],[131,132,"pl-s"],[155,156,"pl-s"],[156,171,"pl-c1"],[171,172,"pl-s"],[208,209,"pl-s"],[209,215,"pl-c1"],[215,216,"pl-s"],[220,221,"pl-s"],[221,231,"pl-c1"],[231,232,"pl-s"],[245,246,"pl-s"],[246,255,"pl-c1"],[255,256,"pl-s"],[292,294,"pl-s"],[307,308,"pl-s"],[308,317,"pl-c1"],[317,318,"pl-s"],[346,348,"pl-s"],[419,420,"pl-s"],[420,452,"pl-c1"],[452,453,"pl-s"],[498,499,"pl-s"],[499,508,"pl-c1"],[508,509,"pl-s"],[544,545,"pl-s"],[545,551,"pl-c1"],[551,552,"pl-s"],[554,555,"pl-s"],[555,563,"pl-c1"],[563,564,"pl-s"],[570,571,"pl-s"],[571,582,"pl-c1"],[582,583,"pl-s"]],[],[[0,3,"pl-ms"]]],"colorizedLines":null}},"title":"Codewhale/docs/TELEMETRY.md at main · codewhale-hq/Codewhale","appPayload":{},"meta":{"title":"Codewhale/docs/TELEMETRY.md at main · codewhale-hq/Codewhale"}}</script>
  <div data-target="react-app.reactRoot"><meta name="github-code-view-meta-stats" id="github-code-view-meta-stats" data-hydrostats="publish"/> <!-- --> <a hidden="" id="code-view-repo-link" href="/codewhale-hq/Codewhale" data-discover="true"></a> <div class="d-none"></div><div><div style="--spacing:var(--spacing-none)" class="prc-PageLayout-PageLayoutRoot--KH-d" data-component="SplitPageLayout" data-has-sidebar="true"><div class="prc-PageLayout-SidebarWrapper-kLG4B CopilotSidePanelSidebar-module__SidePanel__L3O0C CopilotSidePanelSidebar-module__HiddenSidePanel__TBRGn" style="--spacing-column:var(--spacing-none)" data-is-hidden="false" data-position="end" data-sticky="true" data-responsive-variant="fullscreen"><div class="prc-PageLayout-VerticalDivider-9QRmK prc-PageLayout-SidebarVerticalDivider-0Rl0V" data-component="PageLayout.VerticalDivider" data-variant="line" data-position="end" style="--spacing:var(--spacing-none)"><div class="prc-PageLayout-DraggableHandle-9s6B4" data-component="PageLayout.DragHandle" role="slider" aria-label="Draggable pane splitter" aria-valuemin="450" aria-valuemax="768" aria-valuenow="544" aria-valuetext="Pane width 544 pixels" tabindex="0"></div></div><div class="prc-PageLayout-Sidebar-iciWg" data-component="SplitPageLayout.Sidebar" data-resizable="true" style="--spacing:var(--spacing-normal);--pane-min-width:450px;--pane-max-width:768px;--pane-width-custom:544px;--pane-width-size:var(--pane-width-custom);--pane-width:544px"><div class="height-full" data-testid="copilot-code-view-side-panel"><div id="copilot-side-panel-content" class="height-full"></div></div></div></div><div class="prc-PageLayout-PageLayoutWrapper-2BhU2" data-width="full"><div class="prc-PageLayout-PageLayoutContent-BneH9"><div id="repos-file-tree-sidebar" class="CodeViewFileTreeLayout-module__sidebar__n_Aau" tabindex="0"><div class="prc-PageLayout-PaneWrapper-pHPop ReposFileTreePane-module__Pane__rBZpI ReposFileTreePane-module__HideTree__AYZnm ReposFileTreePane-module__HidePane__VHAVt" style="--offset-header:0px;--spacing-row:var(--spacing-none);--spacing-column:var(--spacing-none)" data-is-hidden="false" data-position="start" data-sticky="true"><div class="prc-PageLayout-HorizontalDivider-JLVqp prc-PageLayout-PaneHorizontalDivider-9tbnE" data-component="PageLayout.HorizontalDivider" data-variant-regular="none" data-variant-narrow="none" data-position="start" style="--spacing-divider:var(--spacing-none);--spacing:var(--spacing-none)"></div><div class="prc-PageLayout-Pane-AyzHK" data-component="SplitPageLayout.Pane" data-resizable="true" style="--spacing:var(--spacing-none);--pane-min-width:256px;--pane-max-width:calc(100vw - var(--pane-max-width-diff));--pane-width-size:var(--pane-width-large);--pane-width:320px"></div><div class="prc-PageLayout-VerticalDivider-9QRmK prc-PageLayout-PaneVerticalDivider-le57g" data-component="PageLayout.VerticalDivider" data-variant-narrow="none" data-variant-regular="line" data-variant-wide="line" data-position="start" style="--spacing:var(--spacing-none)"><div class="prc-PageLayout-DraggableHandle-9s6B4" data-component="PageLayout.DragHandle" role="slider" aria-label="Draggable pane splitter" aria-valuemin="256" aria-valuemax="600" aria-valuenow="320" aria-valuetext="Pane width 320 pixels" tabindex="0"></div></div></div></div><div data-component="SplitPageLayout.Content" class="prc-PageLayout-ContentWrapper-gR9eG"><div class="prc-PageLayout-Content-xWL-A" data-width="full" style="--spacing:var(--spacing-none)"><div class="SharedPageLayout-module__content__IwGAp" data-selector="repos-split-pane-content" id="repos-split-pane-content" tabindex="0"> <!-- --> <div class="container CodeViewHeader-module__Box__JkPOb"><div class="CodeViewHeader-module__StickyHeader__Qn7UN" id="StickyHeader"><div class="CodeViewHeader-module__Box_1__SbNDV"><div class="CodeViewHeader-module__Box_2__TB46f"><div class="react-code-view-header-wrap--narrow CodeViewHeader-module__Box_3__q1zUL"><div class="CodeViewHeader-module__treeToggleWrapper__RQ__9"><h2 class="use-tree-pane-module__Heading__s4QbZ prc-Heading-Heading-MtWFE" data-component="Heading"><button data-component="Button" type="button" aria-label="Expand file tree" data-testid="expand-file-tree-button-mobile" class="prc-Button-ButtonBase-9n-Xk ExpandFileTreeButton-module__Button_1__Svs95" data-loading="false" data-size="medium" data-variant="invisible"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-arrow-left" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M7.78 12.53a.75.75 0 0 1-1.06 0L2.47 8.28a.75.75 0 0 1 0-1.06l4.25-4.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L4.81 7h7.44a.75.75 0 0 1 0 1.5H4.81l2.97 2.97a.75.75 0 0 1 0 1.06Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3">Files</span></span></button><button data-component="IconButton" type="button" data-testid="expand-file-tree-button" aria-controls="repos-file-tree" class="prc-Button-ButtonBase-9n-Xk position-relative ExpandFileTreeButton-module__expandButton__hDOcv ExpandFileTreeButton-module__filesButtonBreakpoint__zEvz3 fgColor-muted prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="invisible" aria-labelledby="_R_4lla9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-sidebar-collapse" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M6.823 7.823a.25.25 0 0 1 0 .354l-2.396 2.396A.25.25 0 0 1 4 10.396V5.604a.25.25 0 0 1 .427-.177Z"></path><path d="M1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25V1.75C0 .784.784 0 1.75 0ZM1.5 1.75v12.5c0 .138.112.25.25.25H9.5v-13H1.75a.25.25 0 0 0-.25.25ZM11 14.5h3.25a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25H11Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="se" data-component="Tooltip" aria-hidden="true" id="_R_4lla9lik5_">Expand file tree</span><div class="d-none"></div></h2></div><div class="react-code-view-header-mb--narrow mr-2"><button data-component="Button" type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-label="main branch" data-testid="anchor-button" data-icv-name="Switch branches/tags" class="prc-Button-ButtonBase-9n-Xk ref-selector-class RefSelectorAnchoredOverlay-module__RefSelectorOverlayBtn__a3WK3" data-loading="false" data-size="medium" data-variant="default" id="ref-picker-repos-header-ref-selector-wide"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-git-branch" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3"><div class="RefSelectorAnchoredOverlay-module__RefSelectorOverlayContainer__yaf4p"><div style="max-width:125px" class="ref-selector-button-text-container RefSelectorAnchoredOverlay-module__RefSelectorBtnTextContainer__Di3rk"><span class="RefSelectorAnchoredOverlay-module__RefSelectorText__w_fmP">main</span></div></div></span><span data-component="trailingVisual" class="prc-Button-Visual-YNt2F prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-down" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path></svg></span></span></button><div class="d-none"></div></div><div class="react-code-view-header-mb--narrow CodeViewHeader-module__Box_5__MQ0hL"><div class="Breadcrumb-module__container__Vxvev Breadcrumb-module__lg__Rjz0A"><nav data-testid="breadcrumbs" aria-labelledby="repos-header-breadcrumb-heading" id="repos-header-breadcrumb" class="Breadcrumb-module__nav__rQFDj"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading" id="repos-header-breadcrumb-heading">Breadcrumbs</h2><ol class="Breadcrumb-module__list__ZH6zr"><li class="Breadcrumb-module__listItem__Ib0x_"><a class="Breadcrumb-module__repoLink__O2Nbs prc-Link-Link-9ZwDx" data-component="Link" data-testid="breadcrumbs-repo-link" href="/codewhale-hq/Codewhale/tree/main" data-discover="true">Codewhale</a></li><li class="Breadcrumb-module__listItem__Ib0x_"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__lg__Rjz0A" aria-hidden="true">/</span><a class="Breadcrumb-module__directoryLink__kQy_t prc-Link-Link-9ZwDx" data-component="Link" href="/codewhale-hq/Codewhale/tree/main/docs" data-discover="true">docs</a></li></ol></nav><div data-testid="breadcrumbs-filename" class="Breadcrumb-module__filename__equZR"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__lg__Rjz0A" aria-hidden="true">/</span><h1 class="Breadcrumb-module__filenameHeading__MNMtw Breadcrumb-module__lg__Rjz0A prc-Heading-Heading-MtWFE" data-component="Heading" tabindex="-1" id="file-name-id">TELEMETRY.md</h1></div><button data-component="IconButton" type="button" class="prc-Button-ButtonBase-9n-Xk ml-2 prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="invisible" aria-labelledby="_R_7lla9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copy" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></button><span class="CopyToClipboardIconButton-module__tooltip__WyiwL prc-TooltipV2-Tooltip-tLeuB" data-direction="nw" data-component="Tooltip" aria-label="Copy path" aria-hidden="true" id="_R_7lla9lik5_">Copy path</span></div></div></div><div class="react-code-view-header-element--wide"><div class="CodeViewHeader-module__Box_7___0R6c"><div class="d-flex gap-2"><div><div class="CodeViewHeader-module__FileResultsList__JDzUy"><span class="d-flex FileResultsList-module__FilesSearchBox__ivVkc TextInput-wrapper prc-components-TextInputWrapper-Hpdqi prc-components-TextInputBaseWrapper-wY-n0" data-no-trailing-action="true" data-component="TextInput" data-leading-visual="true" data-trailing-visual="true" aria-busy="false"><span class="TextInput-icon" id="_R_1cpla9lik5_" aria-hidden="true" data-component="TextInput.LeadingVisual"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-search" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path></svg></span><input type="text" aria-label="Go to file" role="combobox" aria-controls="file-results-list" aria-expanded="false" aria-haspopup="dialog" autoCorrect="off" spellCheck="false" placeholder="Go to file" aria-describedby="_R_1cpla9lik5_ _R_1cpla9lik5H1_" data-component="input" class="prc-components-Input-IwWrt" value=""/><span class="TextInput-icon" id="_R_1cpla9lik5H1_" aria-hidden="true" data-component="TextInput.TrailingVisual"></span></span></div><div class="d-none"></div></div><button data-component="Button" type="button" style="display:none" class="prc-Button-ButtonBase-9n-Xk NavigationMenu-module__Button__LpKgm" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="text" class="prc-Button-Label-FWkx3">Blame</span></span></button><div class="d-none"></div><button data-component="IconButton" type="button" data-testid="more-file-actions-button-nav-menu-wide" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-9n-Xk js-blob-dropdown-click NavigationMenu-module__IconButton__HpX3G prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default" aria-labelledby="_R_7p9la9lik5_" id="_R_99la9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-kebab-horizontal" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="nw" data-component="Tooltip" aria-hidden="true" id="_R_7p9la9lik5_">More file actions</span></div></div></div><div class="react-code-view-header-element--narrow"><div class="CodeViewHeader-module__Box_7___0R6c"><div class="d-flex gap-2"><button data-component="Button" type="button" style="display:none" class="prc-Button-ButtonBase-9n-Xk NavigationMenu-module__Button__LpKgm" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="text" class="prc-Button-Label-FWkx3">Blame</span></span></button><div class="d-none"></div><button data-component="IconButton" type="button" data-testid="more-file-actions-button-nav-menu-narrow" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-9n-Xk js-blob-dropdown-click NavigationMenu-module__IconButton__HpX3G prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default" aria-labelledby="_R_7pdla9lik5_" id="_R_9dla9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-kebab-horizontal" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="nw" data-component="Tooltip" aria-hidden="true" id="_R_7pdla9lik5_">More file actions</span></div></div></div></div></div></div></div><div class="CodeView-module__contentWrapper__cG2JH"><div class="react-code-view-bottom-padding"><div class="BlobTopBanners-module__Box__v_nvx"></div></div> <div class="d-none"></div><div class="d-flex flex-column border rounded-2 tmp-mb-3 pl-1"><div class="LatestCommit-module__Box__B25ZT"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading">Latest commit</h2><div style="width:120px" class="Skeleton Skeleton--text" data-testid="loading"> </div><div class="d-flex flex-shrink-0 gap-2"><div data-testid="latest-commit-details" class="d-none d-sm-flex flex-items-center"></div><div class="d-flex gap-2"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading">History</h2><a data-component="LinkButton" href="/codewhale-hq/Codewhale/commits/main/docs/TELEMETRY.md" class="prc-Button-ButtonBase-9n-Xk d-none d-lg-flex LinkButton-module__linkButton__nFnov flex-items-center fgColor-default" data-loading="false" data-size="small" data-variant="invisible"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-history" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3"><span class="fgColor-default">History</span></span></span></a><div class="d-sm-none"></div><div class="d-flex d-lg-none"><a data-component="LinkButton" aria-label="View commit history for this file." href="/codewhale-hq/Codewhale/commits/main/docs/TELEMETRY.md" class="prc-Button-ButtonBase-9n-Xk LinkButton-module__linkButton__nFnov flex-items-center fgColor-default" data-loading="false" data-size="small" data-variant="invisible" aria-describedby="_R_4mlala9lik5_"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-history" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path></svg></span></span></a><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="s" data-component="Tooltip" role="tooltip" aria-hidden="true" id="_R_4mlala9lik5_">History</span></div></div></div></div></div><div class="d-flex flex-row"><div class="container BlobViewContent-module__blobContainer__DtH2d"><div class="react-code-size-details-banner BlobViewContent-module__codeSizeDetails__e5sUw"><div class="react-code-size-details-banner CodeSizeDetails-module__Box__VcD6l"><div class="text-mono CodeSizeDetails-module__Box_1__GVxQL"><div data-testid="blob-size" class="CodeSizeDetails-module__Truncate_1__lE93V prc-Truncate-Truncate-2G1eo" data-inline="true" title="38.1 KB" style="--truncate-max-width:100%"><span>499 lines (397 loc) · 38.1 KB</span></div></div></div></div><div class="react-blob-view-header-sticky BlobViewContent-module__stickyHeader__VwxB5" id="repos-sticky-header"><div class="BlobViewHeader-module__Box__yhm9u"><div class="react-blob-sticky-header"><div class="FileNameStickyHeader-module__outerWrapper__ZL4Xc FileNameStickyHeader-module__outerWrapperHidden__Zpynk"><div class="FileNameStickyHeader-module__Box_1__Hazu5"><div class="FileNameStickyHeader-module__Box_2__hoolP"><div class="FileNameStickyHeader-module__Box_3__MVKsk"><button data-component="Button" type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-label="main branch" data-testid="anchor-button" data-icv-name="Switch branches/tags" class="prc-Button-ButtonBase-9n-Xk ref-selector-class RefSelectorAnchoredOverlay-module__RefSelectorOverlayBtn__a3WK3" data-loading="false" data-size="medium" data-variant="default" id="ref-picker-repos-header-ref-selector"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-git-branch" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3"><div class="RefSelectorAnchoredOverlay-module__RefSelectorOverlayContainer__yaf4p"><div style="max-width:125px" class="ref-selector-button-text-container RefSelectorAnchoredOverlay-module__RefSelectorBtnTextContainer__Di3rk"><span class="RefSelectorAnchoredOverlay-module__RefSelectorText__w_fmP">main</span></div></div></span><span data-component="trailingVisual" class="prc-Button-Visual-YNt2F prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-down" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path></svg></span></span></button><div class="d-none"></div></div><div class="FileNameStickyHeader-module__Box_4__FLhtt"><div class="Breadcrumb-module__container__Vxvev Breadcrumb-module__md__Wb1Gs"><nav data-testid="breadcrumbs" aria-labelledby="sticky-breadcrumb-heading" id="sticky-breadcrumb" class="Breadcrumb-module__nav__rQFDj"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading" id="sticky-breadcrumb-heading">Breadcrumbs</h2><ol class="Breadcrumb-module__list__ZH6zr"><li class="Breadcrumb-module__listItem__Ib0x_"><a class="Breadcrumb-module__repoLink__O2Nbs prc-Link-Link-9ZwDx" data-component="Link" data-testid="breadcrumbs-repo-link" href="/codewhale-hq/Codewhale/tree/main" data-discover="true">Codewhale</a></li><li class="Breadcrumb-module__listItem__Ib0x_"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__md__Wb1Gs" aria-hidden="true">/</span><a class="Breadcrumb-module__directoryLink__kQy_t prc-Link-Link-9ZwDx" data-component="Link" href="/codewhale-hq/Codewhale/tree/main/docs" data-discover="true">docs</a></li></ol></nav><div data-testid="breadcrumbs-filename" class="Breadcrumb-module__filename__equZR"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__md__Wb1Gs" aria-hidden="true">/</span><h1 class="Breadcrumb-module__filenameHeading__MNMtw Breadcrumb-module__md__Wb1Gs prc-Heading-Heading-MtWFE" data-component="Heading" tabindex="-1" id="sticky-file-name-id">TELEMETRY.md</h1></div><button data-component="IconButton" type="button" class="prc-Button-ButtonBase-9n-Xk ml-2 prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="invisible" aria-labelledby="_R_7lcpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copy" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></button><span class="CopyToClipboardIconButton-module__tooltip__WyiwL prc-TooltipV2-Tooltip-tLeuB" data-direction="s" data-component="Tooltip" aria-label="Copy path" aria-hidden="true" id="_R_7lcpala9lik5_">Copy path</span></div></div></div><button data-component="Button" type="button" class="prc-Button-ButtonBase-9n-Xk FileNameStickyHeader-module__Button__LSEU_ FileNameStickyHeader-module__GoToTopButton__nxAFn" data-loading="false" data-size="small" data-variant="invisible"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-arrow-up" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.47 7.78a.75.75 0 0 1 0-1.06l4.25-4.25a.75.75 0 0 1 1.06 0l4.25 4.25a.751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018L9 4.81v7.44a.75.75 0 0 1-1.5 0V4.81L4.53 7.78a.75.75 0 0 1-1.06 0Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3">Top</span></span></button></div></div></div><div class="BlobViewHeader-module__Box_1__VEmuQ"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading">File metadata and controls</h2><div class="BlobViewHeader-module__Box_2__icUs2"><ul aria-label="File view" class="prc-SegmentedControl-SegmentedControl-lqIXp BlobTabButtons-module__SegmentedControl__jen2u" data-variant="default" data-size="small" data-component="SegmentedControl"><li class="prc-SegmentedControl-Item-tSCQh" data-selected="" data-component="SegmentedControl.Button"><button aria-pressed="true" class="prc-SegmentedControl-Button-E48xz" type="button" style="--separator-color:transparent"><span class="prc-SegmentedControl-Content-1COlk segmentedControl-content"><div class="prc-SegmentedControl-Text-7S2y2 segmentedControl-text" data-text="Preview">Preview</div></span></button></li><li class="prc-SegmentedControl-Item-tSCQh" data-component="SegmentedControl.Button"><button aria-pressed="false" class="prc-SegmentedControl-Button-E48xz" type="button" style="--separator-color:var(--borderColor-default)"><span class="prc-SegmentedControl-Content-1COlk segmentedControl-content"><div class="prc-SegmentedControl-Text-7S2y2 segmentedControl-text" data-text="Code">Code</div></span></button></li><li class="prc-SegmentedControl-Item-tSCQh" data-component="SegmentedControl.Button"><button aria-pressed="false" class="prc-SegmentedControl-Button-E48xz" type="button" style="--separator-color:var(--borderColor-default)"><span class="prc-SegmentedControl-Content-1COlk segmentedControl-content"><div class="prc-SegmentedControl-Text-7S2y2 segmentedControl-text" data-text="Blame">Blame</div></span></button></li></ul><div class="d-none"></div><div class="react-code-size-details-in-header CodeSizeDetails-module__Box__VcD6l"><div class="text-mono CodeSizeDetails-module__Box_1__GVxQL"><div data-testid="blob-size" class="CodeSizeDetails-module__Truncate_1__lE93V prc-Truncate-Truncate-2G1eo" data-inline="true" title="38.1 KB" style="--truncate-max-width:100%"><span>499 lines (397 loc) · 38.1 KB</span></div></div></div></div><div class="BlobViewHeader-module__Box_3__ng6v2"><div class="d-none"></div><div class="react-blob-header-edit-and-raw-actions BlobViewHeader-module__Box_4__J4Y4W"><div class="d-none"></div><div class="prc-ButtonGroup-ButtonGroup-vFUrY" data-component="ButtonGroup"><div class="prc-ButtonGroup-Item-PqvDl"><a data-component="LinkButton" href="https://github.com/codewhale-hq/Codewhale/raw/refs/heads/main/docs/TELEMETRY.md" data-testid="raw-button" class="prc-Button-ButtonBase-9n-Xk LinkButton-module__linkButton__nFnov BlobViewHeader-module__LinkButton__X9kx2" data-loading="false" data-no-visuals="true" data-size="small" data-variant="default"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="text" class="prc-Button-Label-FWkx3">Raw</span></span></a></div><div class="prc-ButtonGroup-Item-PqvDl"><button data-component="IconButton" type="button" data-testid="copy-raw-button" class="prc-Button-ButtonBase-9n-Xk prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="default" aria-labelledby="_R_qaucpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copy" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="n" data-component="Tooltip" aria-hidden="true" id="_R_qaucpala9lik5_">Copy raw file</span></div><div class="prc-ButtonGroup-Item-PqvDl"><button data-component="IconButton" type="button" data-testid="download-raw-button" class="prc-Button-ButtonBase-9n-Xk BlobViewHeader-module__downloadButton__ef459 prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="default" aria-labelledby="_R_eaucpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-download" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2.75 14A1.75 1.75 0 0 1 1 12.25v-2.5a.75.75 0 0 1 1.5 0v2.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25v-2.5a.75.75 0 0 1 1.5 0v2.5A1.75 1.75 0 0 1 13.25 14Z"></path><path d="M7.25 7.689V2a.75.75 0 0 1 1.5 0v5.689l1.97-1.969a.749.749 0 1 1 1.06 1.06l-3.25 3.25a.749.749 0 0 1-1.06 0L4.22 6.78a.749.749 0 1 1 1.06-1.06l1.97 1.969Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="n" data-component="Tooltip" aria-hidden="true" id="_R_eaucpala9lik5_">Download raw file</span></div></div></div><button data-component="IconButton" type="button" aria-pressed="false" class="prc-Button-ButtonBase-9n-Xk tmp-mr-2 TableOfContents-module__IconButton__jrlNM prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="invisible" aria-labelledby="_R_3ucpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-list-unordered" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M5.75 2.5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5Zm0 5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5Zm0 5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5ZM2 14a1 1 0 1 1 0-2 1 1 0 0 1 0 2Zm1-6a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM2 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="n" data-component="Tooltip" aria-hidden="true" id="_R_3ucpala9lik5_">Outline</span><div class="react-blob-header-edit-and-raw-actions-combined"><button data-component="IconButton" type="button" title="More file actions" data-testid="more-file-actions-button" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-9n-Xk js-blob-dropdown-click BlobViewHeader-module__IconButton__XrMQY prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="invisible" aria-labelledby="_R_fkecpala9lik5_" id="_R_kecpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-kebab-horizontal" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="nw" data-component="Tooltip" aria-hidden="true" id="_R_fkecpala9lik5_">Edit and raw actions</span></div></div></div></div><div></div></div><div class="BlobViewContent-module__blobContentWrapper__JS0W6"><section aria-labelledby="file-name-id-wide file-name-id-mobile" class="BlobContent-module__blobContentSection__VOgZq BlobContent-module__blobContentSectionMarkdown__mPLOK" style="margin-top:46px"><div class="js-snippet-clipboard-copy-unpositioned BlobContent-module__markdownBlob__T8jpG" data-hpc="true" containertiming="hpc"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 tabindex="-1" class="heading-element" dir="auto">Codewhale product telemetry</h1><a id="user-content-codewhale-product-telemetry" class="anchor" aria-label="Permalink: Codewhale product telemetry" href="#codewhale-product-telemetry"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<blockquote>
<p dir="auto">阅读简体中文版：<a href="/codewhale-hq/Codewhale/blob/main/docs/zh_hans/TELEMETRY.md">zh_hans/TELEMETRY.md</a></p>
</blockquote>
<p dir="auto"><strong>Usage analytics are on by default in the current source.</strong> The first
interactive launch gives a localized, nonblocking disclosure naming <strong>Codewhale
and PostHog</strong>, with a direct route to turn counting off. Notice version <code>5</code>
describes this policy; displaying it is not recorded as human acceptance.
Missing an older acceptance record does not turn a fresh installation off.
Existing explicit opt-outs remain off across upgrades, and unreadable privacy
state fails closed. Environment and CLI kill switches still take precedence.</p>
<p dir="auto">Read the disclosure with <code>codewhale config telemetry</code>. Turn usage off in
<code>/settings</code> or run <code>codewhale config set telemetry false</code>. Turning it back on
in Settings or with <code>codewhale config set telemetry true</code> updates the existing
durable preference and privacy records for new sessions. The compatibility
command <code>codewhale config telemetry --accept-notice 5</code> remains available, but
is not required for a fresh installation. Collection never includes work content or credentials.</p>
<p dir="auto">The PostHog sink is optional and inert until the ingest operator explicitly
configures a project token and approved regional host, and records staging
proof that the actual egress path does not forward the original client IP.
Source readiness does not establish a deployment, an activated processor,
an egress receipt, or a retention setting.</p>
<p dir="auto">Codewhale does not collect conversations, code, prompts, files, file/repo/branch
names, model content, or credentials. It sends no per-turn or per-tool timeline.
It does send the closed, aggregate schema below: version and platform classes,
session duration/outcome, feature/error counters, and a random install id that
rotates every 90 days.</p>
<p dir="auto"><strong>There is now a real endpoint.</strong> An enabled session sends its batches to the
first-party ingest service at <code>https://telemetry.codewhale.net/v1/telemetry</code>,
which is the shipped default for <code>telemetry_endpoint</code>. What that service is,
what it stores, and what it structurally cannot store is spelled out in "What
the endpoint does" below.</p>
<p dir="auto"><strong>To send nothing anywhere, turn telemetry off</strong> (see "Turning it off"). To stay
enabled but contact nobody, set <code>telemetry_endpoint = ""</code>: batches are then
appended to <code>$CODEWHALE_HOME/telemetry/dryrun.jsonl</code> on your own machine, byte
for byte what the server would have received, and no HTTP client is ever
constructed. That file is how you audit this document against reality.</p>
<p dir="auto">This document is the schema. It is not a summary of the schema: a test in
<code>crates/telemetry</code> parses the field names out of this file and asserts set
equality against the structs the serializer actually uses, so a field that is
here and not in the code — or in the code and not here — fails the build.</p>
<p dir="auto">Local saved sessions and <code>codewhale metrics</code> remain available with telemetry
disabled and require no account or hosted reporting service. Disabling telemetry
does not disable local usage receipts.</p>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Turning it off</h2><a id="user-content-turning-it-off" class="anchor" aria-label="Permalink: Turning it off" href="#turning-it-off"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">There are two off switches and they do different things. Both stop collection
completely; only one of them erases anything.</p>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="codewhale config set telemetry false     # opt out: stops collection and erases state
CODEWHALE_TELEMETRY=0 codewhale          # kill switch: stops collection, erases nothing
codewhale --telemetry false              # the same kill switch, for one command"><pre>codewhale config <span class="pl-c1">set</span> telemetry <span class="pl-c1">false</span>     <span class="pl-c"><span class="pl-c">#</span> opt out: stops collection and erases state</span>
CODEWHALE_TELEMETRY=0 codewhale          <span class="pl-c"><span class="pl-c">#</span> kill switch: stops collection, erases nothing</span>
codewhale --telemetry <span class="pl-c1">false</span>              <span class="pl-c"><span class="pl-c">#</span> the same kill switch, for one command</span></pre></div>
<p dir="auto"><strong><code>telemetry = false</code> in the config file is the opt-out.</strong> It is a floor:
<code>--telemetry true</code> and <code>CODEWHALE_TELEMETRY=1</code> both lose to it, because a
setting you can undo by accident from a wrapper script is not a setting. It
deletes the random install id, truncates every buffered event and every dry-run
record, and writes a tombstone. Appends, identity/state writes, and delivery all
share the wipe's ordering lock, so once opt-out returns no pre-opt-out write or
POST remains in flight. If any part of that wipe fails, the tombstone is still
there and the buffer is undrainable — a failed wipe fails closed. Every later
run re-asserts the same tombstone for as long as the setting stands, so it
survives. Turning telemetry back on in <code>/settings</code> records that explicit preference
in both existing privacy registers; a fresh launch can then clear the tombstone. Nothing buffered before that point is
ever sent.</p>
<p dir="auto"><strong>The environment variable and the flag are kill switches, not opt-outs.</strong>
Telemetry is off for the run, nothing is written, nothing is sent — and
nothing on disk is touched or deleted. That is deliberate: a harness or agent
that sets <code>CODEWHALE_TELEMETRY=0</code> for one command must not silently discard the
install id and the dry-run records of the person who owns the machine. If you
want the erasing kind, use the config file.</p>
<p dir="auto"><code>CODEWHALE_TELEMETRY</code> (and its <code>DEEPSEEK_TELEMETRY</code> alias) accepts
<code>0</code>, <code>1</code>, <code>true</code>, <code>false</code>, <code>yes</code>, <code>no</code>, <code>on</code>, <code>off</code>, <code>enabled</code>, <code>disabled</code>.
A value this list cannot read also resolves to off — a typo in a kill switch
must never resolve to "on".</p>
<p dir="auto">The first-run notice is not shown when telemetry is already persistently off or
a run-scoped kill switch is active. The notice never rewrites a
<code>telemetry = false</code> you put there yourself.</p>
<p dir="auto">A repo-local <code>.codewhale/config.toml</code> can set neither <code>telemetry</code> nor
<code>telemetry_endpoint</code>, and a workspace <code>.env</code> can set neither. Someone else's
repository cannot turn your telemetry on or aim it at a host of their choosing.</p>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Where it lives, and how much of your disk it uses</h2><a id="user-content-where-it-lives-and-how-much-of-your-disk-it-uses" class="anchor" aria-label="Permalink: Where it lives, and how much of your disk it uses" href="#where-it-lives-and-how-much-of-your-disk-it-uses"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">Everything is under <code>$CODEWHALE_HOME/telemetry/</code> (<code>0700</code>), every file <code>0600</code>:</p>
<markdown-accessiblity-table><table>
<thead>
<tr>
<th>file</th>
<th>role</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>buffer.jsonl</code></td>
<td>pending events, one JSON object per line</td>
</tr>
<tr>
<td><code>buffer.jsonl.lock</code></td>
<td>the sibling ordering lock shared by writes, delivery, arming, and wipe</td>
</tr>
<tr>
<td><code>dryrun.jsonl</code></td>
<td>where batches go when the endpoint is configured empty</td>
</tr>
<tr>
<td><code>state.json</code></td>
<td>the last app version seen and the last flush attempt</td>
</tr>
<tr>
<td><code>install_id.json</code></td>
<td>the random install id and when it was minted</td>
</tr>
<tr>
<td><code>disabled</code></td>
<td>the tombstone; present means nothing is appended or sent</td>
</tr>
</tbody>
</table></markdown-accessiblity-table>
<p dir="auto">Both <code>buffer.jsonl</code> and <code>dryrun.jsonl</code> are rings capped at 512 records or
256 KiB, whichever comes first, with the oldest dropped. The documented
footprint ceiling for the whole directory is therefore <strong>512 KiB plus a few
hundred bytes of metadata</strong>.</p>
<p dir="auto">The install id is a random v4 UUID. It is never derived from your hostname,
MAC address, <code>machine-id</code>, home directory, username, or executable path — a
derived id is a device fingerprint that survives reinstall and re-identifies
you across your own opt-out. It is regenerated whenever
<code>$CODEWHALE_HOME/telemetry/</code> is cleared, which opting out does automatically,
and in any case every 90 days.</p>
<p dir="auto">There is no factory-reset command in Codewhale, so this document does not
claim one.</p>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">When anything is sent, and where</h2><a id="user-content-when-anything-is-sent-and-where" class="anchor" aria-label="Permalink: When anything is sent, and where" href="#when-anything-is-sent-and-where"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">Nothing is collected or sent when a persistent opt-out or run-scoped kill
switch is in force, or when privacy state is unreadable. TUI and <code>exec</code> sessions have exactly one network flush point: an attempt
during shutdown, bounded at three seconds. Short CLI commands such as <code>config</code>,
<code>doctor</code>, and <code>auth</code> do not wait for that network request. They record
<code>session_end</code>, seal the event to the local buffer with a much shorter bound, and
return; a configured endpoint sends those buffered events with the next
interactive shutdown flush. An explicitly empty endpoint finalizes its local
dry-run batch immediately.</p>
<p dir="auto">There is no startup flush, mid-session flush, per-turn flush, or per-tool-call
flush. Every network shutdown flush re-resolves your setting from disk
immediately beforehand, so <code>codewhale config set telemetry false</code> written from
another terminal stops the flush of a session that is already running.</p>
<p dir="auto">A flush is <strong>one <code>POST</code></strong> to the resolved endpoint — by default
<code>https://telemetry.codewhale.net/v1/telemetry</code>. The request carries a
<code>content-type: application/json</code> header, a
<code>user-agent: codewhale-telemetry/&lt;app_version&gt;</code>, and the batch body. That is
all: no cookies (the HTTP client is built without a cookie jar to disable), no
redirects (refused outright), no <code>Authorization</code> header, no custom headers, and
no query string. The response body is discarded unread; only the status class is
looked at.</p>
<p dir="auto"><code>https://</code> is required. Plain <code>http://</code> is accepted only for a loopback host, so
you can point the client at a recorder of your own and read the wire form
directly; no environment variable overrides that refusal. An endpoint the client
refuses turns telemetry off for the run rather than falling back to a different
destination.</p>
<p dir="auto">Any failure — DNS, connect, TLS, timeout, non-2xx — drops the batch. There is
no retry, no backoff, and no re-queue. A permanently offline machine attempts at
most once per flush point and never grows a queue.</p>
<hr>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Event schema</h2><a id="user-content-event-schema" class="anchor" aria-label="Permalink: Event schema" href="#event-schema"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto"><code>SCHEMA_VERSION = 3</code>. <code>notice_version = 5</code> identifies the disclosed default-on
policy; it does not assert human consent or that a notice was seen. The closed
v2 contract still accepts only <code>consent_version = 4</code>, retaining its original
explicit opt-in meaning. Fields cannot be mixed between versions. The unchanged
v1 contract remains first-party only and <strong>never sent to PostHog</strong>; it refuses
new fields, surfaces, and <code>product_usage</code> events.</p>
<p dir="auto">Every field is an integer, a boolean, or a <strong>closed enum string</strong>, except exactly three bounded strings: <code>app_version</code>, <code>git_sha</code>, <code>panic_site</code>. Each of the three has a written rule and a test pinning the rule. <strong>There is no free-form string type in this schema, and no open-keyed map.</strong> That is the property that makes red line 3 enforceable rather than aspirational.</p>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Batch envelope — sent on every POST</h3><a id="user-content-batch-envelope--sent-on-every-post" class="anchor" aria-label="Permalink: Batch envelope — sent on every POST" href="#batch-envelope--sent-on-every-post"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<div class="highlight highlight-source-json-comments notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="{
  &quot;schema_version&quot;: 3,
  &quot;notice_version&quot;: 5,
  &quot;sent_at&quot;:     &quot;2026-08-03T18:04:11Z&quot;,   // RFC3339 UTC, second precision
  &quot;install_id&quot;:  &quot;3f2a…&quot;,                  // uuid v4, rotates every 90 days
  &quot;app_version&quot;: &quot;0.9.12&quot;,
  &quot;git_sha&quot;:     null,                     // non-null only for SHA-stamped builds
  &quot;surface&quot;:     &quot;tui&quot;,
  &quot;os&quot;:          &quot;macos&quot;,
  &quot;arch&quot;:        &quot;aarch64&quot;,
  &quot;libc&quot;:        &quot;none&quot;,
  &quot;tty&quot;:         true,
  &quot;events&quot;:      [ … ]
}"><pre>{
  <span class="pl-ent">"schema_version"</span>: <span class="pl-c1">3</span>,
  <span class="pl-ent">"notice_version"</span>: <span class="pl-c1">5</span>,
  <span class="pl-ent">"sent_at"</span>:     <span class="pl-s"><span class="pl-pds">"</span>2026-08-03T18:04:11Z<span class="pl-pds">"</span></span>,   <span class="pl-c"><span class="pl-c">//</span> RFC3339 UTC, second precision</span>
  <span class="pl-ent">"install_id"</span>:  <span class="pl-s"><span class="pl-pds">"</span>3f2a…<span class="pl-pds">"</span></span>,                  <span class="pl-c"><span class="pl-c">//</span> uuid v4, rotates every 90 days</span>
  <span class="pl-ent">"app_version"</span>: <span class="pl-s"><span class="pl-pds">"</span>0.9.12<span class="pl-pds">"</span></span>,
  <span class="pl-ent">"git_sha"</span>:     <span class="pl-c1">null</span>,                     <span class="pl-c"><span class="pl-c">//</span> non-null only for SHA-stamped builds</span>
  <span class="pl-ent">"surface"</span>:     <span class="pl-s"><span class="pl-pds">"</span>tui<span class="pl-pds">"</span></span>,
  <span class="pl-ent">"os"</span>:          <span class="pl-s"><span class="pl-pds">"</span>macos<span class="pl-pds">"</span></span>,
  <span class="pl-ent">"arch"</span>:        <span class="pl-s"><span class="pl-pds">"</span>aarch64<span class="pl-pds">"</span></span>,
  <span class="pl-ent">"libc"</span>:        <span class="pl-s"><span class="pl-pds">"</span>none<span class="pl-pds">"</span></span>,
  <span class="pl-ent">"tty"</span>:         <span class="pl-c1">true</span>,
  <span class="pl-ent">"events"</span>:      [ <span class="pl-ii">…</span> ]
}</pre></div>
<markdown-accessiblity-table><table>
<thead>
<tr>
<th>Field</th>
<th>Type</th>
<th>Source anchor</th>
<th>Rule</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>schema_version</code></td>
<td><code>u32</code></td>
<td>const in <code>crates/telemetry/src/event.rs</code></td>
<td>Bumped on any field add/remove/retype. Never reused. Pinned by a golden snapshot test.</td>
</tr>
<tr>
<td><code>notice_version</code></td>
<td><code>u32</code></td>
<td>policy constant in <code>crates/telemetry/src/event.rs</code></td>
<td>Exactly <code>5</code>; identifies the disclosed opt-out policy, not a human acceptance record.</td>
</tr>
<tr>
<td><code>sent_at</code></td>
<td>RFC3339</td>
<td><code>chrono::Utc::now()</code></td>
<td>Second precision. Per-<strong>batch</strong> only — events carry no timestamps at all.</td>
</tr>
<tr>
<td><code>install_id</code></td>
<td>uuid v4</td>
<td><code>crates/telemetry/src/envelope.rs</code></td>
<td>Random, never derived, rotated every 90 days. See "Where it lives" above.</td>
</tr>
<tr>
<td><code>app_version</code></td>
<td>string</td>
<td><code>env!("CARGO_PKG_VERSION")</code>, as at <code>crates/telemetry/src/lib.rs:112</code></td>
<td>Must match <code>^\d+\.\d+\.\d+(-[0-9A-Za-z.]+)?$</code>.</td>
</tr>
<tr>
<td><code>git_sha</code></td>
<td>string | null</td>
<td><code>option_env!("CODEWHALE_RELEASE_BUILD_SHA")</code> — a <strong>new</strong> rustc-env</td>
<td>First 12 hex chars. Emitted <strong>only</strong> when <code>codewhale_build_support::release_build_sha</code> saw a valid full SHA in <code>CODEWHALE_BUILD_SHA</code>, the legacy <code>DEEPSEEK_BUILD_SHA</code>, or <code>GITHUB_SHA</code>, in that precedence order. <code>null</code> for every unstamped build, with no runtime lookup of any kind. <strong>Never</strong> <code>CODEWHALE_BUILD_COMMIT</code> — that falls back to <code>git_commit</code> and is the builder's private HEAD. <strong>Never</strong> <code>Thread.git_sha</code> (<code>crates/state/src/lib.rs:93</code>) — that is the user's workspace commit and a red line, one identifier away by name.</td>
</tr>
<tr>
<td><code>surface</code></td>
<td>enum</td>
<td>explicitly set by the emitting client</td>
<td><code>tui | exec | cli | app-server | mcp-server | serve | website | web-app | desktop | control-plane | vscode-extension</code>. Runtime metrics keep their existing collector. Browser product counts use the same closed envelope. A declared surface is not proof its client is deployed. <code>vscode-extension</code> is an extension client of this schema, deliberately generic the way <code>web-app</code> and <code>desktop</code> are: the editor's own name and version are <strong>not</strong> collected. Widening this whitelist changes no field, so the schema version is unchanged.</td>
</tr>
<tr>
<td><code>os</code></td>
<td>enum</td>
<td><code>std::env::consts::OS</code>, as at <code>crates/cli/src/update.rs:41</code></td>
<td>Whitelist: <code>linux | macos | windows | freebsd | android | other</code>.</td>
</tr>
<tr>
<td><code>arch</code></td>
<td>enum</td>
<td><code>std::env::consts::ARCH</code></td>
<td><code>x86_64 | aarch64 | other</code>.</td>
</tr>
<tr>
<td><code>libc</code></td>
<td>enum</td>
<td><code>cfg!(target_env)</code> — <strong>compile time</strong></td>
<td><code>gnu | musl | none</code>. Runtime detection reads distro vendor strings; compile-time is free and leaks nothing.</td>
</tr>
<tr>
<td><code>tty</code></td>
<td>bool</td>
<td><code>std::io::IsTerminal</code>, as at <code>crates/telemetry/src/envelope.rs:196</code></td>
<td><code>stdin().is_terminal() &amp;&amp; stdout().is_terminal()</code>.</td>
</tr>
<tr>
<td><code>events</code></td>
<td>array</td>
<td>the drained buffer</td>
<td>Every element is one of the six events below and nothing else. Capped at 200 events or 64 KiB per batch; a batch that would exceed either cap leaves the remainder buffered for the next flush.</td>
</tr>
</tbody>
</table></markdown-accessiblity-table>
<p dir="auto"><strong><code>os_major</code> is not collected.</strong> Reading it costs unsafe FFI on two platforms plus a file parser on a third, in the one crate whose entire value is being small enough to audit — and <code>os</code>, <code>arch</code>, and <code>libc</code> are free and answer the platform question. It may be reconsidered if the stored data ever shows that the OS-version cut is what triage is missing; a hunch is not that evidence.</p>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Which surfaces emit</h3><a id="user-content-which-surfaces-emit" class="anchor" aria-label="Permalink: Which surfaces emit" href="#which-surfaces-emit"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">Every runtime surface uses the same <code>decide</code> and flush recheck: readable privacy
state, resolvable home, valid endpoint, and no persistent opt-out or run kill
switch. Missing preferences default on. The interactive TUI shows the disclosure;
headless commands never synthesize consent. Existing runtime events and counters
are unchanged; adding PostHog does not add a second runtime collector.</p>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">An embedder declares the server it started</h3><a id="user-content-an-embedder-declares-the-server-it-started" class="anchor" aria-label="Permalink: An embedder declares the server it started" href="#an-embedder-declares-the-server-it-started"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">A client that starts <code>codewhale serve</code> may name itself, so its sessions are not
counted as anonymous <code>serve</code> traffic from nobody in particular. It sets
<code>CODEWHALE_TELEMETRY_SURFACE</code> to a value in the <code>surface</code> whitelist before
spawning the server; the extension client uses <code>vscode-extension</code>.</p>
<p dir="auto">Three properties of that read are deliberate:</p>
<ul dir="auto">
<li><strong><code>serve</code> only.</strong> The variable is inherited by descendant processes, and an
agent's shell command runs <code>codewhale</code> descendants carrying this environment.
Only the branch that <em>is</em> the embedder's own server consults it, so a nested
<code>codewhale exec</code> cannot report itself as the embedder.</li>
<li><strong><code>tui</code> is refused</strong>, and <code>serve --mcp</code> still reports <code>mcp-server</code>: nothing
starts the interactive terminal UI on a user's behalf, and a server is not an
MCP server because an embedder said so.</li>
<li><strong>An unrecognised name is dropped, not repaired.</strong> A value outside the
whitelist falls back to <code>serve</code> rather than failing startup or being guessed
at; the field is a label, and the default is the honest one.</li>
</ul>
<p dir="auto">This changes how an embedder's sessions are <em>labelled</em>. It does not change
whether anything may be collected: the server resolves that itself, from the
same durable config, the same setup state, and the same <code>CODEWHALE_TELEMETRY</code>
run-scoped kill switch. An embedder cannot enable collection where the user has
turned it off, and a durable opt-out in one client is a durable opt-out for every
client on the machine, because they share one home and one install identity.</p>
<p dir="auto">The extension client is the worked example: it holds a single on/off setting and
passes <code>CODEWHALE_TELEMETRY=0</code> when the user turns reporting off. It contains no
payload builder, no buffer, and no transport of its own — so its sessions share
the home's <code>install_id</code> rather than minting a second one, and one installation is
one install in every count derived from that id.</p>
<p dir="auto">Because that switch is run-scoped rather than a durable opt-out, turning it off
stops the engine this extension starts and leaves the shared buffer and identity
alone: those belong to every surface on the machine, not to one window, and
clearing them would silently change what the user's terminal sessions do. A user
who wants reporting stopped and cleared everywhere does that once, with
<code>codewhale config set telemetry false</code>.</p>
<p dir="auto">Website and application clients use <code>product_usage</code>, with notice version <code>5</code>,
a random browser-local v4 ID rotated after 90 days, <code>os = other</code>, <code>arch = other</code>,
<code>libc = none</code>, <code>tty = false</code>, and <code>git_sha = null</code>. They do not inspect the browser
fingerprint. Their configured same-origin proxy forwards only this bounded JSON
to the first-party ingest, with no incoming cookies, headers, URLs, or identities.
The browser endpoint is inert if unconfigured. Browser opt-out clears pending
counts and local identity; actions taken while disabled are never backfilled.
Product usage settings belong in the app and runtime; marketing privacy details
and any website opt-out belong on the privacy page.</p>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Event: <code>install_or_upgrade</code></h3><a id="user-content-event-install_or_upgrade" class="anchor" aria-label="Permalink: Event: install_or_upgrade" href="#event-install_or_upgrade"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">Emitted once when <code>state.json</code>'s <code>last_version</code> differs from <code>app_version</code>.</p>
<div class="highlight highlight-source-json-comments notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="{ &quot;event&quot;: &quot;install_or_upgrade&quot;, &quot;kind&quot;: &quot;upgrade&quot;, &quot;previous_version&quot;: &quot;0.9.3&quot; }"><pre>{ <span class="pl-ent">"event"</span>: <span class="pl-s"><span class="pl-pds">"</span>install_or_upgrade<span class="pl-pds">"</span></span>, <span class="pl-ent">"kind"</span>: <span class="pl-s"><span class="pl-pds">"</span>upgrade<span class="pl-pds">"</span></span>, <span class="pl-ent">"previous_version"</span>: <span class="pl-s"><span class="pl-pds">"</span>0.9.3<span class="pl-pds">"</span></span> }</pre></div>
<markdown-accessiblity-table><table>
<thead>
<tr>
<th>Field</th>
<th>Type</th>
<th>Source</th>
<th>Rule</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>kind</code></td>
<td>enum</td>
<td>derived</td>
<td><code>install</code> (no prior record) | <code>upgrade</code> | <code>downgrade</code>.</td>
</tr>
<tr>
<td><code>previous_version</code></td>
<td>string | null</td>
<td><code>$CODEWHALE_HOME/telemetry/state.json</code> <strong>only</strong></td>
<td>Same regex as <code>app_version</code>. Never derived from session history or config mtimes — those files have a different privacy contract.</td>
</tr>
</tbody>
</table></markdown-accessiblity-table>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Event: <code>session_start</code></h3><a id="user-content-event-session_start" class="anchor" aria-label="Permalink: Event: session_start" href="#event-session_start"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<div class="highlight highlight-source-json-comments notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="{ &quot;event&quot;: &quot;session_start&quot;, &quot;source&quot;: &quot;interactive&quot; }"><pre>{ <span class="pl-ent">"event"</span>: <span class="pl-s"><span class="pl-pds">"</span>session_start<span class="pl-pds">"</span></span>, <span class="pl-ent">"source"</span>: <span class="pl-s"><span class="pl-pds">"</span>interactive<span class="pl-pds">"</span></span> }</pre></div>
<p dir="auto"><code>source</code> is <code>SessionSource</code> (<code>crates/state/src/lib.rs:34-41</code>) stringified by <code>session_source_to_str</code> (<code>:1909-1917</code>): <code>interactive | resume | fork | api | unknown</code>.</p>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Event: <code>session_end</code></h3><a id="user-content-event-session_end" class="anchor" aria-label="Permalink: Event: session_end" href="#event-session_end"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">The workhorse. Everything a session accumulated ships here, once.</p>
<div class="highlight highlight-source-json-comments notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="{
  &quot;event&quot;: &quot;session_end&quot;,
  &quot;duration_bucket&quot;: &quot;1m_10m&quot;,
  &quot;exit_class&quot;: &quot;clean&quot;,
  &quot;cold_start_bucket&quot;: &quot;250_1000&quot;,
  &quot;providers&quot;: [&quot;deepseek&quot;, &quot;custom&quot;],
  &quot;counters&quot;: { &quot;turns&quot;: 14, &quot;tool_calls&quot;: 61, &quot;fleet_dispatch&quot;: 0, &quot;workflow_run&quot;: 0,
                &quot;subagent_spawn&quot;: 2, &quot;mcp_server_connected&quot;: 0, &quot;memory_search&quot;: 0,
                &quot;approval_modal_shown&quot;: 0, &quot;approval_auto_allowed&quot;: 0,
                &quot;command_palette_open&quot;: 3 },
  &quot;errors&quot;:   { &quot;auth_preflight_failed&quot;: 0, &quot;provider_http_4xx&quot;: 0, &quot;provider_http_5xx&quot;: 1,
                &quot;tool_denied_by_policy&quot;: 0, &quot;tool_timeout&quot;: 0, &quot;network_error&quot;: 0 },
  &quot;turn_wall&quot;: { &quot;lt_5s&quot;: 9, &quot;5_30s&quot;: 4, &quot;30_120s&quot;: 1, &quot;gte_120s&quot;: 0 }
}"><pre>{
  <span class="pl-ent">"event"</span>: <span class="pl-s"><span class="pl-pds">"</span>session_end<span class="pl-pds">"</span></span>,
  <span class="pl-ent">"duration_bucket"</span>: <span class="pl-s"><span class="pl-pds">"</span>1m_10m<span class="pl-pds">"</span></span>,
  <span class="pl-ent">"exit_class"</span>: <span class="pl-s"><span class="pl-pds">"</span>clean<span class="pl-pds">"</span></span>,
  <span class="pl-ent">"cold_start_bucket"</span>: <span class="pl-s"><span class="pl-pds">"</span>250_1000<span class="pl-pds">"</span></span>,
  <span class="pl-ent">"providers"</span>: [<span class="pl-s"><span class="pl-pds">"</span>deepseek<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>custom<span class="pl-pds">"</span></span>],
  <span class="pl-ent">"counters"</span>: { <span class="pl-ent">"turns"</span>: <span class="pl-c1">14</span>, <span class="pl-ent">"tool_calls"</span>: <span class="pl-c1">61</span>, <span class="pl-ent">"fleet_dispatch"</span>: <span class="pl-c1">0</span>, <span class="pl-ent">"workflow_run"</span>: <span class="pl-c1">0</span>,
                <span class="pl-ent">"subagent_spawn"</span>: <span class="pl-c1">2</span>, <span class="pl-ent">"mcp_server_connected"</span>: <span class="pl-c1">0</span>, <span class="pl-ent">"memory_search"</span>: <span class="pl-c1">0</span>,
                <span class="pl-ent">"approval_modal_shown"</span>: <span class="pl-c1">0</span>, <span class="pl-ent">"approval_auto_allowed"</span>: <span class="pl-c1">0</span>,
                <span class="pl-ent">"command_palette_open"</span>: <span class="pl-c1">3</span> },
  <span class="pl-ent">"errors"</span>:   { <span class="pl-ent">"auth_preflight_failed"</span>: <span class="pl-c1">0</span>, <span class="pl-ent">"provider_http_4xx"</span>: <span class="pl-c1">0</span>, <span class="pl-ent">"provider_http_5xx"</span>: <span class="pl-c1">1</span>,
                <span class="pl-ent">"tool_denied_by_policy"</span>: <span class="pl-c1">0</span>, <span class="pl-ent">"tool_timeout"</span>: <span class="pl-c1">0</span>, <span class="pl-ent">"network_error"</span>: <span class="pl-c1">0</span> },
  <span class="pl-ent">"turn_wall"</span>: { <span class="pl-ent">"lt_5s"</span>: <span class="pl-c1">9</span>, <span class="pl-ent">"5_30s"</span>: <span class="pl-c1">4</span>, <span class="pl-ent">"30_120s"</span>: <span class="pl-c1">1</span>, <span class="pl-ent">"gte_120s"</span>: <span class="pl-c1">0</span> }
}</pre></div>
<p dir="auto"><strong><code>counters</code> and <code>errors</code> are <code>#[derive(Serialize)]</code> structs of named <code>u32</code> fields, not maps.</strong> Every field is serialized including zeros. The key set is closed by the compiler: adding a counter requires editing <code>crates/telemetry/src/event.rs</code>, which is where the doc-match test lives.</p>
<p dir="auto"><strong><code>duration_bucket</code></strong> — <code>chrono</code> delta from <code>app.session_started_at</code> (<code>crates/tui/src/tui/app.rs:1889</code>). Half-open, seconds: <code>lt_1m</code> (<code>d &lt; 60</code>), <code>1m_10m</code> (<code>60 ≤ d &lt; 600</code>), <code>10m_60m</code> (<code>600 ≤ d &lt; 3600</code>), <code>gt_60m</code> (<code>d ≥ 3600</code>).</p>
<p dir="auto"><strong><code>exit_class</code></strong> — <code>clean | signal | panic | error</code>. <strong>Derived from an explicit <code>AtomicU8</code>, never from an exit code.</strong> <code>RunTerminationReason::Canceled</code> maps to exit 130 (<code>crates/tui/src/core/runtime_contract/termination.rs:53</code>), the same value the signal task uses (<code>crates/tui/src/lib.rs:682</code>, 128+SIGINT), so a code-based derivation would report every Esc-cancelled turn as a signal. The atomic is set by the panic hook (<code>crates/tui/src/lib.rs:1582</code>), by the signal task (<code>:678-696</code>) before <code>std::process::exit</code>, and on the clean path from <code>RunTerminationReason::is_success()</code> (<code>crates/tui/src/core/runtime_contract/termination.rs:44-46</code>) — <code>error</code> otherwise. Do <strong>not</strong> use <code>exec_failure_exit_code</code> (<code>crates/tui/src/lib.rs:10432</code>): it knows only <code>{75, 1}</code> and would report an approval-required exit (3) as a generic failure.</p>
<p dir="auto"><strong><code>cold_start_bucket</code></strong> — from <code>startup_trace::elapsed_ms()</code>, which reads <code>PROCESS_START</code> directly and is independent of the startup summary's buffer clear (<code>crates/runtime/src/startup_trace.rs:39-45</code>). Boundaries: <code>lt_250</code>, <code>250_1000</code>, <code>1000_3000</code>, <code>gte_3000</code>. Absent on non-TUI surfaces.</p>
<p dir="auto"><strong><code>providers</code></strong> — sorted, deduplicated array of <code>ProviderKind::as_str()</code> (<code>crates/config/src/provider_kind.rs:295</code>, a <code>&amp;'static str</code> from a closed enum; <code>Custom</code> yields the literal <code>"custom"</code>). <strong>The API takes <code>ProviderKind</code> by value, never <code>&amp;str</code>.</strong> Do not call <code>ProviderKind::parse</code> or <code>parse_config_identity</code> (<code>:300</code>, <code>:330</code>) — those are for config-table resolution. <strong>Do not read</strong> <code>provider_identity_for_persistence()</code> (<code>crates/tui/src/tui/app.rs:5049</code>), <code>provider_id_for_persistence()</code> (<code>:5058</code>), <code>ExecStreamMeta.provider_id</code> (<code>crates/tui/src/lib.rs:10220</code>), or <code>PlannedTurnRoute.effective_provider_label</code> (<code>crates/tui/src/turn_route_plan.rs:189-193</code>) — all four return the customer's own <code>[providers.&lt;name&gt;]</code> table key when the route is Custom. This is the single most likely leak in the feature: it is one field away from the natural seam and <code>/status</code> already prints it (<code>crates/tui/src/commands/groups/config/status.rs:24-28</code>). <strong>No model id is ever sent, for any provider</strong> — <code>crates/runtime/src/safe_label.rs:11-15</code> documents that a model id can be a path, a URL, or a deployment id that is itself a credential.</p>
<p dir="auto"><strong><code>counters</code></strong> — closed field set. Every bump happens at the <strong>call site</strong>, never inside a conditionally-entered handler:</p>
<markdown-accessiblity-table><table>
<thead>
<tr>
<th>field</th>
<th>source anchor</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>turns</code></td>
<td><code>run_event_loop</code> in <code>crates/tui/src/tui/ui/event_loop.rs</code>, immediately before it calls <code>execute_turn_end_observer_hook</code>. Never inside that hook: its first statement is <code>if !app.hooks.has_hooks_for_event(HookEvent::TurnEnd) { return Ok(()); }</code> (<code>crates/tui/src/tui/ui/observer_hooks.rs</code>), and the natural future optimization hoists that check to the call site, silently zeroing the counter for every user without hooks.</td>
</tr>
<tr>
<td><code>tool_calls</code></td>
<td><code>execute_tool_with_lock</code> in <code>crates/tui/src/core/engine/tool_execution.rs</code> — surface-agnostic, fires for exec and CLI too</td>
</tr>
<tr>
<td><code>fleet_dispatch</code></td>
<td><code>create_queued_run_with_descriptor</code> in <code>crates/tui/src/fleet/manager.rs</code> — the single funnel that <code>create_run</code> and <code>create_queued_run</code> both land in; counting at either caller would double-count a plain <code>fleet run</code>.</td>
</tr>
<tr>
<td><code>workflow_run</code></td>
<td>bumped in <code>WorkflowTool::execute</code> (<code>crates/tui/src/tools/workflow/mod.rs</code>) only after <code>parse_workflow_action</code> returns an <code>Ok(WorkflowAction)</code>, never from <code>input["action"]</code>. The JSON Schema <code>enum</code> in <code>WorkflowTool::input_schema</code> is what is published <em>to the model</em> — a declaration, not a guard; the real parse also accepts <code>spawn|wait|list|inspect|stop|abort</code>, and its reject arm (<code>Invalid workflow action '…'</code>) embeds the model string verbatim, so a rejected action is never counted.</td>
</tr>
<tr>
<td><code>subagent_spawn</code></td>
<td><code>apply_agent_spawned_status_and_observer</code> in <code>crates/tui/src/tui/ui/apply.rs</code></td>
</tr>
<tr>
<td><code>mcp_server_connected</code></td>
<td>bumped when a server snapshot's <code>.connected</code> is true, in <code>snapshot_from_config</code> (<code>crates/tui/src/mcp.rs</code>); never <code>name</code>, <code>command_or_url</code>, or <code>error</code> — server names are user-chosen and routinely internal infra</td>
</tr>
<tr>
<td><code>memory_search</code></td>
<td><code>tool_name == "memory_search"</code> (the tool registered in <code>crates/tui/src/tools/native_memory.rs</code>), counted at the same <code>execute_tool_with_lock</code> choke point</td>
</tr>
<tr>
<td><code>approval_modal_shown</code></td>
<td>the <code>Event::ApprovalRequired</code> arm of <code>run_event_loop</code> (<code>crates/tui/src/tui/ui/event_loop.rs</code>; the event is defined in <code>crates/tui/src/core/events.rs</code>)</td>
</tr>
<tr>
<td><code>approval_auto_allowed</code></td>
<td><code>tool_ask_rule_decision_for_context</code> in <code>crates/tui/src/core/engine.rs</code>. Count only. Never <code>matched_rule</code>, <code>reason()</code>, the command, or argv — <code>auto_allow</code> patterns are user-authored command strings (<code>crates/execpolicy/src/command_safety.rs:35/309</code>)</td>
</tr>
<tr>
<td><code>command_palette_open</code></td>
<td>the palette key path in <code>run_event_loop</code> (<code>crates/tui/src/tui/ui/event_loop.rs</code>) and <code>handle_context_menu_action</code> in <code>crates/tui/src/tui/mouse_ui.rs</code></td>
</tr>
</tbody>
</table></markdown-accessiblity-table>
<p dir="auto"><strong><code>errors</code></strong> — closed field set. Every value is a <strong>variant discriminant</strong>, never <code>err.to_string()</code>:</p>
<markdown-accessiblity-table><table>
<thead>
<tr>
<th>field</th>
<th>source anchor</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>auth_preflight_failed</code></td>
<td>discriminant of <code>CredentialReadiness</code> (<code>crates/workflow/src/fleet_preflight.rs:37-58</code>) / <code>ProviderAuthClass</code> (<code>crates/tui/src/provider_readiness.rs:32</code>). Discriminant only — <code>Missing { detail }</code> carries free text</td>
</tr>
<tr>
<td><code>provider_http_4xx</code></td>
<td><code>status.as_u16() / 100 == 4</code>, captured at <code>crates/tui/src/client/chat.rs:595</code> and <code>:673</code> <strong>before</strong> the <code>bail!</code>. One row per field, because the doc-match test reads this table field for field</td>
</tr>
<tr>
<td><code>provider_http_5xx</code></td>
<td><code>status.as_u16() / 100 == 5</code>, same capture points</td>
</tr>
<tr>
<td><code>tool_denied_by_policy</code></td>
<td>the <code>permission_denied</code> arm of the 8-variant match at <code>crates/tui/src/core/engine/tool_execution.rs:512-531</code></td>
</tr>
<tr>
<td><code>tool_timeout</code></td>
<td>the <code>timeout</code> arm, same match</td>
</tr>
<tr>
<td><code>network_error</code></td>
<td><code>retry_reason_label_and_human()</code>'s <code>&amp;'static str</code> half, <code>crates/tui/src/client.rs:2659</code></td>
</tr>
</tbody>
</table></markdown-accessiblity-table>
<p dir="auto">Why discriminants and nothing else: <code>ToolError::PathEscape</code>'s <code>Display</code> <em>is</em> an absolute path (<code>crates/tools/src/lib.rs:61</code>); <code>fim.rs:48-50</code>'s <code>Display</code> <em>is</em> a literal source fragment the model emitted; <code>secrets/src/lib.rs:50</code>'s <code>Display</code> carries the secret store's absolute path; every <code>LlmError</code> variant carries the raw provider HTTP body verbatim (<code>crates/tui/src/llm_client/mod.rs:327</code>), and a 400 from a content filter routinely echoes the prompt.</p>
<p dir="auto"><strong><code>turn_wall</code></strong> — a per-session histogram of counts, never per-turn events. <code>lt_5s</code>, <code>5_30s</code>, <code>30_120s</code>, <code>gte_120s</code>. Recorded by <code>observe_turn_secs</code> next to the <code>turns</code> bump in <code>run_event_loop</code>, which already has the turn duration in hand.</p>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Event: <code>panic</code></h3><a id="user-content-event-panic" class="anchor" aria-label="Permalink: Event: panic" href="#event-panic"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">Appended <strong>synchronously</strong> by the panic hook, because a <code>session_end</code> may never be written.</p>
<div class="highlight highlight-source-json-comments notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="{ &quot;event&quot;: &quot;panic&quot;, &quot;site&quot;: &quot;crates/tui/src/lib.rs:1582:5&quot; }"><pre>{ <span class="pl-ent">"event"</span>: <span class="pl-s"><span class="pl-pds">"</span>panic<span class="pl-pds">"</span></span>, <span class="pl-ent">"site"</span>: <span class="pl-s"><span class="pl-pds">"</span>crates/tui/src/lib.rs:1582:5<span class="pl-pds">"</span></span> }</pre></div>
<p dir="auto"><code>site</code> comes from <code>panic_info.location()</code> (<code>crates/tui/src/lib.rs:1597-1600</code>) or <code>Location::caller()</code> (<code>crates/tui/src/utils.rs:523</code>). <strong>Allowlist reduction, not optional:</strong> emit verbatim only if <code>file()</code> starts with <code>crates/</code>; otherwise emit the literal <code>"&lt;dep&gt;"</code>. Must match <code>^crates/[A-Za-z0-9_/.-]+\.rs:\d+:\d+$</code> or <code>^&lt;dep&gt;$</code>. There is no <code>--remap-path-prefix</code> in this repo (no <code>.cargo/config.toml</code>; <code>Cargo.toml:69-74</code> sets only <code>lto</code>/<code>strip</code>/<code>codegen-units</code>), so a panic inside a registry dependency yields <code>/Users/&lt;builder&gt;/.cargo/registry/src/…/ratatui-0.29.0/src/…</code> — the <strong>build machine's username</strong>, shipped from every user's binary.</p>
<p dir="auto"><strong>The panic message is never sent.</strong> The hook at <code>crates/tui/src/lib.rs:1590-1596</code> builds <code>msg</code> from the payload; telemetry must not read it. A slicing panic embeds the entire string being sliced, and this tree slices user and model text in dozens of places.</p>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Event: <code>product_usage</code></h3><a id="user-content-event-product_usage" class="anchor" aria-label="Permalink: Event: product_usage" href="#event-product_usage"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">One aggregate of explicit product interactions, with every field a saturating
<code>u32</code>, including zero values. No page paths, URLs, referrers, search terms,
account/session IDs, text, or action timestamps are permitted. Clients flush
aggregate counts on page exit or when hidden, rather than each action.</p>
<div class="highlight highlight-source-json-comments notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="{
  &quot;event&quot;: &quot;product_usage&quot;,
  &quot;counters&quot;: {
    &quot;page_view&quot;: 1,
    &quot;docs_view&quot;: 0,
    &quot;install_copy&quot;: 0,
    &quot;download&quot;: 0,
    &quot;signup&quot;: 0,
    &quot;login&quot;: 0,
    &quot;session_create&quot;: 0,
    &quot;session_resume&quot;: 0,
    &quot;turn_submit&quot;: 0,
    &quot;turn_complete&quot;: 0,
    &quot;settings_open&quot;: 0,
    &quot;integration_connect&quot;: 0,
    &quot;error_shown&quot;: 0
  }
}"><pre>{
  <span class="pl-ent">"event"</span>: <span class="pl-s"><span class="pl-pds">"</span>product_usage<span class="pl-pds">"</span></span>,
  <span class="pl-ent">"counters"</span>: {
    <span class="pl-ent">"page_view"</span>: <span class="pl-c1">1</span>,
    <span class="pl-ent">"docs_view"</span>: <span class="pl-c1">0</span>,
    <span class="pl-ent">"install_copy"</span>: <span class="pl-c1">0</span>,
    <span class="pl-ent">"download"</span>: <span class="pl-c1">0</span>,
    <span class="pl-ent">"signup"</span>: <span class="pl-c1">0</span>,
    <span class="pl-ent">"login"</span>: <span class="pl-c1">0</span>,
    <span class="pl-ent">"session_create"</span>: <span class="pl-c1">0</span>,
    <span class="pl-ent">"session_resume"</span>: <span class="pl-c1">0</span>,
    <span class="pl-ent">"turn_submit"</span>: <span class="pl-c1">0</span>,
    <span class="pl-ent">"turn_complete"</span>: <span class="pl-c1">0</span>,
    <span class="pl-ent">"settings_open"</span>: <span class="pl-c1">0</span>,
    <span class="pl-ent">"integration_connect"</span>: <span class="pl-c1">0</span>,
    <span class="pl-ent">"error_shown"</span>: <span class="pl-c1">0</span>
  }
}</pre></div>
<p dir="auto"><code>page_view</code> counts a page view and <code>docs_view</code> a documentation view; <code>install_copy</code>
and <code>download</code> count installation actions. <code>signup</code> and <code>login</code> count successful
authentication actions, never identity. <code>session_create</code>, <code>session_resume</code>,
<code>turn_submit</code>, and <code>turn_complete</code> count their named product actions.
<code>settings_open</code>, <code>integration_connect</code>, and <code>error_shown</code> are counts only:
never the selected setting, integration name, error body, or work content.
An event's availability depends on the emitting client; zero is not proof a
feature was exercised or available.</p>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Event: <code>operations_summary</code></h3><a id="user-content-event-operations_summary" class="anchor" aria-label="Permalink: Event: operations_summary" href="#event-operations_summary"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">Anonymous service health aggregates from the existing control-plane signal ledger.
Exactly these six saturating <code>u32</code> fields are accepted, only on <code>control-plane</code>.
This requires an explicit operator delivery/processor configuration, independently
of the end-user analytics choice. Each batch uses a fresh random v4 <code>install_id</code>;
there is no user/account/session join. No per-request rows, routes, request
digests, IDs, error text, traces, or timing series are permitted. <code>requests</code> and
<code>errors</code> count requests and failures; <code>duration_ms_total</code> and <code>duration_ms_max</code>
are aggregate latency values; <code>probes</code> and <code>probes_failed</code> count health probes.</p>
<div class="highlight highlight-source-json-comments notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="{
  &quot;event&quot;: &quot;operations_summary&quot;,
  &quot;requests&quot;: 10,
  &quot;errors&quot;: 1,
  &quot;duration_ms_total&quot;: 1500,
  &quot;duration_ms_max&quot;: 300,
  &quot;probes&quot;: 2,
  &quot;probes_failed&quot;: 0
}"><pre>{
  <span class="pl-ent">"event"</span>: <span class="pl-s"><span class="pl-pds">"</span>operations_summary<span class="pl-pds">"</span></span>,
  <span class="pl-ent">"requests"</span>: <span class="pl-c1">10</span>,
  <span class="pl-ent">"errors"</span>: <span class="pl-c1">1</span>,
  <span class="pl-ent">"duration_ms_total"</span>: <span class="pl-c1">1500</span>,
  <span class="pl-ent">"duration_ms_max"</span>: <span class="pl-c1">300</span>,
  <span class="pl-ent">"probes"</span>: <span class="pl-c1">2</span>,
  <span class="pl-ent">"probes_failed"</span>: <span class="pl-c1">0</span>
}</pre></div>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">What the endpoint does — a shipping gate, not a footnote</h3><a id="user-content-what-the-endpoint-does--a-shipping-gate-not-a-footnote" class="anchor" aria-label="Permalink: What the endpoint does — a shipping gate, not a footnote" href="#what-the-endpoint-does--a-shipping-gate-not-a-footnote"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">This section was a gate on configuring any non-loopback endpoint. The endpoint is now configured by default, so this is a description of a service that exists rather than a promise about one that might.</p>
<p dir="auto"><strong>What it is.</strong> <code>https://telemetry.codewhale.net/v1/telemetry</code> — a Cloudflare Worker named <code>codewhale-telemetry-ingest</code>, whose complete source is in this repository at <a href="/codewhale-hq/Codewhale/blob/main/telemetry-ingest"><code>telemetry-ingest/</code></a>. It is the single schema and storage authority; browser applications may use a same-origin proxy that forwards only the body. There is no telemetry queue or additional runtime collector. It is write-only: nothing in the Worker can read back what was stored, and querying happens out of band through Cloudflare's SQL API with the owner's token. The hostname is deliberately self-describing, so anyone inspecting their own network traffic can tell what it is from the name alone.</p>
<p dir="auto"><strong>What it stores.</strong> Everything in this document and nothing else, in Workers Analytics Engine — one row per event. The validator in <code>telemetry-ingest/src/schema.ts</code> is a <strong>closed</strong> field set: an unknown key anywhere in a batch rejects the whole batch with <code>400</code>. A future client bug that starts attaching a path, a prompt, or a provider table name gets refused by the server rather than quietly stored. <code>telemetry-ingest/test/schema-doc.test.ts</code> parses the field names and enum spellings back out of <em>this file</em> and asserts set equality against the validator, and <code>telemetry-ingest/test/ingest.test.ts</code> posts the Rust client's own pinned golden batch and asserts it is accepted byte for byte — so this document, the client, and the endpoint cannot drift apart without a red test.</p>
<p dir="auto">Batches are <strong>IP-stripped at ingest</strong>. No IP is stored, logged, or joined to <code>install_id</code> — and that is structural rather than a setting anyone could flip. An Analytics Engine row is exactly <code>_sample_interval</code>, <code>blob1</code>–<code>blob20</code>, <code>dataset</code>, <code>double1</code>–<code>double20</code>, <code>index1</code>, and <code>timestamp</code>. Every one of those columns is written by the Worker's own <code>writeDataPoint</code> call; there is no implicit column, so <strong>there is no IP, country, or geo column</strong> — no slot one could occupy even if the code wanted it there. And the code cannot want it:</p>
<ul dir="auto">
<li>The handler reads exactly <strong>two</strong> request headers — <code>content-type</code> and <code>content-length</code>. Nothing else, ever.</li>
<li>It never touches the request's <code>cf</code> property, so country, colo, city, region, ASN, timezone, and coordinates are never in scope.</li>
<li>The function that builds every stored row cannot see the request at all; its input type is the validated batch body.</li>
<li>Nothing logs. <code>invocation_logs</code> is off in <code>wrangler.jsonc</code> — Cloudflare describes those as "enriched with information available to Cloudflare in the context of the invocation", which is exactly the class of automatic per-request record this service will not keep — and there is no <code>console.*</code> call in the source.</li>
<li>Rate limiting is keyed on <code>install_id</code> from the validated body, never on a network address. An IP-keyed limiter would mean this Worker handles IPs. It is the weaker limiter and it is the right trade.</li>
<li><code>telemetry-ingest/test/no-ip.test.ts</code> reads the shipped source as text and fails the build if any address or geo name appears, if the set of headers read grows past two, if a <code>console.*</code> call is added, or if a <code>Response</code> is ever constructed with a body.</li>
</ul>
<p dir="auto"><strong>Retention: three months.</strong> That is Cloudflare's fixed window for Analytics Engine and it is not configurable, so it is a ceiling rather than a policy — there is no setting that could make it longer.</p>
<p dir="auto"><strong>Optional PostHog processor.</strong> After first-party storage, an explicitly
configured ingest may forward validated schema-v3 / notice-v5 batches and
legacy schema-v2 / consent-v4 batches to
PostHog's <a href="https://posthog.com/docs/api/capture" rel="nofollow">batch capture API</a>. The only
permitted origins are <code>https://us.i.posthog.com</code> and <code>https://eu.i.posthog.com</code>.
Legacy v1 batches cannot reach that path. PostHog receives the same bounded
envelope and event fields, the batch timestamp as its event timestamp, and
<code>codewhale:&lt;install_id&gt;</code> as its anonymous <code>distinct_id</code>. Events are named
<code>codewhale_install_or_upgrade</code>, <code>codewhale_session_start</code>,
<code>codewhale_session_end</code>, <code>codewhale_panic</code>, <code>codewhale_product_usage</code>, or
<code>codewhale_operations_summary</code>.
<code>$process_person_profile = false</code>, <code>$geoip_disable = true</code>, and <code>$ip = null</code>
are fixed transport controls. No request metadata, profile identification,
SDK, autocapture, session replay, advertising, or work content is forwarded.
A fresh server request has no user cookies or authorization headers, cannot
follow redirects, and is limited to 1.5 seconds. There are no retries or logs;
a failure does not change a successful first-party ingest response.</p>
<p dir="auto">The PostHog project's retention and privacy settings are separate deployment
configuration and must be reviewed before activation. The Analytics Engine
three-month limit does not establish a PostHog retention period.</p>
<p dir="auto"><strong>The edge egress path also requires staging proof.</strong> <a href="https://developers.cloudflare.com/fundamentals/reference/http-headers/#cf-connecting-ip-in-worker-subrequests" rel="nofollow">Cloudflare documents</a>
that Worker subrequests to non-Cloudflare zones can receive platform-added
client-IP headers. Fresh JavaScript headers and local fetch tests cannot prove
those headers are removed. <code>POSTHOG_IP_SAFE_EGRESS_VERIFIED="true"</code> is an explicit
operator prerequisite alongside the host and token, and must remain unset
until a receipt for the actual deployment and regional destination confirms
no original client IP in any received header, including <code>CF-Connecting-IP</code>,
<code>X-Forwarded-For</code>, and <code>X-Real-IP</code>. The flag does not strip platform headers.
Requalify a changed egress path; if it cannot pass, keep the sink disabled or
run only its delivery in a detached first-party context. No such live proof
is established by this source change.</p>
<p dir="auto"><strong>Every response is a bare status with an empty body</strong> — <code>204</code> accepted, <code>400</code> schema violation, <code>404</code>/<code>405</code> wrong path or method, <code>413</code> oversized, <code>415</code> wrong content type, <code>429</code> rate-limited, <code>500</code> internal. The endpoint cannot echo back what it received or what it holds, and because the client drops the batch on anything that is not 2xx, a rejection is invisible to you by construction and a server error can never surface as a client-visible failure.</p>
<p dir="auto"><code>install_id</code> rotates client-side every 90 days (<code>rotated_at</code> in <code>install_id.json</code>), so no single identifier spans a long history. This costs longitudinal accuracy and the docs say so: <strong>no count derived from <code>install_id</code> is a user count.</strong> It is a lower bound on distinct machine-installs in a window, and it undercounts a returning user across a rotation.</p>
<p dir="auto"><strong>Turning it off deletes what was kept locally, not what was already sent.</strong> <code>codewhale config set telemetry false</code> erases the install id, the buffer, and the dry-run records on your machine, and stops anything further. Rows already accepted by the endpoint are keyed only by a rotating random id that is now gone; first-party rows age out with the three-month window. If PostHog processing is activated, already-delivered processor records follow that project’s configured retention. The client has no remote deletion API and does not claim that local opt-out erases delivered records.</p>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">What the owner reads back — observed active installs</h3><a id="user-content-what-the-owner-reads-back--observed-active-installs" class="anchor" aria-label="Permalink: What the owner reads back — observed active installs" href="#what-the-owner-reads-back--observed-active-installs"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">The one product metric derived from this data is <strong>observed active installs</strong>: the number of distinct rotating anonymous install ids that produced a <code>session_start</code> event on a UTC day. That is the whole definition. It is not a count of people, not a count of accounts, and not a count of total installs — the id is per installation, rotates every 90 days, and is deleted on opt-out, so no number derived from it can be any of those things.</p>
<p dir="auto">The exact owner command is checked into the repository, so the routine query is reviewable code rather than SQL pasted from a chat:</p>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="cd telemetry-ingest
CF_ACCOUNT_ID=... CF_API_TOKEN=... npm run report:active-installs"><pre><span class="pl-c1">cd</span> telemetry-ingest
CF_ACCOUNT_ID=... CF_API_TOKEN=... npm run report:active-installs</pre></div>
<p dir="auto">It prints the daily series, a 7-day trend over complete UTC days, the freshness of the newest ingested event, and — with the numbers, in both text and <code>--json</code> output — the coverage caveats: clients older than the telemetry feature, opted-out installs, and non-emitting environments (kill switches, fleet workers, offline shutdowns, dropped flushes) are invisible, so every count is a lower bound; and because ids rotate, week-over-week comparisons are not a retention metric. The report's read path is itself tested: the install id appears only inside an aggregate, no payload column is selected, and the wording can never drift into calling the result users. (<code>npm run report:dau</code> remains as a compatibility alias for the same report.)</p>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">What is never collected — the public red-line list</h3><a id="user-content-what-is-never-collected--the-public-red-line-list" class="anchor" aria-label="Permalink: What is never collected — the public red-line list" href="#what-is-never-collected--the-public-red-line-list"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">Prompts; completions; tool arguments; diffs; patches; file contents; filenames; absolute or relative paths; git remotes; repo names; branch names; workspace commit SHAs; memory entries; chat history; API keys, tokens, cookies, or <code>Authorization</code> headers (including any boolean asserting a key exists); model ids of any kind; custom provider table names; MCP server names, commands, or URLs; approval rule text; error message bodies; panic message text; per-event timestamps; keystrokes; clipboard; screenshots; microphone; camera; location; and any third-party ad or analytics SDK — there are none in the runtime binary and none may be added.</p>
<p dir="auto">Two named traps for the implementer. <code>crates/state/src/lib.rs</code> persists <code>git_sha</code>, <code>git_branch</code>, <code>git_origin_url</code>, <code>cwd</code>, and <code>path</code> on the threads table (<code>:93, :399, :653</code>): a payload builder that accepts a <code>Thread</code> or <code>ThreadMeta</code> and derives <code>Serialize</code> breaches the contract in one line. <strong>Never derive <code>Serialize</code> over an existing state type</strong> — build every telemetry struct from scratch with explicit fields. And <code>crates/core/src/lib.rs:1389-1398</code> is the one place in the tree where the word <code>telemetry</code> sits inside a JSON object next to <code>prompt</code>, <code>base_url</code>, and <code>has_api_key</code>. It is the object someone will copy. Do not.</p>
<hr>
</article></div><div class="d-none"></div></section></div></div></div> </div> <!-- --> </div></div></div></div></div></div><div class="ScrollMarksContainer-module__scrollMarksContainer__Eu7uU" id="find-result-marks-container"></div><div class="d-none"></div><div class="d-none"></div></div> <!-- --> <!-- --> </div>
</react-app>




  </div>

</turbo-frame>

    </main>
  </div>

  </div>

          <footer class="footer f6 color-fg-muted color-border-subtle tmp-pt-7 tmp-pb-6 p-responsive" role="contentinfo"  >
  <h2 class='sr-only'>Footer</h2>

  


  <div class="d-flex flex-justify-center flex-items-center flex-column-reverse flex-lg-row flex-wrap flex-lg-nowrap">
    <div class="d-flex flex-items-center flex-shrink-0 mx-2">
      <a aria-label="GitHub Homepage" class="footer-octicon mr-2" href="https://github.com">
        <svg aria-hidden="true" data-component="Octicon" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-mark-github">
    <path d="M10.226 17.284c-2.965-.36-5.054-2.493-5.054-5.256 0-1.123.404-2.336 1.078-3.144-.292-.741-.247-2.314.09-2.965.898-.112 2.111.36 2.83 1.01.853-.269 1.752-.404 2.853-.404 1.1 0 1.999.135 2.807.382.696-.629 1.932-1.1 2.83-.988.315.606.36 2.179.067 2.942.72.854 1.101 2 1.101 3.167 0 2.763-2.089 4.852-5.098 5.234.763.494 1.28 1.572 1.28 2.807v2.336c0 .674.561 1.056 1.235.786 4.066-1.55 7.255-5.615 7.255-10.646C23.5 6.188 18.334 1 11.978 1 5.62 1 .5 6.188.5 12.545c0 4.986 3.167 9.12 7.435 10.669.606.225 1.19-.18 1.19-.786V20.63a2.9 2.9 0 0 1-1.078.224c-1.483 0-2.359-.808-2.987-2.313-.247-.607-.517-.966-1.034-1.033-.27-.023-.359-.135-.359-.27 0-.27.45-.471.898-.471.652 0 1.213.404 1.797 1.235.45.651.921.943 1.483.943.561 0 .92-.202 1.437-.719.382-.381.674-.718.944-.943"></path>
</svg>
</a>
      <span>
        &copy; 2026 GitHub,&nbsp;Inc.
      </span>
    </div>

    <nav aria-label="Footer">
      <h3 class="sr-only" id="sr-footer-heading">Footer navigation</h3>

      <ul class="list-style-none d-flex flex-justify-center flex-wrap mb-2 mb-lg-0" aria-labelledby="sr-footer-heading">


          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to Terms&quot;,&quot;label&quot;:&quot;text:terms&quot;}" href="https://docs.github.com/site-policy/github-terms/github-terms-of-service" data-view-component="true" class="Link--secondary Link">Terms</a>
          </li>

          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to privacy&quot;,&quot;label&quot;:&quot;text:privacy&quot;}" href="https://docs.github.com/site-policy/privacy-policies/github-privacy-statement" data-view-component="true" class="Link--secondary Link">Privacy</a>
          </li>


            <li class="mx-2">
              <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to security&quot;,&quot;label&quot;:&quot;text:security&quot;}" href="https://github.com/security" data-view-component="true" class="Link--secondary Link">Security</a>
            </li>

            <li class="mx-2">
              <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to status&quot;,&quot;label&quot;:&quot;text:status&quot;}" href="https://www.githubstatus.com/" data-view-component="true" class="Link--secondary Link">Status</a>
            </li>

          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to community&quot;,&quot;label&quot;:&quot;text:community&quot;}" href="https://github.community/" data-view-component="true" class="Link--secondary Link">Community</a>
          </li>

          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to docs&quot;,&quot;label&quot;:&quot;text:docs&quot;}" href="https://docs.github.com/" data-view-component="true" class="Link--secondary Link">Docs</a>
          </li>

          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to contact&quot;,&quot;label&quot;:&quot;text:contact&quot;}" href="https://support.github.com?tags=dotcom-footer" data-view-component="true" class="Link--secondary Link">Contact</a>
          </li>

          
<li class="mx-2" >
  <cookie-consent-link>
    <button
      type="button"
      class="Link--secondary underline-on-hover border-0 p-0 color-bg-transparent"
      data-action="click:cookie-consent-link#showConsentManagement"
      data-analytics-event="{&quot;location&quot;:&quot;footer&quot;,&quot;action&quot;:&quot;cookies&quot;,&quot;context&quot;:&quot;subfooter&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;cookies_link_subfooter_footer&quot;}"
    >
      Manage cookies
    </button>
  </cookie-consent-link>
</li>

  <li class="mx-2">
    <cookie-consent-link>
      <button
        type="button"
        class="Link--secondary underline-on-hover border-0 p-0 color-bg-transparent text-left"
        data-action="click:cookie-consent-link#showConsentManagement"
        data-analytics-event="{&quot;location&quot;:&quot;footer&quot;,&quot;action&quot;:&quot;dont_share_info&quot;,&quot;context&quot;:&quot;subfooter&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;dont_share_info_link_subfooter_footer&quot;}"
      >
        Do not share my personal information
      </button>
    </cookie-consent-link>
  </li>

      </ul>
    </nav>
  </div>
</footer>



    <ghcc-consent id="ghcc" class="position-fixed bottom-0 left-0" style="z-index: 999999"
      data-locale="en"
      data-initial-cookie-consent-allowed=""
      data-cookie-consent-required="true"
    ></ghcc-consent>




  <div id="ajax-error-message" class="ajax-error-message flash flash-error" hidden>
    <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert">
    <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path>
</svg>
    <button type="button" class="flash-close js-ajax-error-dismiss" aria-label="Dismiss error">
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x">
    <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path>
</svg>
    </button>
    You can’t perform that action at this time.
  </div>

    <template id="site-details-dialog">
  <details class="details-reset details-overlay details-overlay-dark lh-default color-fg-default hx_rsm" open>
    <summary role="button" aria-label="Close dialog"></summary>
    <details-dialog class="Box Box--overlay d-flex flex-column anim-fade-in fast hx_rsm-dialog hx_rsm-modal">
      <button class="Box-btn-octicon m-0 btn-octicon position-absolute right-0 top-0" type="button" aria-label="Close dialog" data-close-dialog>
        <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x">
    <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path>
</svg>
      </button>
      <div class="octocat-spinner tmp-my-6 js-details-dialog-spinner"></div>
    </details-dialog>
  </details>
</template>

    <div class="Popover js-hovercard-content position-absolute" style="display: none; outline: none;">
  <div class="Popover-message Popover-message--bottom-left Popover-message--large Box color-shadow-large" style="width:360px;">
  </div>
</div>

    <template id="snippet-clipboard-copy-button">
  <div class="zeroclipboard-container position-absolute right-0 top-0">
    <clipboard-copy aria-label="Copy code to clipboard" class="ClipboardButton btn js-clipboard-copy m-2 p-0" data-copy-feedback="Copied!" data-tooltip-direction="w">
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy js-clipboard-copy-icon m-2 tmp-m-2">
    <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path>
</svg>
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check js-clipboard-check-icon color-fg-success d-none m-2 tmp-m-2">
    <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path>
</svg>
    </clipboard-copy>
  </div>
</template>
<template id="snippet-clipboard-copy-button-unpositioned">
  <div class="zeroclipboard-container">
    <clipboard-copy aria-label="Copy code to clipboard" class="ClipboardButton btn btn-invisible js-clipboard-copy m-2 p-0 d-flex flex-justify-center flex-items-center" data-copy-feedback="Copied!" data-tooltip-direction="w">
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy js-clipboard-copy-icon">
    <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path>
</svg>
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check js-clipboard-check-icon color-fg-success d-none">
    <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path>
</svg>
    </clipboard-copy>
  </div>
</template>




    </div>
    <div id="js-global-screen-reader-notice" class="sr-only mt-n1" aria-live="polite" aria-atomic="true" ></div>
    <div id="js-global-screen-reader-notice-assertive" class="sr-only mt-n1" aria-live="assertive" aria-atomic="true"></div>
  </body>
</html>

