



  

<!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"
  data-css-features="site_disable_smooth_scrolling"
  >




  <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-fa5e2e82e6e0ecc0.js","react-dom":"https://github.githubassets.com/assets/react-dom-c7f52540bb6b77ed.js","react-dom/client":"https://github.githubassets.com/assets/react-dom-client-35b308126995de85.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@d5750093facf" data-turbo-track="reload" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-fa5e2e82e6e0ecc0.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-c7f52540bb6b77ed.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-dom-client-35b308126995de85.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-3a3d2c708970e4e8.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/light_high_contrast-9c7b506bdc5ea73f.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/dark-c9dacb4ec19616db.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/dark_high_contrast-5ef38214a3eabc7d.css" /><link data-color-theme="light" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light-3a3d2c708970e4e8.css" /><link data-color-theme="light_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_high_contrast-9c7b506bdc5ea73f.css" /><link data-color-theme="light_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_colorblind-3862d92e8cad06f0.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-554f83c57e146400.css" /><link data-color-theme="light_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_tritanopia-8a8312bd5594c79a.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-26b9d9807a0334fb.css" /><link data-color-theme="dark" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark-c9dacb4ec19616db.css" /><link data-color-theme="dark_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_high_contrast-5ef38214a3eabc7d.css" /><link data-color-theme="dark_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_colorblind-bea0b289618fbfb6.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-fe483dca5ad67edd.css" /><link data-color-theme="dark_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_tritanopia-7d4b8c531c77a24a.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-edfb3968733aaf25.css" /><link data-color-theme="dark_dimmed" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_dimmed-1f24e8126354e7aa.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-bb55737dcb13dc9b.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-02e066689466a8cd.css" />
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-38ae573fa780d76a.css" />
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/global-58d1122073b19732.css" />
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/github-11ab453cdcc1b7c1.css" />
  <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/repository-542ca59b4b92999d.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/code-b25a4886e30e3e5f.css" />

  

  <script type="application/json" id="client-env">{"locale":"en","featureFlags":["actions_enable_background_steps","actions_new_hosted_runner_image_select_sizes_and_versions","actions_runners_react_view","actions_workflows_react_toggle","agent_author_search_expansion","agent_author_search_expansion_ui_pulls","ahp_v1_wire_protocol","alternate_user_config_repo","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_scanning_ai_scan_button_v2","code_view_raf_sticky_lines","code_view_skip_unchanged_wrap_preference","codespaces_prebuild_region_target_update","coding_agent_third_party_model_ui","collab_docs_authorization","copilot_agent_snippy","copilot_api_agentic_issue_marshal_yaml","copilot_automation_continuous_history","copilot_automation_repo_mcp_servers","copilot_automations_pagination","copilot_background_shell_workbench","copilot_base_model_policy_row","copilot_chat_auto_mode_v2","copilot_chat_clear_model_selection_for_default_change","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_managed_settings_validation_file_links","copilot_mc_cli_resume_any_users_task","copilot_mission_control_agent_merge_feedback","copilot_mission_control_agent_merge_fix_ci","copilot_mission_control_agent_merge_resolve_conflicts","copilot_mission_control_agents_repository_task_detail","copilot_mission_control_agents_task_detail","copilot_mission_control_ahp_diff","copilot_mission_control_ahp_diff_workbench","copilot_mission_control_ahp_local_images","copilot_mission_control_awps_batching","copilot_mission_control_create_pull_request_client_tool","copilot_mission_control_early_stop","copilot_mission_control_environment_task_destination_startup","copilot_mission_control_environments_web_kickoff","copilot_mission_control_independent_mode_controls","copilot_mission_control_needs_attention","copilot_mission_control_pinned_tasks","copilot_mission_control_reasoning_effort","copilot_mission_control_reserved_sandbox_tasks","copilot_mission_control_reuse_project_workspace","copilot_mission_control_session_client_attribution","copilot_mission_control_session_metadata","copilot_mission_control_setup_steps_timing","copilot_mission_control_sticky_header","copilot_mission_control_task_alive_updates","copilot_mission_control_task_sharing","copilot_mission_control_use_api_gateway","copilot_org_policy_page_focus_mode","copilot_policy_ui_refresh","copilot_pr_chat_thread_persistence","copilot_quick_chat_default_chat_scope","copilot_quick_chat_project_sessions","copilot_quick_chat_recent_artifact_sessions","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_code_scanning_alert_trigger","copilot_swe_agent_dependabot_alert_trigger","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_closed_trigger","copilot_swe_agent_issue_comment_trigger","copilot_swe_agent_issue_labeled_trigger","copilot_swe_agent_issue_reopened_trigger","copilot_swe_agent_pr_comment_model_picker","copilot_swe_agent_pull_request_assigned_trigger","copilot_swe_agent_pull_request_closed_trigger","copilot_swe_agent_pull_request_comment_trigger","copilot_swe_agent_pull_request_converted_to_draft_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_reopened_trigger","copilot_swe_agent_pull_request_review_dismissed_trigger","copilot_swe_agent_pull_request_review_requested_trigger","copilot_swe_agent_pull_request_review_submitted_trigger","copilot_swe_agent_pull_request_review_thread_resolved_trigger","copilot_swe_agent_pull_request_review_thread_unresolved_trigger","copilot_swe_agent_pull_request_synchronize_trigger","copilot_swe_agent_secret_scanning_alert_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_workbench_sunset_redirect","dashboard_agents_module_auth_token_check","fgpat_permissions_selector_redesign","glc_code_quality_repo_settings_workflow_config","global_issues_filtered_list_layout","global_nav_user_menu_fetch_on_intent","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","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","marketplace_sidebar_layout","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","one_copilot_chat_owner_split_picker","one_copilot_chat_queue_submit_while_reconnecting","one_copilot_grouped_tool_calls","one_copilot_simplified_environment_picker","primer_react_css_anchor_positioning","primer_react_merged_forwarded_refs","primer_react_timeline_list_semantics","prs_contextual_comment_controls","prs_copilot_app_open_action","prs_css_anchor_positioning","prs_interweave_commits_into_comments","prs_url_search_param_panels","pull_request_copilot_attribution_header","pull_request_file_tree_prefetch_on_hover_50ms","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","pull_requests_deferred_highlight_fallback","pull_requests_persistent_whitespace_preferences","react_blob_isolate_code_lines","react_blob_ssr_content_visibility","react_data_router_nonblocking_revalidation","react_data_router_tanstack_allowed","react_query_props_with_key","react_sandbox_future_tanstack","repo_app_turbo","repo_deployments_sidebar_layout","repo_issues_sidebar_layout","repo_pulls_dashboard_merge_queue_link","repos_contributors_limited_default_range","review_involves_filter","rulesets_actor_list_editor","sample_network_conn_type","secret_scanning_public_monitoring_hide_validity_coming_soon","security_center_artifact_filters_popover","see_who_reacted","selector_observer_skip_detached_adds","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_landing_pages_stable_canvas_position","speculation_rules_ui_service","suggest_custom_property_values_copilot","suppress_automated_browser_vitals","swp_forms_disable_octocaptcha","thread_resolution_reason","trusted_types_policies","turbo_link_eligibility_optimization","ui_service_code_view_budget_banner_eligibility","ui_service_code_view_overview_data","universe26_banners_virt","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-141c17800ca6ba23.js"></script>
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/wp-runtime-e6eb71b50aa3db90.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/app-foundation-799625033ee8341e.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/app-runtime-24d1e3019d231636.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/fetch-utilities-27ed50f7568a5f72.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ser-2defe2918d9c9884.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/environment-e1773fc4c5a5ee0b.js" defer="defer"></script>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/app-runtime.47c2032941ed0c3c.module.css" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/catalyst-5bc36fa5a846f5a0.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/selector-observer-7ae05416e4a383ae.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/relative-time-element-a7b7e0f1360ca8f9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/by4-04f0d28829dc4df0.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ja9-b94de714266ba389.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/3h2-5f8899065b81d778.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/t2-19741658de225445.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/z8j-d8f6fa7339115370.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/hjg-55b6d77c48226433.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/wc-9718c61e184d7417.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/github-elements-b97ce6d485234500.js" defer="defer"></script>
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/element-registry-bbca0eaed1ea1095.js" defer="defer"></script>
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/runtime-helpers-26f2970b9e869a17.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/aria-live-e0f60f15396869e3.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/hotkey-a82e6cb07443fd1c.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-core-64258d9ba65c8c5a.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/cc-99eedace671eb2b6.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/urv-453c749eec9d7d37.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/4t-f1181f796eb9ea15.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/pb0-3a1794e99794195c.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/6n-e6e586acca87c769.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/z-b2cf9f86cb4bed3b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/9k-9938b9e1b5d2f0d0.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/0r-4a2b771052825f69.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ow-98d10140e8228c74.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/mv-2c0d46e691479ec1.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/eou-b91079b9ea7074de.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/eon-36af335a1906af16.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/yga-dd50cf95593467fe.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/behaviors-8cb4c4cc377e2d47.js" defer="defer"></script>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/react-core.c2407ba3ce2b1978.module.css" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/code-menu-ed07bff73ca578de.js" defer="defer"></script>
  
  <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/primer-react-911369ee234690ef.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/nc-28ebfc8e58bca42f.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/qmp-308230626a2aedb0.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/to-b501df3e06c1799a.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/t7l-423469c05c948a8b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/4u-bf6e08201764cb0a.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/s07-527b0afa5c76403e.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/fe-f8365f29462c346a.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/zd-61606dd1c14634aa.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/7v5-d77d961bce5db1f3.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/15-627ae2a5640b1bab.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/5w-452c3a937483ff49.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/la-27ea91f01fa7ffcf.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/y0-02339f2a1b7b69ad.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/t9-28dc4f6af25a5400.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/20-c4fa69654eec9c7a.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/a68-c67bfbb035a5cd79.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/3s-ebbc335534e40b2a.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/cnq-00f06287d057a2b3.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/gw-4bf343b417f9ec19.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/0-8683d136d595e7ee.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/jn-9c45b198d99a47c8.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/q6j-256bc816dd682a0f.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/fn-a24b6dda102e437d.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/i2-5e26ac37ee961d06.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/b2-35e229a50d0f3d05.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/pg-10c94bf4f9e9df2f.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/lrk-ea49e115e48ba34b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/mlz-fce49bd96df2c99f.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/dx-72390bda3ecf1bb9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/sm-22346830d5e5a763.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ur-4cd875e44a87e9f6.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/pr-7e5e6964ac1c13a7.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/up-2550cb0824072126.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/gd-c0d7e6321e1379df.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/51-b582a312086b7975.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/c28-f2c3e9d4cd1ed8f5.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ti-dc598d1734870bb6.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/stw-61e8fd83c623657f.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/w77-0527a66a073ed15c.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/6g-b16e60ccff69b263.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/code-view-78021c04b029066e.js" defer="defer"></script>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.dc074e1b2708fdd8.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/w77.25ab7aedc8e0cfc5.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/code-view.755dfb5b519b5384.module.css" />


  <title>cosmos-framework/docs/posttrain/guides/sft.md at main · NVIDIA/cosmos-framework · 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:1f2f7d39-e0ff-2774-2280-d165edb6a7a5">

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


  <meta name="request-id" content="ECDE:210849:E082F9:127EE76:6ADC7DCC" data-pjax-transient="true"/><meta name="html-safe-nonce" content="9f5475b6762e1e74906235cb2c59a7330591bfe9ccb6656486623762bf2812f1" data-pjax-transient="true"/><meta name="visitor-payload" content="eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFQ0RFOjIxMDg0OTpFMDgyRjk6MTI3RUU3Njo2QURDN0RDQyIsInZpc2l0b3JfaWQiOiIyMTMzMjM0NTUwMzI3NTA4NDI4IiwicmVnaW9uX2VkZ2UiOiJmcmEiLCJyZWdpb25fcmVuZGVyIjoiZnJhIn0=" data-pjax-transient="true"/><meta name="visitor-hmac" content="82078fe2682ed4770e45cdd5c1f4ae09c99ed8991ebfca52a958cbfd0d0618fc" data-pjax-transient="true"/>


    <meta name="hovercard-subject-tag" content="repository:1243757086" 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="Our inference and training framework to run on the Cosmos Models - cosmos-framework/docs/posttrain/guides/sft.md at main · NVIDIA/cosmos-framework">

      <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/NVIDIA/cosmos-framework/blob/main/docs/posttrain/guides/sft.md" />

      <meta name="twitter:image" content="https://opengraph.githubassets.com/9547ea03c4af019144f8812755058364e87bcb00a0ee662f7cf1e37220957a9c/NVIDIA/cosmos-framework" /><meta name="twitter:site" content="@github" /><meta name="twitter:card" content="summary_large_image" /><meta name="twitter:title" content="cosmos-framework/docs/posttrain/guides/sft.md at main · NVIDIA/cosmos-framework" /><meta name="twitter:description" content="Our inference and training framework to run on the Cosmos Models - NVIDIA/cosmos-framework" />
  <meta property="og:image" content="https://opengraph.githubassets.com/9547ea03c4af019144f8812755058364e87bcb00a0ee662f7cf1e37220957a9c/NVIDIA/cosmos-framework" /><meta property="og:image:alt" content="Our inference and training framework to run on the Cosmos Models - NVIDIA/cosmos-framework" /><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="cosmos-framework/docs/posttrain/guides/sft.md at main · NVIDIA/cosmos-framework" /><meta property="og:url" content="https://github.com/NVIDIA/cosmos-framework/blob/main/docs/posttrain/guides/sft.md" /><meta property="og:description" content="Our inference and training framework to run on the Cosmos Models - NVIDIA/cosmos-framework" />
  




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



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


  <meta http-equiv="x-pjax-version" content="7d8fa16435ae04e27a39b696328733f82328ca887e877161d9ee8e0b55c5822a" data-turbo-track="reload">
  <meta http-equiv="x-pjax-csp-version" content="c1fb7e623a3445adf13b126b9a4e9c6c959567f2c234374a2df7062de1125e44" data-turbo-track="reload">
  <meta http-equiv="x-pjax-css-version" content="177e033949cafbe72bb749a4e9400308b68c9b6958fc23a6a7edc4a75e510853" data-turbo-track="reload">
  <meta http-equiv="x-pjax-js-version" content="d5da699858f6078b32f87897c570da974cb9e3d0aa20393dd0432bb067742ea4" 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/NVIDIA/cosmos-framework git https://github.com/NVIDIA/cosmos-framework.git">

  <meta name="octolytics-dimension-user_id" content="1728152" /><meta name="octolytics-dimension-user_login" content="NVIDIA" /><meta name="octolytics-dimension-repository_id" content="1243757086" /><meta name="octolytics-dimension-repository_nwo" content="NVIDIA/cosmos-framework" /><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="1243757086" /><meta name="octolytics-dimension-repository_network_root_nwo" content="NVIDIA/cosmos-framework" />
  



    

    <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="5e1a76138af4c72fbadd723b0d36db8c66cd7319" data-turbo-track="reload">
  <meta name="ui-target" content="canary-2">

  <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/keyboard-shortcuts-dialog-240a3b08c2b74f23.js" fetchpriority="low" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.dc074e1b2708fdd8.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/keyboard-shortcuts-dialog.a7e873c5d56fafca.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/g6m-c6c2e85d4cbe6e0f.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/app-install-banner-partial-8e1eb389e6a9a11c.js" fetchpriority="low" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.dc074e1b2708fdd8.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/app-install-banner-partial.39d1c8868e2681fb.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/h3j-5f947742bed6a5d9.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/qz-bc8ee8395fbadf86.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/fz-cb55e83c29d0a351.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/skl-90fea02d318d647f.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/h4-5f55e06e297293d6.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/z7-54a4e2eade1aa26b.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/a6j-32ec4660665b36c1.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/marketing-header-39db730d4411ab84.js" fetchpriority="low" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.dc074e1b2708fdd8.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-brand-css.605c0b537201e723.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/a6j.40fbb8aed1553149.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%2FNVIDIA%2Fcosmos-framework%2Fblob%2Fmain%2Fdocs%2Fposttrain%2Fguides%2Fsft.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=NVIDIA%2Fcosmos-framework","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/NVIDIA/cosmos-framework/blob/main/docs/posttrain/guides/sft.md\",\"user_id\":null}}","auth_hydro_click_hmac":"684a964b59cccfda611d1500e240346b5478283bfbe7ebc18db8af297cecff60","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="root__q6pgdo 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="visuallyHidden__TIbnmb">Navigation Menu</h2><button type="button" class="backdrop__rMNFxs" aria-label="Close navigation menu"></button><div class="bar__cF4m1O"><div class="topRow__-dqkhM"><div class="toggleSlot__-ODxSX"><button type="button" class="toggle__kPg75-" aria-label="Toggle navigation" aria-expanded="false"><span class="toggleBar__8J10Uq"></span><span class="toggleBar__8J10Uq"></span><span class="toggleBar__8J10Uq"></span></button></div><a href="/" aria-label="Homepage" class="logo__bX9RKh" 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="mobileActions__8F9jkX"><a class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw cta__xkenoh" href="/login?return_to=https%3A%2F%2Fgithub.com%2FNVIDIA%2Fcosmos-framework%2Fblob%2Fmain%2Fdocs%2Fposttrain%2Fguides%2Fsft.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/NVIDIA/cosmos-framework/blob/main/docs/posttrain/guides/sft.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="684a964b59cccfda611d1500e240346b5478283bfbe7ebc18db8af297cecff60"><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 trigger__VWDtQ2" 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></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="menu__2EHTkB"><div class="menuWrapper__Vmk5KX"><nav class="nav__mHQXuz" aria-label="Global"><ul class="list__2Gh7vS"><li><div class="container__KHyzq4"><button type="button" class="button__qiVZaY" aria-expanded="false" aria-controls="_R_nd_">Platform<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right buttonIcon__44FXu9" 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="dropdown__jv_u56"><div><ul class="list__F2oFju"><li><div class="group__i-sw4v"><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_ title__g2f4Ur" id="_R_5knd_">AI CODE CREATION</span><ul class="list__GYi3Jn" aria-labelledby="_R_5knd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 link__3viuP9" 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_ title__MTYMi3"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copilot icon__Sf_Nku" 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 subtitle__gxA0qn">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 link__3viuP9" 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_ title__MTYMi3"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-mark-github icon__Sf_Nku" 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 subtitle__gxA0qn">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 link__3viuP9" 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_ title__MTYMi3"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-mcp icon__Sf_Nku" 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 subtitle__gxA0qn">Integrate external tools</span></span></a></li></ul></div></li><li><div class="group__i-sw4v"><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_ title__g2f4Ur" id="_R_9knd_">DEVELOPER WORKFLOWS</span><ul class="list__GYi3Jn" aria-labelledby="_R_9knd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 link__3viuP9" 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_ title__MTYMi3"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-workflow icon__Sf_Nku" 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 subtitle__gxA0qn">Automate any workflow</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 link__3viuP9" 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_ title__MTYMi3"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-codespaces icon__Sf_Nku" 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 subtitle__gxA0qn">Instant dev environments</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 link__3viuP9" 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_ title__MTYMi3"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-issue-opened icon__Sf_Nku" 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 subtitle__gxA0qn">Plan and track work</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 link__3viuP9" 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_ title__MTYMi3"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-code icon__Sf_Nku" 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 subtitle__gxA0qn">Manage code changes</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 link__3viuP9" 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_ title__MTYMi3"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-codescan-checkmark icon__Sf_Nku" 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 subtitle__gxA0qn">Enforce quality at merge</span></span></a></li></ul></div></li><li><div class="group__i-sw4v"><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_ title__g2f4Ur" id="_R_dknd_">APPLICATION SECURITY</span><ul class="list__GYi3Jn" aria-labelledby="_R_dknd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 link__3viuP9" 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_ title__MTYMi3"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-shield-check icon__Sf_Nku" 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 subtitle__gxA0qn">Find and fix vulnerabilities</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 link__3viuP9" 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_ title__MTYMi3"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-code-square icon__Sf_Nku" 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 subtitle__gxA0qn">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 link__3viuP9" 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_ title__MTYMi3"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-lock icon__Sf_Nku" 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 subtitle__gxA0qn">Stop leaks before they start</span></span></a></li></ul></div></li><li><div class="group__i-sw4v hasSeparator__DZ8QkP"><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_ title__g2f4Ur" id="_R_hknd_">EXPLORE</span><ul class="list__GYi3Jn" 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="trailingLinkContainer__bY9qr5"><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></div></li><li><div class="container__KHyzq4"><button type="button" class="button__qiVZaY" aria-expanded="false" aria-controls="_R_17d_">Solutions<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right buttonIcon__44FXu9" 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="dropdown__jv_u56"><div><ul class="list__F2oFju"><li><div class="group__i-sw4v"><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_ title__g2f4Ur" id="_R_5l7d_">BY COMPANY SIZE</span><ul class="list__GYi3Jn" 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="group__i-sw4v"><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_ title__g2f4Ur" id="_R_9l7d_">BY USE CASE</span><ul class="list__GYi3Jn" 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="group__i-sw4v"><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_ title__g2f4Ur" id="_R_dl7d_">BY INDUSTRY</span><ul class="list__GYi3Jn" 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;see_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;see_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">See 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="trailingLinkContainer__bY9qr5"><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></div></li><li><div class="container__KHyzq4"><button type="button" class="button__qiVZaY" aria-expanded="false" aria-controls="_R_1nd_">Resources<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right buttonIcon__44FXu9" 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="dropdown__jv_u56"><div><ul class="list__F2oFju"><li><div class="group__i-sw4v"><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_ title__g2f4Ur" id="_R_5lnd_">EXPLORE BY TOPIC</span><ul class="list__GYi3Jn" 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="group__i-sw4v"><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_ title__g2f4Ur" id="_R_9lnd_">EXPLORE BY TYPE</span><ul class="list__GYi3Jn" 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="group__i-sw4v"><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_ title__g2f4Ur" id="_R_dlnd_">SUPPORT &amp; SERVICES</span><ul class="list__GYi3Jn" 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="trailingLinkContainer__bY9qr5"><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></div></li><li><div class="container__KHyzq4"><button type="button" class="button__qiVZaY" aria-expanded="false" aria-controls="_R_27d_">Open Source<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right buttonIcon__44FXu9" 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="dropdown__jv_u56"><div><ul class="list__F2oFju"><li><div class="group__i-sw4v"><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_ title__g2f4Ur" id="_R_5m7d_">COMMUNITY</span><ul class="list__GYi3Jn" aria-labelledby="_R_5m7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 link__3viuP9" 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_ title__MTYMi3"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-sponsor-tiers icon__Sf_Nku" 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 subtitle__gxA0qn">Fund open source developers</span></span></a></li></ul></div></li><li><div class="group__i-sw4v"><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_ title__g2f4Ur" id="_R_9m7d_">PROGRAMS</span><ul class="list__GYi3Jn" 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="group__i-sw4v"><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_ title__g2f4Ur" id="_R_dm7d_">REPOSITORIES</span><ul class="list__GYi3Jn" 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></div></li><li><div class="container__KHyzq4"><button type="button" class="button__qiVZaY" aria-expanded="false" aria-controls="_R_2nd_">Enterprise<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right buttonIcon__44FXu9" 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="dropdown__jv_u56"><div><ul class="list__F2oFju"><li><div class="group__i-sw4v"><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_ title__g2f4Ur" id="_R_5mnd_">ENTERPRISE SOLUTIONS</span><ul class="list__GYi3Jn" aria-labelledby="_R_5mnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 link__3viuP9" 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_ title__MTYMi3"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-stack icon__Sf_Nku" 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 subtitle__gxA0qn">AI-powered developer platform</span></span></a></li></ul></div></li><li><div class="group__i-sw4v"><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_ title__g2f4Ur" id="_R_9mnd_">AVAILABLE ADD-ONS</span><ul class="list__GYi3Jn" aria-labelledby="_R_9mnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 link__3viuP9" 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_ title__MTYMi3"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-shield-check icon__Sf_Nku" 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 subtitle__gxA0qn">Enterprise-grade security features</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 link__3viuP9" 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_ title__MTYMi3"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copilot icon__Sf_Nku" 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 subtitle__gxA0qn">Enterprise-grade AI features</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 link__3viuP9" 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_ title__MTYMi3"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-comment-discussion icon__Sf_Nku" 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 subtitle__gxA0qn">Enterprise-grade 24/7 support</span></span></a></li></ul></div></li></ul></div></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="navLink__HiENMw">Pricing</a></li></ul></nav><div class="ctaContainer__XiXTge"><div class="searchSlot__PLyIP2"><button class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw trigger__A07fH5" 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="content__-QV4lC"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-search icon__dKfd-T" 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="label__Axw9pp">Search</span><kbd class="kbd__-xAXYz" aria-hidden="true">/</kbd></span></span></span></button><div class="d-none"></div></div><div class="AuthActions__J52IGi"><div class="signInWrap___-hg2x"><a class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw cta__xkenoh desktopActionGap__qkQEsb hiddenBelowLg__f0ML96" href="/login?return_to=https%3A%2F%2Fgithub.com%2FNVIDIA%2Fcosmos-framework%2Fblob%2Fmain%2Fdocs%2Fposttrain%2Fguides%2Fsft.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/NVIDIA/cosmos-framework/blob/main/docs/posttrain/guides/sft.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="684a964b59cccfda611d1500e240346b5478283bfbe7ebc18db8af297cecff60"><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 cta__xkenoh" 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=NVIDIA%2Fcosmos-framework" 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/NVIDIA/cosmos-framework/blob/main/docs/posttrain/guides/sft.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="684a964b59cccfda611d1500e240346b5478283bfbe7ebc18db8af297cecff60"><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 trigger__VWDtQ2" 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></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><div class="bottomBorder__38-D2c" 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-e936f519-66a0-487f-83f2-0294451ec620" aria-labelledby="tooltip-1b7853da-a9e1-4923-adf9-6bbf0165a12e" 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-1b7853da-a9e1-4923-adf9-6bbf0165a12e" for="icon-button-e936f519-66a0-487f-83f2-0294451ec620" 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/cn-7a4f85e8a901f4f7.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/0b-a7be65069037ffea.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/t5-2c5d26edae56bda2.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/5l-60d6b21dcbe3c5b7.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/1a-76a60fd58c2fa34b.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/rk7-418a4f74edbc9f0d.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/zxp-3431056caddba9d0.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/9ty-47c453f28886426e.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/r3j-2177885dae8b60eb.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/1t-bdeb715d0c007303.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/3j-c46f566649f3b4dc.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/aj-7444763a0a51ca63.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/sgn-de0af0b55144d4f4.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/li6-9946ed6b82f92046.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/jvc-172b2b204ed5e8d3.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/global-nav-bar-ebf6a261f08dc70b.js" fetchpriority="low" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.dc074e1b2708fdd8.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/global-nav-bar.3a0179cc872fc3d8.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":"NVIDIA","is_root":false,"href":"/NVIDIA"},{"crumb_type":"repository","label":"cosmos-framework","is_root":false,"href":"/NVIDIA/cosmos-framework"}],"localNavigation":[{"id":"code","icon":"code","label":"Code","href":"/NVIDIA/cosmos-framework","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":"/NVIDIA/cosmos-framework/issues","selectedLinks":["repo_issues","repo_labels","repo_milestones"],"count":15,"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":"/NVIDIA/cosmos-framework/pulls","selectedLinks":["repo_pulls","checks"],"count":23,"popoverTarget":false,"commandId":"repositories:go-to-pull-requests","reactNav":{"appTarget":null,"anchor":null},"turboNav":{"frame":"repo-content-turbo-frame"}},{"id":"actions","icon":"play","label":"Actions","href":"/NVIDIA/cosmos-framework/actions","selectedLinks":["repo_actions"],"popoverTarget":false,"commandId":"repositories:go-to-actions","reactNav":{"appTarget":"repo","anchor":null},"turboNav":{"frame":"repo-content-turbo-frame"}},{"id":"projects","icon":"table","label":"Projects","href":"/NVIDIA/cosmos-framework/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":"/NVIDIA/cosmos-framework/security","selectedLinks":["security","overview","alerts","policy","token_scanning","code_scanning"],"count":0,"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":"/NVIDIA/cosmos-framework/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:NVIDIA/cosmos-framework","current_repo_name":"cosmos-framework","current_repo_nwo":"NVIDIA/cosmos-framework","current_repo_org":"NVIDIA","user_id":"NVIDIA"}},"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=8","contextRegionUrl":"/_global-navigation/context-region.json"}}</script>
  <div data-target="react-partial.reactRoot"><header aria-label="Global navigation menu" data-component="Stack" class="GlobalNav appHeader__6OmbvL 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="center__f1ujjY withLocalNavigation__FzpnU6 loggedOut__--dPuC prc-Stack-Stack-UQ9k6" data-gap="condensed" data-direction="horizontal" data-align="stretch" data-wrap="nowrap" data-justify="start" data-padding="normal"><nav class="contextRegion__Wb1-GR 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="contextCrumb__Q8nET8 prc-Breadcrumbs-Item-jcraJ" data-component="Breadcrumbs.Item" href="/NVIDIA" data-discover="true"><span class="">NVIDIA</span></a></li><li class="prc-Breadcrumbs-ItemWrapper-k0NLn"><a class="contextCrumb__Q8nET8 prc-Breadcrumbs-Item-jcraJ" data-component="Breadcrumbs.Item" href="/NVIDIA/cosmos-framework" data-discover="true"><span class="contextCrumbLast__l2P28s">cosmos-framework</span></a></li></ol></nav></div><div data-testid="top-nav-right" data-component="Stack" class="right__5m36ST withLocalNavigation__FzpnU6 rightWithResponsiveCreateButton__JePGAt 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__QHRW7C" 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="/NVIDIA/cosmos-framework" 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="/NVIDIA/cosmos-framework/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">15</span><span class="prc-VisuallyHidden-VisuallyHidden-Q0qSB"> (<!-- -->15<!-- -->)</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="/NVIDIA/cosmos-framework/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">23</span><span class="prc-VisuallyHidden-VisuallyHidden-Q0qSB"> (<!-- -->23<!-- -->)</span></span></a></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a data-tab-item="actions" data-react-nav="repo" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/NVIDIA/cosmos-framework/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="/NVIDIA/cosmos-framework/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="/NVIDIA/cosmos-framework/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></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="/NVIDIA/cosmos-framework/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="/NVIDIA/cosmos-framework/blob/main/docs/posttrain/guides/sft.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":"SFT","anchor":"sft","htmlText":"SFT"},{"level":2,"text":"1. When to choose it","anchor":"1-when-to-choose-it","htmlText":"1. When to choose it"},{"level":2,"text":"2. Quick start","anchor":"2-quick-start","htmlText":"2. Quick start"},{"level":2,"text":"3. Data contract","anchor":"3-data-contract","htmlText":"3. Data contract"},{"level":2,"text":"4. Objective and masking","anchor":"4-objective-and-masking","htmlText":"4. Objective and masking"},{"level":2,"text":"5. Main knobs","anchor":"5-main-knobs","htmlText":"5. Main knobs"},{"level":2,"text":"6. Metrics and validation","anchor":"6-metrics-and-validation","htmlText":"6. Metrics and validation"},{"level":2,"text":"7. Checkpoints, resume and export","anchor":"7-checkpoints-resume-and-export","htmlText":"7. Checkpoints, resume and export"},{"level":2,"text":"8. Extension points","anchor":"8-extension-points","htmlText":"8. Extension points"}]},"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\"\u003eSFT\u003c/h1\u003e\u003ca id=\"user-content-sft\" class=\"anchor\" aria-label=\"Permalink: SFT\" href=\"#sft\"\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=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e1. When to choose it\u003c/h2\u003e\u003ca id=\"user-content-1-when-to-choose-it\" class=\"anchor\" aria-label=\"Permalink: 1. When to choose it\" href=\"#1-when-to-choose-it\"\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\"\u003eFull-parameter supervised fine-tuning of Qwen conversations through the existing \u003ccode\u003eLLMTrainer\u003c/code\u003e.\nThe \u003ca href=\"/NVIDIA/cosmos-framework/blob/main/cosmos_framework/posttrain/configs/sft_qwen3p8_27b_multimodal.py\"\u003emultimodal recipe\u003c/a\u003e targets \u003ccode\u003eQwen/Qwen3.8-27B\u003c/code\u003e\n(the dense \u003ccode\u003eqwen3_5\u003c/code\u003e architecture), with text, images, videos and multiple assistant turns.\nLocal/torchrun FSDP is supported; Ray execution, LoRA, sequence packing and MTP training are not.\nThere is no rollout engine, reference model or reward function.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eSFT opts into Transformers 5.8.1; existing RL/GR00T defaults stay on 4.57.6. The SFT builder\nsupports Qwen text models, dense Qwen3.5/3.8 multimodal models and the Qwen3-VL / Qwen3-VL-MoE\nfamilies (all three ship \u003ccode\u003eQwen3VLProcessor\u003c/code\u003e). A \"seat\" is the model construction path the SFT\nobjective sits on. Qwen3.5/3.8 sits on the HF backend (\u003ccode\u003emodel_backend='hf'\u003c/code\u003e,\n\u003ccode\u003emodel/hf.py::HFModel\u003c/code\u003e). Qwen3-VL and Qwen3-VL-MoE sit on the i4-native policy builder\n(\u003ccode\u003emodel_backend='i4'\u003c/code\u003e with \u003ccode\u003econfig.model = NativePolicyBuildSpec(builder=model/qwen3_vl.py:: build_qwen3_vl_native_policy, ...)\u003c/code\u003e, see \u003ca href=\"/NVIDIA/cosmos-framework/blob/main/cosmos_framework/posttrain/configs/sft_qwen3_vl_moe_native.py\"\u003ethe native recipe\u003c/a\u003e):\nthe HF backend refuses MoE VLMs because the general weight loader has no fused-expert handling and\nTransformers 5 stores the MoE expert tensors transposed relative to a Transformers 4 checkpoint.\nOn the native seat the parameters are stored in bfloat16 (the MoE expert kernel requires it), so the\nrecipe uses \u003ccode\u003eattn_impl='sdpa'\u003c/code\u003e and \u003ccode\u003eOptimizerConfig(name='fusedadam')\u003c/code\u003e (apex fp32 master weights and\nmoments inside the optimizer); \u003ccode\u003evalidate_config\u003c/code\u003e refuses \u003ccode\u003eadamw\u003c/code\u003e there because its bfloat16 moments\nround most updates to zero. The seat's masking contract is pinned against the official Qwen3-VL\nprocessor template in \u003ccode\u003etests/test_data_packer_sft.py\u003c/code\u003e (the collated \u003ccode\u003eattention_mask\u003c/code\u003e is \u003ccode\u003etorch.int64\u003c/code\u003e\n0/1, the contract \u003ccode\u003emain\u003c/code\u003e pins in \u003ccode\u003etest_model_qwen3_vl.py\u003c/code\u003e; the native eager mask casts it to bool); its\nGPU training path reuses the online adapters.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e2. Quick start\u003c/h2\u003e\u003ca id=\"user-content-2-quick-start\" class=\"anchor\" aria-label=\"Permalink: 2. Quick start\" href=\"#2-quick-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\u003cp dir=\"auto\"\u003eStart the container and install uv 0.11.29 as in\n\u003ca href=\"/NVIDIA/cosmos-framework/blob/main/docs/posttrain/howto/run-posttrain.md#1-start-the-container\"\u003esections 1 and 2 of the run guide\u003c/a\u003e, then run\nfrom the repository root. SFT uses its own venv with the \u003ccode\u003esft\u003c/code\u003e group\n(\u003ca href=\"/NVIDIA/cosmos-framework/blob/main/docker/posttrain/environment/pyproject.toml\"\u003elocked environment project\u003c/a\u003e):\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"# `python3 -m uv` runs the pip-installed uv 0.11.29: a bare `uv` can resolve to an older release\n# that ships with the container, which the environment project refuses.\n# cu130-runtime matches the run guide's CUDA 13.0 image; use cu128-runtime on a CUDA 12.8 stack.\nUV_PROJECT_ENVIRONMENT=\u0026quot;$PWD/docker/posttrain/environment/.venv-sft\u0026quot; \\\n  python3 -m uv sync --project docker/posttrain/environment --frozen \\\n  --no-group transformers4 --group sft --group cu130-runtime\nexport SFT_PYTHON=\u0026quot;$PWD/docker/posttrain/environment/.venv-sft/bin/python\u0026quot;\nexport PYTHONPATH=.\n\n# The reviewed Qwen3.8-27B snapshot (about 56 GB).\nuvx hf@latest download Qwen/Qwen3.8-27B \\\n  --revision 1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0 \\\n  --local-dir artifacts/models/Qwen3.8-27B\nexport SFT_MODEL_PATH=\u0026quot;$PWD/artifacts/models/Qwen3.8-27B\u0026quot;\nexport SFT_DATA_ROOT=\u0026quot;$PWD/.ene/scratch/sft-example\u0026quot;\n\u0026quot;$SFT_PYTHON\u0026quot; -m cosmos_framework.posttrain.scripts.prepare_sft_example --output \u0026quot;$SFT_DATA_ROOT\u0026quot;\n\u0026quot;$SFT_PYTHON\u0026quot; -m cosmos_framework.posttrain.entrypoints.sft --validate-manifest\n\u0026quot;$SFT_PYTHON\u0026quot; -m cosmos_framework.posttrain.entrypoints.sft --validate-rows\n\n# N is the allocated GPU count; this command does not allocate resources.\n\u0026quot;$SFT_PYTHON\u0026quot; -m torch.distributed.run --standalone --nproc_per_node=\u0026quot;$N\u0026quot; \\\n  -m cosmos_framework.posttrain.entrypoints.sft\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e `python3 -m uv` runs the pip-installed uv 0.11.29: a bare `uv` can resolve to an older release\u003c/span\u003e\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e that ships with the container, which the environment project refuses.\u003c/span\u003e\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e cu130-runtime matches the run guide's CUDA 13.0 image; use cu128-runtime on a CUDA 12.8 stack.\u003c/span\u003e\nUV_PROJECT_ENVIRONMENT=\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003e$PWD\u003c/span\u003e/docker/posttrain/environment/.venv-sft\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e \\\n  python3 -m uv sync --project docker/posttrain/environment --frozen \\\n  --no-group transformers4 --group sft --group cu130-runtime\n\u003cspan class=\"pl-k\"\u003eexport\u003c/span\u003e SFT_PYTHON=\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003e$PWD\u003c/span\u003e/docker/posttrain/environment/.venv-sft/bin/python\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003eexport\u003c/span\u003e PYTHONPATH=.\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e The reviewed Qwen3.8-27B snapshot (about 56 GB).\u003c/span\u003e\nuvx hf@latest download Qwen/Qwen3.8-27B \\\n  --revision 1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0 \\\n  --local-dir artifacts/models/Qwen3.8-27B\n\u003cspan class=\"pl-k\"\u003eexport\u003c/span\u003e SFT_MODEL_PATH=\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003e$PWD\u003c/span\u003e/artifacts/models/Qwen3.8-27B\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003eexport\u003c/span\u003e SFT_DATA_ROOT=\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003e$PWD\u003c/span\u003e/.ene/scratch/sft-example\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003e$SFT_PYTHON\u003c/span\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e -m cosmos_framework.posttrain.scripts.prepare_sft_example --output \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003e$SFT_DATA_ROOT\u003c/span\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003e$SFT_PYTHON\u003c/span\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e -m cosmos_framework.posttrain.entrypoints.sft --validate-manifest\n\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003e$SFT_PYTHON\u003c/span\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e -m cosmos_framework.posttrain.entrypoints.sft --validate-rows\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e N is the allocated GPU count; this command does not allocate resources.\u003c/span\u003e\n\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003e$SFT_PYTHON\u003c/span\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e -m torch.distributed.run --standalone --nproc_per_node=\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003e$N\u003c/span\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e \\\n  -m cosmos_framework.posttrain.entrypoints.sft\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe generator creates 32 training and 8 validation conversations with local PNG/MP4 media;\nit refuses to overwrite a nonempty directory. Video decoding requires TorchCodec 0.11.0\nand compatible FFmpeg shared libraries. This is a functional example, not a quality benchmark.\nPreflight checks configuration, local file availability and role wiring, not GPU memory or\nremote access. \u003ccode\u003e--validate-rows\u003c/code\u003e then runs every row through the real packer on CPU and refuses\nover-long rows, masks that disagree with the assistant turns, and mislabelled tool turns before any\ntrainer is built (\u003ca href=\"/NVIDIA/cosmos-framework/blob/main/cosmos_framework/posttrain/scripts/README.md#pre-launch-sft-row-validator\"\u003escripts/README.md\u003c/a\u003e). Use torchrun even for one GPU; 27B FP32 training does not fit a single ordinary GPU.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eUse a complete immutable snapshot, not a mutable Hub branch or metadata-only test fixture.\nThe reviewed Qwen3.8 revision is \u003ccode\u003e1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0\u003c/code\u003e; its config selects\n\u003ccode\u003eQwen3_5ForConditionalGeneration\u003c/code\u003e and its processor is \u003ccode\u003eQwen3VLProcessor\u003c/code\u003e. Preserve the\nprocessor/tokenizer/template sidecars. The loader requires every dense model parameter and\nignores extra \u003ccode\u003emtp.*\u003c/code\u003e weights; SFT does not train MTP.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e3. Data contract\u003c/h2\u003e\u003ca id=\"user-content-3-data-contract\" class=\"anchor\" aria-label=\"Permalink: 3. Data contract\" href=\"#3-data-contract\"\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 complete conversation per JSONL record:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-json notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"{\u0026quot;messages\u0026quot;:[{\u0026quot;role\u0026quot;:\u0026quot;user\u0026quot;,\u0026quot;content\u0026quot;:[{\u0026quot;type\u0026quot;:\u0026quot;image\u0026quot;,\u0026quot;image\u0026quot;:\u0026quot;media/frame.png\u0026quot;},{\u0026quot;type\u0026quot;:\u0026quot;text\u0026quot;,\u0026quot;text\u0026quot;:\u0026quot;What color is the object?\u0026quot;}]},{\u0026quot;role\u0026quot;:\u0026quot;assistant\u0026quot;,\u0026quot;content\u0026quot;:\u0026quot;Red.\u0026quot;},{\u0026quot;role\u0026quot;:\u0026quot;user\u0026quot;,\u0026quot;content\u0026quot;:\u0026quot;Repeat in uppercase.\u0026quot;},{\u0026quot;role\u0026quot;:\u0026quot;assistant\u0026quot;,\u0026quot;content\u0026quot;:\u0026quot;RED.\u0026quot;}]}\"\u003e\u003cpre\u003e{\u003cspan class=\"pl-ent\"\u003e\"messages\"\u003c/span\u003e:[{\u003cspan class=\"pl-ent\"\u003e\"role\"\u003c/span\u003e:\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003euser\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\u003cspan class=\"pl-ent\"\u003e\"content\"\u003c/span\u003e:[{\u003cspan class=\"pl-ent\"\u003e\"type\"\u003c/span\u003e:\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eimage\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\u003cspan class=\"pl-ent\"\u003e\"image\"\u003c/span\u003e:\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003emedia/frame.png\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e},{\u003cspan class=\"pl-ent\"\u003e\"type\"\u003c/span\u003e:\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003etext\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\u003cspan class=\"pl-ent\"\u003e\"text\"\u003c/span\u003e:\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eWhat color is the object?\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e}]},{\u003cspan class=\"pl-ent\"\u003e\"role\"\u003c/span\u003e:\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eassistant\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\u003cspan class=\"pl-ent\"\u003e\"content\"\u003c/span\u003e:\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eRed.\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e},{\u003cspan class=\"pl-ent\"\u003e\"role\"\u003c/span\u003e:\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003euser\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\u003cspan class=\"pl-ent\"\u003e\"content\"\u003c/span\u003e:\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eRepeat in uppercase.\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e},{\u003cspan class=\"pl-ent\"\u003e\"role\"\u003c/span\u003e:\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eassistant\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\u003cspan class=\"pl-ent\"\u003e\"content\"\u003c/span\u003e:\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eRED.\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e}]}\u003c/pre\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eRoles: \u003ccode\u003esystem\u003c/code\u003e (first only), \u003ccode\u003euser\u003c/code\u003e, \u003ccode\u003eassistant\u003c/code\u003e, and \u003ccode\u003etool\u003c/code\u003e. Text is a string or a\n\u003ccode\u003e{\"type\":\"text\",\"text\":\"...\"}\u003c/code\u003e part. Videos use \u003ccode\u003e{\"type\":\"video\",\"video\":\"...\"}\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eOptional \u003ccode\u003etools\u003c/code\u003e, assistant \u003ccode\u003etool_calls\u003c/code\u003e, and \u003ccode\u003ereasoning_content\u003c/code\u003e are retained. Tool-only\nassistant content may be absent/null; it normalizes to empty text.\u003c/li\u003e\n\u003cli\u003eOptional \u003ccode\u003esupervise\u003c/code\u003e, a string: \u003ccode\u003eall_assistant\u003c/code\u003e (the rule when the key is absent) or \u003ccode\u003elast_assistant\u003c/code\u003e\n(section 4). Any other value, \u003ccode\u003enull\u003c/code\u003e included, is refused at load with the row's label. The key is\nnever added to a row that lacks it, so the fingerprint of an existing file does not change.\u003c/li\u003e\n\u003cli\u003eOptional \u003ccode\u003eopener\u003c/code\u003e, a string: \u003ccode\u003eself\u003c/code\u003e (the rule when the key is absent) or \u003ccode\u003eprefilled\u003c/code\u003e (section 4);\nvalidated and never added the same way. A \u003ccode\u003emeta.opener\u003c/code\u003e (the exporter's record of its prefilled slice)\nmust agree with the \u003ccode\u003eopener\u003c/code\u003e field, which is what the packer reads.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003erl.data.path\u003c/code\u003e and \u003ccode\u003erl.validation.data.path\u003c/code\u003e accept local JSONL or \u003ccode\u003es3://bucket/key.jsonl\u003c/code\u003e.\nRemote reads use each source's \u003ccode\u003ecredentials\u003c/code\u003e path and the existing S3/GCS client.\u003c/li\u003e\n\u003cli\u003eJSONL is read once per rank into memory. Fingerprints cover normalized content and local\nmedia bytes. Text-only identity excludes URI/credentials and survives cross-cluster moves.\u003c/li\u003e\n\u003cli\u003eLocal media resolves relative to the JSONL file unless \u003ccode\u003emedia_root\u003c/code\u003e is set. S3 JSONL with\nmedia requires an explicit local \u003ccode\u003emedia_root\u003c/code\u003e; automatic remote media fetching is not supported.\u003c/li\u003e\n\u003cli\u003eAlternatively, \u003ccode\u003erl.data.factory\u003c/code\u003e plus \u003ccode\u003efactory_kwargs\u003c/code\u003e selects a map-style source returning\nthis schema with an immutable \u003ccode\u003ecursor_fingerprint()\u003c/code\u003e covering rows and media. Additional\ndataset cursor hooks must be supplied as a save/load pair.\u003c/li\u003e\n\u003cli\u003eTraining row count must divide DP world size. Rows shuffle and repeat by epoch; no training\nrecords are silently dropped or padded. Validation requires a separate source.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e4. Objective and masking\u003c/h2\u003e\u003ca id=\"user-content-4-objective-and-masking\" class=\"anchor\" aria-label=\"Permalink: 4. Objective and masking\" href=\"#4-objective-and-masking\"\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 packer renders with the checkpoint's own chat template and passes \u003ccode\u003epreserve_thinking=True\u003c/code\u003e\nonly to a template that declares that variable (the toy test template does). The official\nQwen3-VL template has no such variable: it renders \u003ccode\u003ereasoning_content\u003c/code\u003e for every assistant turn\nand passes inline \u003ccode\u003e\u0026lt;think\u0026gt;\u003c/code\u003e text through as content, so nothing is passed to it; a kwarg the\ntemplate does not declare is one Transformers 5 reclassifies as a processor kwarg and warns about\non every render. Every assistant body and turn-ending token is supervised; headers,\nuser/system/tool content, media tokens, generated video timestamps and padding are ignored.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eRow-level supervision (\u003ccode\u003esupervise\u003c/code\u003e).\u003c/strong\u003e A row's \u003ccode\u003esupervise\u003c/code\u003e field selects the assistant\nturns that carry loss: \u003ccode\u003eall_assistant\u003c/code\u003e (the default and the behaviour before the field existed: every\nassistant body and its \u003ccode\u003e\u0026lt;|im_end|\u0026gt;\u003c/code\u003e) or \u003ccode\u003elast_assistant\u003c/code\u003e (the LAST assistant turn's body through its\n\u003ccode\u003e\u0026lt;|im_end|\u0026gt;\u003c/code\u003e only; every earlier assistant turn stays in the sequence as context at -100, like the tool\nresults and user turns around it). The packer records the row's contract string on\n\u003ccode\u003eSFTPolicyInput.masking\u003c/code\u003e (\u003ccode\u003eqwen_chatml_all_assistant_bodies_and_end_v2\u003c/code\u003e or\n\u003ccode\u003eqwen_chatml_last_assistant_body_and_end_v1\u003c/code\u003e); the packer-level resume identity keeps the all-assistant\nstring because the field is part of the row and therefore of the source fingerprint.\n\u003ccode\u003erl.mask_think_opener\u003c/code\u003e applies to the supervised turn only (the per-row \u003ccode\u003eopener\u003c/code\u003e field below applies the\nsame rule to one row). The rule exists for \u003cstrong\u003eprefix rows\u003c/strong\u003e (a term\ndefined here): one row per model call of an agent-harness episode, whose prompt is the served prefix of\nthat call -- the tokenizer template's rendering of the history, every earlier assistant turn\nreasoning-free, exactly what the default serve renders when the request carries a tools array (measured\nequal to the serving deployment's tokenize endpoint on 146 of 146 calls of one agent-harness episode) --\nand whose completion is the student's own turn at that call, reasoning included.\nA prefix row therefore matches the \u003cstrong\u003edefault serve\u003c/strong\u003e of a default export token for token; a\nwhole-episode row with reasoning in every assistant turn does not (it is exact only under a serve that\nrenders the processor template with tools: a \u003cstrong\u003eunified export\u003c/strong\u003e, defined in section 7 as an export built\nwith the materializer's \u003ccode\u003e--unified-chat-template\u003c/code\u003e, whose two template files carry the canonical processor\ntemplate). Fixtures:\n\u003ccode\u003etests/test_data_packer_sft.py::test_supervise_last_assistant_three_turn_row_exact_loss_counts\u003c/code\u003e\n(a three-turn row through the toy tokenizer: 96 = [91, 5] loss tokens under the default, 5 = [5] under\n\u003ccode\u003elast_assistant\u003c/code\u003e, the ids identical) and\n\u003ccode\u003etest_supervise_last_assistant_official_template_keeps_history_at_minus_100\u003c/code\u003e (the official template\nwith an image and a tool call; the opener mask then touches the last turn's opener only). Under\n\u003ccode\u003elast_assistant\u003c/code\u003e the history turns must carry no reasoning: the packer refuses a history assistant turn\nwith a non-empty \u003ccode\u003ereasoning_content\u003c/code\u003e or a content opening with \u003ccode\u003e\u0026lt;think\u0026gt;\u003c/code\u003e (the processor template renders\na history \u003ccode\u003ereasoning_content\u003c/code\u003e as a think block, 250 vs 236 ids on one probe, while the default serve's\nprefix has none, and it strips an exact \u003ccode\u003e\u0026lt;think\u0026gt;\u0026lt;/think\u0026gt;\u003c/code\u003e content prefix the tokenizer template keeps).\nFixture:\n\u003ccode\u003etest_last_assistant_row_prefix_is_the_served_prefix_under_both_templates_and_history_reasoning_is_refused\u003c/code\u003e\n(the base's two templates as repo fixtures: the row's text and ids begin with the tokenizer template's\nserved prefix, the two templates agree byte for byte when no turn carries reasoning, a history\n\u003ccode\u003ereasoning_content\u003c/code\u003e or \u003ccode\u003e\u0026lt;think\u0026gt;\u0026lt;/think\u0026gt;\u003c/code\u003e prefix diverges inside the history and is refused, an\n\u003ccode\u003eall_assistant\u003c/code\u003e row with the same history still packs).\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eRow-level opener (\u003ccode\u003eopener\u003c/code\u003e).\u003c/strong\u003e A row's \u003ccode\u003eopener\u003c/code\u003e field says whose token the\n\u003ccode\u003e\u0026lt;think\u0026gt;\u003c/code\u003e opener of a supervised assistant turn is: \u003ccode\u003eself\u003c/code\u003e (the default and the behaviour before the\nfield: the opener is the student's first supervised token, as the agent harness's serve prefills nothing)\nor \u003ccode\u003eprefilled\u003c/code\u003e (the serve prefills the opener token itself, \u003ccode\u003e\u0026lt;|im_start|\u0026gt;assistant\\n\u0026lt;think\u0026gt;\u003c/code\u003e, id 151667, no\nnewline after it, as a thinking-on client without tools does: the packer masks the first \u003ccode\u003e\u0026lt;think\u0026gt;\u003c/code\u003e token\nof every supervised assistant block of that row, exactly the rule the run-level \u003ccode\u003erl.mask_think_opener=True\u003c/code\u003e\napplies to every row, and the supervised target begins with the newline that opens the reasoning text;\nunder \u003ccode\u003elast_assistant\u003c/code\u003e that is the last block only). One rule: a row with \u003ccode\u003eopener: prefilled\u003c/code\u003e in a run\nwith \u003ccode\u003emask_think_opener=True\u003c/code\u003e is masked once, the count unchanged. Why per row: the exporter writes the\nprefilled slice (20 percent of the supervised reasoning turns, a fixed seed) into the same row files\nas the self rows, so the mask must be the row's, not the run's; the exporter records its choice as\n\u003ccode\u003emeta.opener\u003c/code\u003e and must write the same value in the row's \u003ccode\u003eopener\u003c/code\u003e field, which is what the packer reads\n(the loader refuses a \u003ccode\u003emeta.opener\u003c/code\u003e that disagrees with the field, a \u003ccode\u003eprefilled\u003c/code\u003e in \u003ccode\u003emeta\u003c/code\u003e without the\nfield included). The per-row contract string gains \u003ccode\u003e_opener_prefilled_v1\u003c/code\u003e\n(\u003ccode\u003eqwen_chatml_all_assistant_bodies_and_end_v2_opener_prefilled_v1\u003c/code\u003e,\n\u003ccode\u003eqwen_chatml_last_assistant_body_and_end_v1_opener_prefilled_v1\u003c/code\u003e); the packer-level identity keeps\nrecording the run-level knob. A \u003ccode\u003eprefilled\u003c/code\u003e row on a tokenizer without \u003ccode\u003e\u0026lt;think\u0026gt;\u003c/code\u003e is refused. A \u003ccode\u003eprefilled\u003c/code\u003e\nrow needs a reasoning block in every supervised assistant turn: the packer\nrefuses the row unless its mask removed exactly one \u003ccode\u003e\u0026lt;think\u0026gt;\u003c/code\u003e id in every supervised block (the refusal\nnames the bare blocks and the per-block counts), and the loader refuses a \u003ccode\u003eprefilled\u003c/code\u003e row whose supervised\nturns (all of them under \u003ccode\u003eall_assistant\u003c/code\u003e, the last under \u003ccode\u003elast_assistant\u003c/code\u003e) lack a non-empty\n\u003ccode\u003ereasoning_content.strip()\u003c/code\u003e, so the string \u003ccode\u003e_opener_prefilled_v1\u003c/code\u003e is only ever recorded when the masking\nhappened; the run-level knob on a bare turn masks nothing and refuses nothing (it is the run's variant,\nrecorded in the packer identity, not the row's contract). The loader also refuses a \u003ccode\u003emeta.supervise\u003c/code\u003e that\ndisagrees with the row's \u003ccode\u003esupervise\u003c/code\u003e field, as it does for \u003ccode\u003emeta.opener\u003c/code\u003e. Fixtures:\n\u003ccode\u003etests/test_data_packer_sft.py::test_opener_prefilled_three_turn_row_exact_loss_counts_under_the_four_combinations\u003c/code\u003e\n(a three-turn row through the toy tokenizer: with reasoning in both assistant turns under \u003ccode\u003eall_assistant\u003c/code\u003e,\n\u003ccode\u003eself\u003c/code\u003e 118 = [102, 16] and \u003ccode\u003eprefilled\u003c/code\u003e 116 = [101, 15]; under \u003ccode\u003elast_assistant\u003c/code\u003e, with the history turn\nreasoning-free as that mode requires, 16 and 15; the difference exactly the opener token of each\nsupervised block), \u003ccode\u003etest_opener_prefilled_and_the_global_mask_are_one_rule\u003c/code\u003e,\n\u003ccode\u003etest_opener_refuses_unknown_values_and_a_tokenizer_without_think\u003c/code\u003e,\n\u003ccode\u003etest_opener_prefilled_refuses_a_supervised_block_without_an_opener\u003c/code\u003e (B1 / B2 / B3 refused, self rows and the\nrun-level knob unchanged),\n\u003ccode\u003etests/test_roles_env_sft.py::test_opener_field_is_validated_by_the_loader_and_reaches_the_target\u003c/code\u003e and\n\u003ccode\u003e::test_opener_prefilled_rows_require_reasoning_on_every_supervised_turn_and_meta_supervise_must_agree\u003c/code\u003e. A row\nvalidator that counts assistant tokens independently of the labels must count over\n\u003ccode\u003edata/packer/sft.py::supervised_assistant_blocks(n_assistant_blocks, supervise)\u003c/code\u003e, the indices the packer\npaints, or it reports every \u003ccode\u003elast_assistant\u003c/code\u003e row as a mask mismatch.\n\u003ccode\u003erl.mask_think_opener=True\u003c/code\u003e additionally unsupervises the \u003ccode\u003e\u0026lt;think\u0026gt;\u003c/code\u003e token that opens an assistant\nbody, and only that token. Keep the default \u003ccode\u003eFalse\u003c/code\u003e: on the serving path of record (Codex\n\u003ccode\u003e--thinking high\u003c/code\u003e sends \u003ccode\u003ereasoning.effort\u003c/code\u003e and the harness's tools array on every call) vLLM 0.24\nprefills no opener -- with tools present the served prefix is \u003ccode\u003e\u0026lt;|im_start|\u0026gt;assistant\\n\u003c/code\u003e and nothing\nmore (the effort field adds 0 input tokens; \u003ccode\u003e/tokenize\u003c/code\u003e with tools and \u003ccode\u003eenable_thinking\u003c/code\u003e ends in\n\u003ccode\u003eassistant\\n\u003c/code\u003e; measured live; the ids are the fixture\n\u003ccode\u003etests/fixtures/served_prefix_with_tools.json\u003c/code\u003e), so the student must emit \u003ccode\u003e\u0026lt;think\u0026gt;\u003c/code\u003e itself as the\nfirst token of every turn and then the reasoning, or the closer \u003ccode\u003e\\n\\n\u0026lt;/think\u0026gt;\\n\\n\u003c/code\u003e of the empty\nblock a turn without reasoning (a no-think turn) is rendered with; all of it is the student's and\nthe opener's loss is the only training signal for that token. \u003ccode\u003eTrue\u003c/code\u003e would leave it unsupervised;\nwhat a \u003ccode\u003eTrue\u003c/code\u003e-trained student would emit there is UNMEASURED with tools present (no such student\nexists, and the first token after \u003ccode\u003eassistant\\n\u003c/code\u003e with tools present was never sampled), so the\nconsequence is a RISK, not a measurement. The failure it could reopen has a measured trigger: the\nqwen3 parser treats an output that carries no \u003ccode\u003e\u0026lt;/think\u0026gt;\u003c/code\u003e as reasoning in full, so a no-think TEXT\nturn of the student never reaches Codex as an agent message, while a no-think TOOL-CALL turn is\nunaffected (vLLM 0.24 \u003ccode\u003ereasoning/basic_parsers.py\u003c/code\u003e 173-181: without \u003ccode\u003e\u0026lt;/think\u0026gt;\u003c/code\u003e the whole output is\nreasoning; with \u003ccode\u003e\u0026lt;/think\u0026gt;\u003c/code\u003e it is split even without \u003ccode\u003e\u0026lt;think\u0026gt;\u003c/code\u003e); under the exporter's rendering the\ncloser stays supervised under \u003ccode\u003eTrue\u003c/code\u003e, so a turn that dropped only the opener would still carry\n\u003ccode\u003e\u0026lt;/think\u0026gt;\u003c/code\u003e. The decision does not rest on the risk: \u003ccode\u003eFalse\u003c/code\u003e stays the default because the opener's\nloss is the only training signal for a token the student must emit on the path of record. Selecting\nthe \u003ccode\u003eprefilled_opener\u003c/code\u003e variant sets the typed field \u003ccode\u003erl.serve_contract=prefills_opener\u003c/code\u003e beside the\nmask: the declaration that the student will be served by a path that prefills \u003ccode\u003e\u0026lt;think\u0026gt;\u003c/code\u003e for it,\nrecorded in the resolved config and, being non-default, in the objective identity. \u003ccode\u003eSFTConfig\u003c/code\u003e\nrefuses the VALUE \u003ccode\u003erl.mask_think_opener=True\u003c/code\u003e under the default contract \u003ccode\u003etools_no_prefill\u003c/code\u003e from any\nsource, a \u003ccode\u003e--\u003c/code\u003e override on the \u003ccode\u003edefault\u003c/code\u003e variant included, and the resolved variant name is stamped\ninto the attempt's provenance as \u003ccode\u003erecipe_variant\u003c/code\u003e. The prefill exists only for requests without\ntools: there a present effort sets \u003ccode\u003eenable_thinking\u003c/code\u003e and the template appends \u003ccode\u003e\u0026lt;think\u0026gt;\u003c/code\u003e (10 input\ntokens instead of 9) -- not a path of record; under such a serve the supervised opener costs one\ndeterministic token per turn and the student continues after it, so \u003ccode\u003eFalse\u003c/code\u003e is right under both\nconditions. (The Nemo-Chat processor rule also unsupervises an empty block, because its serve\nsupplies the whole block; that rule, applied here, would remove the closer's loss under a single-newline\nrendering.) The native recipe's table (its \u003ccode\u003e\u0026lt;think\u0026gt;\u003c/code\u003e opener row) records the decision with its\nmeasurements. Templates that drop supplied reasoning or reorder messages are rejected, as are\nreserved chat/media delimiters in source text.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eMasks use the \u003cstrong\u003efinal processor-expanded token stream\u003c/strong\u003e, requiring an exact tokenizer round\ntrip; no prefix-length approximation or pre-expansion assistant mask is used. Labels are\nunshifted at collation; the objective shifts exactly once. With \u003ccode\u003erl.ce_exponent=0\u003c/code\u003e (the framework\ndefault) the loss is the global supervised-token mean across ranks and accumulation; with\n\u003ccode\u003ece_exponent=e\u003c/code\u003e every row contributes its token sum divided by \u003ccode\u003en^e\u003c/code\u003e over the DP-mean of\n\u003ccode\u003esum_rows n^(1-e)\u003c/code\u003e (\u003ccode\u003e0.5\u003c/code\u003e = the Cosmos post-training recipe's square-root weighting, \u003ccode\u003e1\u003c/code\u003e = every row\nweighs the same). \u003ccode\u003erl.moe_lbl_coeff\u0026gt;0\u003c/code\u003e adds the MoE load-balancing term\n\u003ccode\u003ecoeff * E * mean_layers(sum_e f_e * P_e)\u003c/code\u003e from the sparse blocks' routing statistics of the same\nforward (\u003ccode\u003ef_e\u003c/code\u003e the share of routed tokens, summed over the DP ranks under \u003ccode\u003emoe_lbl_method='global'\u003c/code\u003e;\n\u003ccode\u003eP_e\u003c/code\u003e the mean router probability); \u003ccode\u003etrain/lbl_loss\u003c/code\u003e, \u003ccode\u003etrain/moe_load_max_rel\u003c/code\u003e (the largest\nexpert's share relative to uniform, 1.0 = balanced) and \u003ccode\u003etrain/objective\u003c/code\u003e (the value descended)\nthen appear beside \u003ccode\u003etrain/loss_avg\u003c/code\u003e, which stays the plain token-mean CE. Overlength conversations\nfail rather than truncating targets.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e5. Main knobs\u003c/h2\u003e\u003ca id=\"user-content-5-main-knobs\" class=\"anchor\" aria-label=\"Permalink: 5. Main knobs\" href=\"#5-main-knobs\"\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\"\u003eGlobal conversations/update are \u003ccode\u003erl.micro_batch_size × rl.grad_accum × DP world size\u003c/code\u003e.\n\u003ccode\u003erl.max_steps\u003c/code\u003e counts optimizer updates; \u003ccode\u003erl.max_length\u003c/code\u003e limits the full expanded sequence.\n\u003ccode\u003erl.optimizer.*\u003c/code\u003e controls the optimizer, clipping and warmup (\u003ccode\u003ewarmup_steps\u003c/code\u003e must be \u003ccode\u003e\u0026gt;= 0\u003c/code\u003e);\n\u003ccode\u003erl.lr_schedule.kind\u003c/code\u003e selects what follows the warmup: \u003ccode\u003econstant\u003c/code\u003e (the pre-existing path) or\n\u003ccode\u003ecosine\u003c/code\u003e (the Cosmos post-training recipe's \u003ccode\u003eLambdaWarmUpCosineScheduler\u003c/code\u003e: lr × \u003ccode\u003ef_start\u003c/code\u003e at the\nfirst update, linear to lr at \u003ccode\u003ewarmup_steps\u003c/code\u003e, cosine down to lr × \u003ccode\u003ef_min\u003c/code\u003e at \u003ccode\u003ecycle_steps\u003c/code\u003e or\n\u003ccode\u003emax_steps\u003c/code\u003e). \u003ccode\u003erl.optimizer.lr_multipliers\u003c/code\u003e scales the learning rate of the parameters whose name\ncontains a key (\u003ccode\u003e{\"model.visual\": 0.1}\u003c/code\u003e = the vision tower at a tenth). Precision differs by seat.\nThe dense HF recipe keeps FP32 parameters and optimizer state (\u003ccode\u003emaster_dtype='float32'\u003c/code\u003e) under BF16\nautocast. The native Qwen3-VL-MoE recipe stores the parameters in bfloat16\n(\u003ccode\u003emaster_dtype='bfloat16'\u003c/code\u003e, \u003ccode\u003eparam_dtype='bfloat16'\u003c/code\u003e); its fp32 master weights and fp32 moments\nlive inside the apex fused Adam (\u003ccode\u003eOptimizerConfig(name='fusedadam')\u003c/code\u003e), which refreshes the bf16\nparameters from the master on every step, and the saved artifact is that bf16 copy, never the\nmaster: an update below half a bf16 ulp of a weight is carried in the master during the run and\nreaches neither the artifact nor the training forward, which reads the same bf16 copy. Known limit,\nmeasured over 1,401 training steps at lr 1e-5: \u003ccode\u003emodel.language_model.norm.weight\u003c/code\u003e\n(median |w| 3.08, bf16 ulp 0.0156 \u0026gt; 1,401 × 1e-5 = 0.014) changed in 0 of 2,048 elements while\n\u003ccode\u003elayers.0.input_layernorm.weight\u003c/code\u003e (median 0.0036) changed in 1,985 of 2,048; 36 of the 882 tensors\n(34 vision norms, \u003ccode\u003elayers.47.input_layernorm.weight\u003c/code\u003e, the final norm) were bitwise the base's, i.e.\nthose 36 norm scales did not train. Trade-off: the served model is bf16 either way, and storing the\n1-D parameters (the 426 norm scales and biases, a few MB in fp32) in fp32 would un-freeze them at\nnegligible memory cost, the export rounding each once (at most half an ulp lost). The materializer\nrecords per export how many tensors equal the base (\u003ccode\u003etensors_equal_to_base\u003c/code\u003e in \u003ccode\u003e.materialized\u003c/code\u003e).\n\u003ccode\u003etests/test_config_sft.py::test_bf16_storage_freezes_large_scales_below_half_an_ulp\u003c/code\u003e is a pin of the\nmechanism on a tiny fixture (it records pure bf16 arithmetic, which the framework does not change), as\nis \u003ccode\u003etest_deterministic_knob_reaches_setup\u003c/code\u003e (pre-existing setup behaviour); neither tests a change to\nthe framework. Both recipes use activation checkpointing and SDPA. Weight decay is decoupled;\n\u003ccode\u003edecay_groups=''\u003c/code\u003e builds one parameter group (every trainable parameter decays, norms, biases,\nembeddings and routers included -- the Cosmos post-training recipe's own grouping:\n\u003ccode\u003ecosmos3/utils/optimizer.py::_build_params_with_metadata\u003c/code\u003e decays all 882 tensors of the backbone),\n\u003ccode\u003edecay_groups='hf'\u003c/code\u003e reproduces the Transformers Trainer's [decay, no-decay] split (LayerNorm modules,\nbiases and \u003ccode\u003e*norm*\u003c/code\u003e names undecayed; the embedding, the head and the router gates decay), and\n\u003ccode\u003edecay_groups='qwen_moe'\u003c/code\u003e (the native recipe) leaves every 1-D parameter (norm scales, biases) AND\nthe token embedding, the output head and the MoE router gates undecayed -- the seat's own choice,\nwhose protection and cost the recipe's table states in its weight-decay row. The native recipe's\ndocstring carries the per-knob decision table (Cosmos post-training recipe vs the A1 arms vs its\ndefaults).\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003erl.processor_kwargs\u003c/code\u003e accepts HF \u003ccode\u003eimages_kwargs\u003c/code\u003e and \u003ccode\u003evideos_kwargs\u003c/code\u003e. Pixel budgets use\n\u003ccode\u003esize.shortest_edge\u003c/code\u003e/\u003ccode\u003elongest_edge\u003c/code\u003e (pixel area), not legacy \u003ccode\u003emin_pixels\u003c/code\u003e/\u003ccode\u003emax_pixels\u003c/code\u003e.\nThe example samples 8 video frames with \u003ccode\u003efps=None\u003c/code\u003e; do not also request FPS-based sampling.\nThe processor's media tensors and \u003ccode\u003emm_token_type_ids\u003c/code\u003e reach the model unchanged. The Qwen3.5\nforward adapter orders image/video vision calls and backward graphs on every rank, including\ndummy work for absent modalities; dummy grids never enter token positions or M-RoPE.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e6. Metrics and validation\u003c/h2\u003e\u003ca id=\"user-content-6-metrics-and-validation\" class=\"anchor\" aria-label=\"Permalink: 6. Metrics and validation\" href=\"#6-metrics-and-validation\"\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\u003etrain/loss_avg\u003c/code\u003e and \u003ccode\u003eval/loss_avg\u003c/code\u003e are token-weighted means; valid token/sequence counts\nare sums. Every committed frame is written to \u003ccode\u003e\u0026lt;run dir\u0026gt;/metrics.jsonl\u003c/code\u003e (one JSON line per step:\n\u003ccode\u003etrain/grad_norm\u003c/code\u003e = the pre-clip global norm, \u003ccode\u003etrain/learning_rate\u003c/code\u003e, \u003ccode\u003etrain/valid_token_count\u003c/code\u003e,\n\u003ccode\u003etimer/e2e_step_s\u003c/code\u003e, \u003ccode\u003etrain/grad_clip_coef\u003c/code\u003e = the factor \u003ccode\u003eclip_grad_norm_\u003c/code\u003e applied,\n\u003ccode\u003emin(1, grad_clip_norm / (norm + 1e-6))\u003c/code\u003e, and \u003ccode\u003etrain/grad_clipped\u003c/code\u003e = 1.0 exactly when that factor is\nbelow 1 (one rule; both recorded by \u003ccode\u003eLLMTrainer\u003c/code\u003e from the norm it clipped),\n\u003ccode\u003etrain/grad_clip_fraction\u003c/code\u003e = the share of the run's updates clipped so far (the loop's running count),\nplus the validation keys of that step) and the console line carries the headline subset. The file\nholds one row per step across relaunches: an attempt that resumes at step \u003ccode\u003es\u003c/code\u003e keeps the rows with\n\u003ccode\u003estep \u0026lt;= s\u003c/code\u003e and drops the later ones, which it re-emits (a crash past the last save leaves committed\nrows the resumed attempt recomputes), and the clip counters continue from the kept rows, so the\nfraction is the run's, not the attempt's; a fresh attempt starts the file empty. Held-out validation\nuses finite batches with zero-weight tail padding and restores module modes, source cursor and RNGs.\nFinal validation is mandatory when enabled. The validation source must be held out row by row: setup\nrefuses it when any validation row has the content hash (messages + tools, media by file bytes so a\ncopy of the training media under another root is the same row) of a training row or the item id\n(\u003ccode\u003emeta.item\u003c/code\u003e) of one, and when validation rows carry no item id while the training rows do (a row\nwithout an item has only its content hash as identity, which one changed character defeats); a\nwhole-source fingerprint check is not enough, since it passes a strict subset of the training file.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eOn the native Qwen3-VL-MoE seat, \u003ccode\u003etrain/grad_norm\u003c/code\u003e varies from run to run because routing in the bf16\nMoE forward is not deterministic. Read it as a per-run diagnostic, not as a quantity to compare\nbetween two runs.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e7. Checkpoints, resume and export\u003c/h2\u003e\u003ca id=\"user-content-7-checkpoints-resume-and-export\" class=\"anchor\" aria-label=\"Permalink: 7. Checkpoints, resume and export\" href=\"#7-checkpoints-resume-and-export\"\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 generic example saves DCP every 10 updates and at its final step. Obj1k instead selects\nconsolidated \u003ccode\u003emodel.pt\u003c/code\u003e for HF export. \u003ccode\u003erl.resume=auto\u003c/code\u003e resumes the latest checkpoint for the\nsame job identity; an explicit iteration directory also works. Exact resume binds every rank's\ndata cursor, tokenizer/processor/masking semantics, precision and batching. Preemption saves\nonly at complete optimizer boundaries.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eFor storage and retention see \u003ca href=\"/NVIDIA/cosmos-framework/blob/main/docs/posttrain/reference/checkpoint.md\"\u003echeckpointing\u003c/a\u003e. The\n\u003ca href=\"/NVIDIA/cosmos-framework/blob/main/docs/posttrain/howto/checkpoint-artifacts.md#materialize-an-opd-teacher\"\u003eHF materializer\u003c/a\u003e consumes consolidated\n\u003ccode\u003emodel.pt\u003c/code\u003e, not DCP; it preserves tokenizer/processor sidecars, writes the base's \u003ccode\u003econfig.json\u003c/code\u003e into the\nexport (the transformers-written one is kept unpublished as \u003ccode\u003econfig.json.trainer.bak\u003c/code\u003e, the export's own file\nbefore the base overlay), and verifies every tensor of \u003ccode\u003emodel.pt\u003c/code\u003e bitwise against the shards before it\nreturns, keeping a sha256 per tensor and the list of tensors bitwise equal to the base in \u003ccode\u003e.materialized\u003c/code\u003e. A\n\u003ccode\u003eprocessor_config.json\u003c/code\u003e in the export is the base's own file or none (the reference base carries none);\n\u003ccode\u003econversion.hf.service_processor_config\u003c/code\u003e composes one from the base's sidecars but has no production caller,\nand the file served beside one deployed export (placed by hand) differs from it in the image processor class\nand 17 explicit defaults, so connecting the helper is a separate change: a contract bump, \u003ccode\u003everify_sidecars\u003c/code\u003e\naccepting the composed file and a re-anchored serve. Select \u003ccode\u003erl.checkpoint_format=consolidated\u003c/code\u003e if export is\nrequired and budget rank-0 host memory. \u003ccode\u003erl.export_*\u003c/code\u003e is not wired and is rejected.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eUnified chat template (\u003ccode\u003e--unified-chat-template\u003c/code\u003e).\u003c/strong\u003e The base ships two chat templates: \u003ccode\u003echat_template.json\u003c/code\u003e\n(the \u003cstrong\u003eprocessor template\u003c/strong\u003e, 5,614 chars, text sha256 \u003ccode\u003e97de86bf6ddb765a...\u003c/code\u003e) and \u003ccode\u003etokenizer_config.json\u003c/code\u003e's\n\u003ccode\u003echat_template\u003c/code\u003e (the \u003cstrong\u003etokenizer template\u003c/strong\u003e, 5,292 chars, \u003ccode\u003e3636d0f0bd6bef02...\u003c/code\u003e). They differ in what they\nrender for an assistant turn in the HISTORY: the processor template renders \u003ccode\u003ereasoning_content\u003c/code\u003e\n(\u003ccode\u003e\u0026lt;think\u0026gt;...\u0026lt;/think\u0026gt;\u003c/code\u003e) in every assistant turn, the tokenizer template renders none. vLLM 0.24 renders a\nrequest that carries a tools array with the tokenizer template (measured: a captured agent-harness request,\nreq_012, tokenizes to 8,946 ids on the default serve and to 8,969 with the processor template forced, the 23\nextra ids an earlier turn's think block; the first differing id sits at position 7,247, \u003ccode\u003e\u0026lt;think\u0026gt;\u003c/code\u003e vs\n\u003ccode\u003e\u0026lt;tool_call\u0026gt;\u003c/code\u003e). The materializer option writes BOTH template files of the export, \u003ccode\u003etokenizer_config.json\u003c/code\u003e's\n\u003ccode\u003echat_template\u003c/code\u003e and \u003ccode\u003echat_template.json\u003c/code\u003e's \u003ccode\u003echat_template\u003c/code\u003e, as the processor template in its CANONICAL form,\nevery other key of each file unchanged (every other line byte-equal when the base's file is a plain\n\u003ccode\u003ejson.dumps\u003c/code\u003e rendering, which both of the reference base's are). The \u003cstrong\u003ecanonical form\u003c/strong\u003e\n(\u003ccode\u003etemplate_mode: processor-canonical\u003c/code\u003e) is the processor template with ONE change in its reasoning branch,\n\u003ccode\u003e'\u0026lt;think\u0026gt;\\n' ~ (message.reasoning_content | trim) ~ '\\n\u0026lt;/think\u0026gt;\\n'\u003c/code\u003e instead of the untrimmed rendering: a\nreplayed reasoning string that arrives with a newline at both ends (the agent harness's form) then renders the\ncanonical block \u003ccode\u003e\u0026lt;think\u0026gt;\\n\u0026lt;text\u0026gt;\\n\u0026lt;/think\u0026gt;\\n\u003c/code\u003e, the student's own emission form, instead of the padded\n\u003ccode\u003e\u0026lt;think\u0026gt;\\n\\n\u0026lt;text\u0026gt;\\n\\n\u0026lt;/think\u0026gt;\\n\u003c/code\u003e (\u003ccode\u003econversion.hf.canonicalize_processor_template\u003c/code\u003e; a base whose processor\ntemplate lacks the exact line is refused). The marker records the processor template's sha, the shipped sha of\neach file (\u003ccode\u003eshipped\u003c/code\u003e) and the one-hunk diff under \u003ccode\u003echat_template\u003c/code\u003e (\u003ccode\u003etemplate_mode\u003c/code\u003e, \u003ccode\u003efiles\u003c/code\u003e, \u003ccode\u003ecanonical_diff\u003c/code\u003e;\nalso \u003ccode\u003eoptions.unified_chat_template\u003c/code\u003e and \u003ccode\u003esidecars.chat_template\u003c/code\u003e), makes the option part of the output's\nidentity (a request without it on such an output is refused until \u003ccode\u003e--force\u003c/code\u003e, and the reverse) and verifies\nboth files by rule instead of byte identity (\u003ccode\u003everify_sidecars\u003c/code\u003e: each file's mapping equals the base's on every\nkey but \u003ccode\u003echat_template\u003c/code\u003e, whose value is the canonical text; \u003ccode\u003everify_with_torch\u003c/code\u003e: the loaded tokenizer's and\nthe loaded processor's templates are that text). Default off: the default export stays byte-identical to the\nbase's sidecars. The rows for this template write \u003ccode\u003ereasoning_content\u003c/code\u003e as the model's TRIMMED reasoning text\n(the \u003ccode\u003estr.strip()\u003c/code\u003e of the model's reasoning bytes; the packer renders the base's own processor template, which\nyields the same canonical block for a stripped string, so training bytes are canonical with or without the\noption), and no-reasoning turns stay BARE, no think block (matching the student's measured emission and the\nserve's history form). Serving condition: \u003cstrong\u003eunified rows\u003c/strong\u003e (a term defined here: whole-episode rows in which\nevery assistant turn is supervised and the history turns carry their reasoning, the row shape of a unified\nexport's training set) are exact under ANY serve of a unified export and without a serve-side template flag:\nboth template files of a unified export carry the canonical text, so a request with or without tools renders\nthe same reasoning form (a tokenizer-only loader reads \u003ccode\u003etokenizer_config.json\u003c/code\u003e, a processor loader reads\n\u003ccode\u003echat_template.json\u003c/code\u003e). Two row conditions carry this claim, both measured on the captured request req_012: (a)\ntool-call \u003ccode\u003earguments\u003c/code\u003e travel in the row as the PARSED OBJECT, which the template renders through \u003ccode\u003etojson\u003c/code\u003e\n(\u003ccode\u003e{\"query\": \"value\"}\u003c/code\u003e, with \u003ccode\u003e\": \"\u003c/code\u003e and \u003ccode\u003e\", \"\u003c/code\u003e), exactly as the serve re-serialises the parsed arguments; a row\nthat keeps the model's compact JSON string (\u003ccode\u003e{\"query\":\"value\"}\u003c/code\u003e) renders it verbatim and differs from the\nserved prefix at the first argument (3 of 3 argument strings of req_012 differ from their re-serialised form);\nthe packer also accepts \u003ccode\u003earguments\u003c/code\u003e as a string and renders it verbatim, and such a string matches only when\nit equals \u003ccode\u003ejson.dumps(obj, ensure_ascii=False)\u003c/code\u003e of its parsed object (the \u003ccode\u003etojson\u003c/code\u003e form the serve emits): the\nmodel's compact string and \u003ccode\u003ejson.dumps(obj)\u003c/code\u003e with the default \u003ccode\u003eensure_ascii=True\u003c/code\u003e (non-ASCII escaped as\n\u003ccode\u003e\\uXXXX\u003c/code\u003e) both differ; (b) \u003ccode\u003ereasoning_content\u003c/code\u003e is the \u003ccode\u003estr.strip()\u003c/code\u003e of the model's reasoning bytes (Jinja's\n\u003ccode\u003etrim\u003c/code\u003e), not the text with one newline removed at each end: a trailing space or a second newline survives the\nlatter and breaks the match. Pins: the string-vs-object and whitespace cases of\n\u003ccode\u003etests/test_data_packer_sft.py::test_processor_canonical_template_trims_the_replayed_reasoning_where_the_verbatim_template_pads_it\u003c/code\u003e\n(the \u003ccode\u003eensure_ascii=True\u003c/code\u003e case included). Supported-base contract under the option: a base ships its templates\nin the two JSON files, \u003ccode\u003echat_template.json\u003c/code\u003e and \u003ccode\u003etokenizer_config.json\u003c/code\u003e's \u003ccode\u003echat_template\u003c/code\u003e, as the evidenced\nCosmos base does, and carries NO template sidecar a loader prefers over them; the materializer's preflight\nenforces it. The materializer's preflight is the torch-free set of checks in\n\u003ccode\u003echeckpoint/tools/materialize_hf.py\u003c/code\u003e that read the base alone before anything is removed or written (not the\ntrainer's preflight of section 2, which checks the training configuration). Read on transformers 4.57.6 and\n5.8.1, the two pinned versions, those are \u003ccode\u003echat_template.jinja\u003c/code\u003e (the tokenizer loader takes it over\n\u003ccode\u003etokenizer_config.json\u003c/code\u003e's key; the processor loader reads it only when \u003ccode\u003echat_template.json\u003c/code\u003e is absent), the\n\u003ccode\u003eadditional_chat_templates/\u003c/code\u003e directory (named templates the tokenizer loader prefers over the key; beside\n\u003ccode\u003echat_template.json\u003c/code\u003e the processor loader refuses the combination; the directory is refused whatever it holds,\nempty or with nested directories only included, by the one helper the materializer's preflight and\n\u003ccode\u003everify_sidecars\u003c/code\u003e share: both loaders discover named templates with \u003ccode\u003eglob(\"*.jinja\")\u003c/code\u003e and ignore an empty\ndirectory, and the rule still refuses it, fail closed) and a \u003ccode\u003echat_template\u003c/code\u003e key in \u003ccode\u003eprocessor_config.json\u003c/code\u003e\n(the processor loader prefers it on 5.8.1). With such a sidecar the export would ship both canonical JSON\nfiles while \u003ccode\u003eAutoTokenizer\u003c/code\u003e renders the sidecar, so the materializer REFUSES the base in unified mode before\nanything is published, with or without \u003ccode\u003e--no-verify\u003c/code\u003e, naming the file. That refusal is part of the\nmaterializer's preflight, which runs before any destructive step: under \u003ccode\u003e--force\u003c/code\u003e the existing output is\nremoved, \u003ccode\u003e\u0026lt;out\u0026gt;.tmp\u003c/code\u003e created and the overlay run only after it has passed, so a refused request leaves the\nexisting output byte-identical. The same preflight also parses every JSON sidecar of the base\n(\u003ccode\u003etokenizer_config.json\u003c/code\u003e and \u003ccode\u003echat_template.json\u003c/code\u003e as objects; the overlay and the template record read them\nafter the overlay), refuses in the default path an \u003ccode\u003eadditional_chat_templates/\u003c/code\u003e whose entries are not all\nregular files (the default path copies the directory verbatim and its verifier refuses a sub-directory), and\nturns an unreadable base into a named refusal instead of a traceback (fixtures\n\u003ccode\u003etests/test_checkpoint_materialize_hf.py::test_force_rebuild_keeps_the_existing_output_when_a_base_json_sidecar_does_not_parse\u003c/code\u003e,\n\u003ccode\u003e::test_default_preflight_refuses_a_named_template_directory_with_entries_that_are_not_regular_files\u003c/code\u003e and\n\u003ccode\u003e::test_preflight_refuses_an_unreadable_base_with_a_named_reason_instead_of_a_traceback\u003c/code\u003e). The same preflight\nalso runs on every base shard the index lists the safetensors header check the output gets\n(\u003ccode\u003econversion.hf.shard_status\u003c/code\u003e: present, readable, header parsed, size = 8 + header + data, header keys = the\ntensors the index maps to it), because the overlay's \u003ccode\u003efrom_pretrained\u003c/code\u003e opens every shard in the staged build\nand a shard truncated by one byte, with a garbage header or unreadable would otherwise pass (the identity\nrecords sizes only); requires every JSON sidecar of the base to be a JSON object and \u003ccode\u003echat_template.json\u003c/code\u003e,\nwhen present, to carry a non-empty \u003ccode\u003echat_template\u003c/code\u003e string (the loaders index these after the overlay: a \u003ccode\u003e[]\u003c/code\u003e\nsidecar fails \u003ccode\u003eAutoProcessor\u003c/code\u003e / \u003ccode\u003eGenerationConfig\u003c/code\u003e and a \u003ccode\u003e{}\u003c/code\u003e template file is the processor loader's\nKeyError, read on the container's transformers 5.13.0); validates the index's \u003ccode\u003eweight_map\u003c/code\u003e (a non-empty object\nof tensor name -\u0026gt; shard name, so no index shape escapes as AttributeError / TypeError); and raises every\nrefusal in the one message family\n\u003ccode\u003eREFUSED before anything is published: \u0026lt;what was found; what the staged build would have done with it\u0026gt;\u003c/code\u003e\n(fixtures\n\u003ccode\u003e::test_preflight_refuses_a_base_shard_the_safetensors_header_check_rejects_before_anything_is_removed\u003c/code\u003e,\n\u003ccode\u003e::test_preflight_refuses_a_json_sidecar_the_loaders_reject_although_it_parses\u003c/code\u003e,\n\u003ccode\u003e::test_preflight_refuses_an_index_whose_weight_map_is_not_tensor_to_shard_names_without_a_traceback\u003c/code\u003e and\n\u003ccode\u003e::test_every_preflight_refusal_is_in_the_one_message_family_and_names_what_it_found\u003c/code\u003e). ONE JSON decoder\nserves the whole preflight and the materializer's own readers (\u003ccode\u003econversion.hf.decode_json_bytes\u003c/code\u003e: strict UTF-8\ntext, what \u003ccode\u003emodel_identity\u003c/code\u003e, \u003ccode\u003e_read_json_file\u003c/code\u003e and transformers' loaders decode in the staged build), so a\nUTF-8 byte-order mark in front of valid JSON (config.json, any JSON sidecar, the index) is refused by name\ninstead of passing through \u003ccode\u003ejson.loads(bytes)\u003c/code\u003e, which strips it (on the reference base's files a leading mark\nfails AutoConfig, AutoProcessor, AutoTokenizer and GenerationConfig: \u003ccode\u003eUnexpected UTF-8 BOM\u003c/code\u003e /\n\u003ccode\u003enot a valid JSON file\u003c/code\u003e); and \u003ccode\u003eshard_status\u003c/code\u003e validates the safetensors header's shape (a JSON object of tensor\nentries with a dtype string, a shape list and \u003ccode\u003edata_offsets\u003c/code\u003e of two non-negative integers begin \u0026lt;= end, an\noptional \u003ccode\u003e__metadata__\u003c/code\u003e object), so a malformed header is a named refusal in the preflight and a named failure\nof the output verifier, never a traceback (fixtures\n\u003ccode\u003e::test_preflight_refuses_a_utf8_byte_order_mark_in_front_of_valid_json_as_the_loaders_do\u003c/code\u003e and\n\u003ccode\u003e::test_shard_status_refuses_a_header_without_the_safetensors_shape_and_the_preflight_names_it\u003c/code\u003e). The\nconstruction is STAGED. The whole build happens in \u003ccode\u003e\u0026lt;out\u0026gt;.tmp\u003c/code\u003e beside an existing output: the overlay (the\nbase read by its real readers: the pinned safetensors reader on every shard, transformers on the sidecars),\nthe sidecar sync, \u003ccode\u003econfig.json \u0026lt;- base\u003c/code\u003e, the verification (index, sidecars and, unless \u003ccode\u003e--no-verify\u003c/code\u003e, the\ntorch probe, all on the staged copy) and the \u003ccode\u003e.materialized\u003c/code\u003e marker, the last file written there (its\nsemantics unchanged); only then the swap replaces the existing output by renames (\u003ccode\u003e\u0026lt;out\u0026gt;\u003c/code\u003e -\u0026gt; \u003ccode\u003e\u0026lt;out\u0026gt;.previous\u003c/code\u003e,\n\u003ccode\u003e\u0026lt;out\u0026gt;.tmp\u003c/code\u003e -\u0026gt; \u003ccode\u003e\u0026lt;out\u0026gt;\u003c/code\u003e, \u003ccode\u003e\u0026lt;out\u0026gt;.previous\u003c/code\u003e removed; \u003ccode\u003ematerialize_hf.publish_staging\u003c/code\u003e). On any failure before the\nswap the staging directory is removed, the error names its stage and the existing output is byte-identical,\nunder \u003ccode\u003e--force --no-verify\u003c/code\u003e too. Transient disk: two exports side by side from the overlay to the swap (the\nstaged shards are written by \u003ccode\u003esave_pretrained\u003c/code\u003e, not linked). A leftover \u003ccode\u003e\u0026lt;out\u0026gt;.previous\u003c/code\u003e is refused before the\nbuild unless \u003ccode\u003e--force\u003c/code\u003e, which discards it. Before the staging, the same preflight asks the pinned safetensors\nreader itself (\u003ccode\u003econversion.hf.safetensors_reader_error\u003c/code\u003e: \u003ccode\u003esafe_open\u003c/code\u003e on the header of every base shard the\nindex lists; dtype names, string metadata values, contiguous offsets, byte count per tensor, file length: a\nBF16 \u003ccode\u003e[3]\u003c/code\u003e tensor over four bytes, an unknown dtype, a non-string metadata value and an offset gap all passed\nthe shape check) and decodes, strictly as UTF-8, every Jinja template the tokenizer and processor loaders read\n(\u003ccode\u003echat_template.jinja\u003c/code\u003e and each \u003ccode\u003eadditional_chat_templates/*.jinja\u003c/code\u003e named template;\n\u003ccode\u003econversion.hf.loader_template_files\u003c/code\u003e cites the loader lines), refusing by file and reader message / decode\nposition in the one family (fixtures\n\u003ccode\u003e::test_preflight_refuses_a_base_shard_the_pinned_safetensors_reader_rejects_and_keeps_the_export\u003c/code\u003e,\n\u003ccode\u003e::test_preflight_decodes_the_jinja_templates_the_loaders_read_as_strict_utf8_and_keeps_the_export\u003c/code\u003e,\n\u003ccode\u003e::test_a_failure_after_the_preflight_keeps_the_existing_export_and_removes_the_staging_directory\u003c/code\u003e,\n\u003ccode\u003e::test_the_swap_publishes_by_rename_and_a_leftover_previous_output_is_refused_without_force\u003c/code\u003e and\n\u003ccode\u003e::test_preflight_refuses_when_the_pinned_safetensors_reader_cannot_be_imported\u003c/code\u003e). Under \u003ccode\u003e--force\u003c/code\u003e no complete\nmarked tree is discarded while it is the only one: in the crash state between the swap's two renames\n(\u003ccode\u003e\u0026lt;out\u0026gt;.previous\u003c/code\u003e = the old export, \u003ccode\u003e\u0026lt;out\u0026gt;.tmp\u003c/code\u003e = the new one complete and marked, no \u003ccode\u003e\u0026lt;out\u0026gt;\u003c/code\u003e)\n\u003ccode\u003e\u0026lt;out\u0026gt;.previous\u003c/code\u003e is renamed back to \u003ccode\u003e\u0026lt;out\u0026gt;\u003c/code\u003e first and the build happens beside it; a leftover \u003ccode\u003e\u0026lt;out\u0026gt;.previous\u003c/code\u003e\nbeside an existing \u003ccode\u003e\u0026lt;out\u0026gt;\u003c/code\u003e is removed at the swap, after the new tree is verified. \u003ccode\u003e--force\u003c/code\u003e rebuilds from the\nsource; a death-left \u003ccode\u003e\u0026lt;out\u0026gt;.tmp\u003c/code\u003e is discarded once \u003ccode\u003e\u0026lt;out\u0026gt;\u003c/code\u003e is complete again whatever its marker says (a\nmarker match covers the identity, the shard sizes and tensor counts, not the shard bytes, and the base digest\nexcludes the base shards' bytes), a complete marked \u003ccode\u003e\u0026lt;out\u0026gt;.tmp\u003c/code\u003e that is the only complete tree is refused by\nname rather than discarded, and a kept staged copy is published only by a request without \u003ccode\u003e--force\u003c/code\u003e, after the\nsame verification as a fresh build (index, sidecars, the torch probe unless \u003ccode\u003e--no-verify\u003c/code\u003e, which trusts the\nkept copy's bytes on size and tensor count). One materializer per output: \u003ccode\u003e\u0026lt;out\u0026gt;.lock\u003c/code\u003e beside the output, held\nwith \u003ccode\u003efcntl.flock\u003c/code\u003e from before the staging to after the swap; a second materializer on the same \u003ccode\u003e--out\u003c/code\u003e is\nrefused by name (pid, host, start time of the holder) without touching anything; the lock file stays beside\nthe output (it is not part of the export) and the file system must support flock (Lustre: the \u003ccode\u003eflock\u003c/code\u003e mount\noption; a mount that refuses it is a named refusal). Fixtures\n\u003ccode\u003e::test_force_after_a_death_between_the_swap_renames_restores_the_old_export_before_building\u003c/code\u003e,\n\u003ccode\u003e::test_two_materializers_on_one_output_exclude_each_other_through_the_per_output_lock\u003c/code\u003e,\n\u003ccode\u003e::test_the_per_output_lock_refuses_by_name_in_process_and_fails_closed_without_flock\u003c/code\u003e,\n\u003ccode\u003e::test_force_rebuilds_from_the_source_instead_of_publishing_a_death_left_copy\u003c/code\u003e and\n\u003ccode\u003e::test_a_death_left_copy_is_published_only_by_a_request_without_force_after_verification\u003c/code\u003e. An inherited sole\ncomplete marked \u003ccode\u003e\u0026lt;out\u0026gt;.tmp\u003c/code\u003e (a first publication that died after \u003ccode\u003e.materialized\u003c/code\u003e and before the rename) is\nnever deleted: the unforced recovery checks its marker against the request (else refused by name), repairs a\nmissing staged \u003ccode\u003econfig.json\u003c/code\u003e from the base through a temporary file and a rename, re-syncs the sidecars the\nsame way (never a shard), then verifies, re-marks and swaps; a failed recovery check refuses by name and KEEPS\nthe tree (its shards and its marker untouched, its sidecars possibly repaired from the base before the check:\nconfig.json rewritten, a differing one kept as \u003ccode\u003econfig.json.trainer.bak\u003c/code\u003e, a stray sidecar removed, a\n\u003ccode\u003e.copying\u003c/code\u003e or \u003ccode\u003e.writing\u003c/code\u003e temporary left by an interrupted copy or unified-template rewrite, and under\n\u003ccode\u003e--unified-chat-template\u003c/code\u003e the two template files back in the base's form when that rewrite did not reach its\nrename; the refusal says so and names the state at \u003ccode\u003e\u0026lt;out\u0026gt;\u003c/code\u003e: absent, standing but not a complete marked export,\nor a complete marked export), and the overlay is never run while the copy is the sole complete tree. The\nmarker / skip / mismatch decision is taken under the per-output lock, so a materializer that paused before the\nlock while another published a different source is refused on that export's marker instead of overwriting it;\na held lock is waited for up to 120 s (\u003ccode\u003e--lock-wait-seconds\u003c/code\u003e, polling), so two simultaneous identical requests\nof a published source both end with 0 (the second skips once the holder has finished), a differing request is\nrefused on the marker, and a holder still there after the bound is refused by name with the bound stated.\nFixtures: \u003ccode\u003e::test_a_failed_recovery_check_leaves_the_inherited_sole_marked_copy_as_found\u003c/code\u003e,\n\u003ccode\u003e::test_the_marker_decision_is_taken_under_the_output_lock_so_a_paused_materializer_cannot_overwrite_a_newer_export\u003c/code\u003e,\n\u003ccode\u003e::test_a_repair_then_failed_recovery_check_keeps_the_shards_and_the_marker_and_says_what_it_changed\u003c/code\u003e,\n\u003ccode\u003e::test_an_identical_request_waits_for_the_lock_holder_and_skips_with_0\u003c/code\u003e,\n\u003ccode\u003e::test_the_lock_wait_is_bounded_and_the_refusal_names_the_bound\u003c/code\u003e and\n\u003ccode\u003e::test_a_failed_unified_rewrite_during_recovery_leaves_the_writing_temporary_and_the_refusal_names_it\u003c/code\u003e; the\nlock bound must be a finite number \u0026gt;= 0 (\u003ccode\u003einf\u003c/code\u003e and \u003ccode\u003enan\u003c/code\u003e are refused by name:\n\u003ccode\u003e::test_lock_wait_seconds_refuses_non_finite_values\u003c/code\u003e). The source's identity of record (sha256 + bytes of\n\u003ccode\u003emodel.pt\u003c/code\u003e) is read UNDER the output lock, not before the wait, through a file object opened once there, and\nthe overlay memory-maps that SAME open file (through \u003ccode\u003e/proc/self/fd\u003c/code\u003e; where that reference does not exist the\nloader reads the payload whole through the file object, no mmap, with the whole payload in RAM), so by\nconstruction the skip / mismatch decision, the source record and the marker name the bytes the overlay\nconsumed, and the default verification (the torch probe) compares the staged shards against that same open\nfile (a path replaced during the overlay can neither fail a correct build nor pass a wrong one), whatever the\npath names meanwhile: the merge tool (tmp + os.replace over \u003ccode\u003emodel.pt\u003c/code\u003e) is not excluded by the lock and may\nreplace the path while the request waits (adopted with a WARNING naming both hashes) or while the overlay runs\n(logged; nothing of what was built changes). The opened inode is fstat'd before the hash and after the\noverlay: a change of its size or mtime refuses the build by name, with no \"same bytes\" acceptance, since the\ndigest of the file after the fact does not say what a reader consumed; that check is best effort against a\nwriter into the opened inode (a client may report an open inode's attributes late), which the merge tool never\nis: the guarantee of record is against a replaced path, by construction (fixtures\n\u003ccode\u003e::test_the_marker_records_the_source_the_overlay_read_when_the_source_changes_during_the_lock_wait\u003c/code\u003e,\n\u003ccode\u003e::test_a_source_replaced_during_the_overlay_does_not_change_what_was_built_or_recorded\u003c/code\u003e,\n\u003ccode\u003e::test_the_marker_names_the_bytes_the_overlay_consumed_when_forced_merges_race_the_overlay\u003c/code\u003e with the real\nmerge tool, \u003ccode\u003e::test_the_default_verification_receives_the_held_payload\u003c/code\u003e, the verification suite's\n\u003ccode\u003etest_checkpoint_hf_verification.py::test_default_verification_consumes_the_held_payload_when_the_path_is_replaced\u003c/code\u003e\nwith the real merge tool and the real torch verifier, and the loader's\n\u003ccode\u003etest_checkpoint_hf_overlay.py::test_load_consolidated_state_dict_reads_the_open_file_not_the_path\u003c/code\u003e). The\nweights-free loader calls themselves (\u003ccode\u003eAutoProcessor\u003c/code\u003e / \u003ccode\u003eAutoTokenizer\u003c/code\u003e / \u003ccode\u003eGenerationConfig\u003c/code\u003e \u003ccode\u003efrom_pretrained\u003c/code\u003e\non the base) are NOT part of the preflight, by design: they are not torch-free (the processor instantiates the\nimage and video processors, which import torch), their verdicts depend on the installed transformers rather\nthan on the files, and the synthetic bases of the tests are not loadable by them; a base that passes every\nfile check but fails a loader on a schema fact the files do not state (\u003ccode\u003etokenizer.json\u003c/code\u003e = \u003ccode\u003e{}\u003c/code\u003e, a\n\u003ccode\u003epreprocessor_config.json\u003c/code\u003e without \u003ccode\u003eimage_processor_type\u003c/code\u003e) is still refused by the overlay, in the staged\nbuild, with the existing output kept. A \u003ccode\u003echat_template.jinja\u003c/code\u003e (or a \u003ccode\u003eprocessor_config.json\u003c/code\u003e key) whose text\nequals the canonical text is allowed, synced verbatim and recorded under \u003ccode\u003echat_template.preferred_sidecars\u003c/code\u003e;\n\u003ccode\u003everify_sidecars\u003c/code\u003e applies the same rule to the export. Fixtures:\n\u003ccode\u003etests/test_checkpoint_materialize_hf.py::test_unified_chat_template_refuses_a_base_whose_preferred_template_sidecar_diverges\u003c/code\u003e\nand \u003ccode\u003etests/test_data_packer_sft.py::test_unified_export_tokenizer_loads_the_canonical_text_and_a_divergent_jinja_sidecar_is_refused\u003c/code\u003e\n(a real tokenizer load from a unified export of a toy base: canonical; with the Jinja beside it: the Jinja);\nthe directory rule and the preflight order:\n\u003ccode\u003etests/test_checkpoint_materialize_hf.py::test_unified_template_directory_rule_is_one_helper_for_preflight_and_verifier\u003c/code\u003e\nand \u003ccode\u003etests/test_checkpoint_materialize_hf.py::test_force_rebuild_keeps_the_existing_output_when_a_torch_free_preflight_refuses\u003c/code\u003e.\nPrefix rows (section 4) are exact under the default serve of a default export. Offline proof on the real\nbase's sidecars: the tokenizer loaded from a unified scratch export renders req_012 (messages normalised as\nvLLM does: \u003ccode\u003edeveloper\u003c/code\u003e to \u003ccode\u003esystem\u003c/code\u003e, \u003ccode\u003econtent: null\u003c/code\u003e to \u003ccode\u003e\"\"\u003c/code\u003e, \u003ccode\u003ereasoning\u003c/code\u003e as \u003ccode\u003ereasoning_content\u003c/code\u003e, argument\nstrings parsed, the image placeholder expanded to its 209 tokens; its two replayed reasoning strings begin and\nend with a newline) to 8,969 ids with positions 7248, 7254, 8016, 8025 reading 198, 624, 198, 624 (the\nstripped form: \u003ccode\u003e\\n\u003c/code\u003e and \u003ccode\u003e.\\n\u003c/code\u003e); the verbatim processor template renders 8,969 ids with 271, 382, 271, 382 at\nthe same positions (the padded form: \u003ccode\u003e\\n\\n\u003c/code\u003e and \u003ccode\u003e.\\n\\n\u003c/code\u003e), pinned beside it; the base's tokenizer renders\n8,946. Consequence: the shared-vocabulary identity of \u003ccode\u003econfig/build.py\u003c/code\u003e hashes the tokenizer's\n\u003ccode\u003echat_template\u003c/code\u003e, so a unified export is not an OPD teacher for a student loaded from the default sidecars (and\nthe reverse); pair teacher and student on the same choice. Serve assumption, recorded in \u003ccode\u003e.materialized\u003c/code\u003e\nbeside the shas (\u003ccode\u003echat_template.serve_assumption\u003c/code\u003e): the serve sets no \u003ccode\u003eenable_thinking\u003c/code\u003e. Under the unified\ntemplate a request that sets \u003ccode\u003eenable_thinking=true\u003c/code\u003e is prefilled with the opener token itself,\n\u003ccode\u003e\u0026lt;|im_start|\u0026gt;assistant\\n\u0026lt;think\u0026gt;\u003c/code\u003e (id 151667, no newline after it: 251 vs 250 ids; the same tail without tools,\n\u003ccode\u003e\\n\u003c/code\u003e, \u003ccode\u003e\u0026lt;|im_start|\u0026gt;\u003c/code\u003e, \u003ccode\u003eassistant\u003c/code\u003e, \u003ccode\u003e\\n\u003c/code\u003e, \u003ccode\u003e\u0026lt;think\u0026gt;\u003c/code\u003e, 10 ids against 9), while the rows supervise the opener as\nthe student's first token; under such a serve \u003ccode\u003erl.mask_think_opener=True\u003c/code\u003e masks exactly that one token and the\nsupervised target begins with the newline that opens the reasoning text (the rule of an \u003ccode\u003eopener: prefilled\u003c/code\u003e\nrow, section 4). The agent harness sends no \u003ccode\u003eenable_thinking\u003c/code\u003e, and the student's serve recipe must not set it.\nFixtures:\n\u003ccode\u003etests/test_checkpoint_materialize_hf.py::test_unified_chat_template_rewrites_the_tokenizer_template_only_and_is_verified_by_rule\u003c/code\u003e\nand \u003ccode\u003etest_main_unified_chat_template_option_identity_and_skip\u003c/code\u003e; the padded and stripped forms side by side on\nthe official template through the toy tokenizer (same count, \u003ccode\u003e\\n\\n\u003c/code\u003e tokens become \u003ccode\u003e\\n\u003c/code\u003e tokens; a trimmed\nstring renders identically under both):\n\u003ccode\u003etests/test_data_packer_sft.py::test_processor_canonical_template_trims_the_replayed_reasoning_where_the_verbatim_template_pads_it\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e8. Extension points\u003c/h2\u003e\u003ca id=\"user-content-8-extension-points\" class=\"anchor\" aria-label=\"Permalink: 8. Extension points\" href=\"#8-extension-points\"\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\"\u003eKeep tensor shaping in \u003ccode\u003edata/packer/sft.py\u003c/code\u003e, objective math in \u003ccode\u003ealgorithm/sft.py\u003c/code\u003e, model\nadaptation in \u003ccode\u003emodel/qwen3_5.py\u003c/code\u003e, and lifecycle orchestration in \u003ccode\u003eentrypoints/sft.py\u003c/code\u003e.\u003c/p\u003e\n\u003c/article\u003e","richTextTruncated":false,"renderedFileInfo":null,"symbols":{"timed_out":false,"not_analyzed":false,"symbols":[{"name":"SFT","fully_qualified_name":"SFT","kind":"section_1","ident_start":2,"ident_end":5,"extent_start":0,"extent_end":49576,"ident_utf16":{"start":{"line_number":0,"utf16_col":2},"end":{"line_number":0,"utf16_col":5}},"extent_utf16":{"start":{"line_number":0,"utf16_col":0},"end":{"line_number":555,"utf16_col":0}}},{"name":"1. When to choose it","fully_qualified_name":"1. When to choose it","kind":"section_2","ident_start":10,"ident_end":30,"extent_start":7,"extent_end":2029,"ident_utf16":{"start":{"line_number":2,"utf16_col":3},"end":{"line_number":2,"utf16_col":23}},"extent_utf16":{"start":{"line_number":2,"utf16_col":0},"end":{"line_number":27,"utf16_col":0}}},{"name":"2. Quick start","fully_qualified_name":"2. Quick start","kind":"section_2","ident_start":2032,"ident_end":2046,"extent_start":2029,"extent_end":4875,"ident_utf16":{"start":{"line_number":27,"utf16_col":3},"end":{"line_number":27,"utf16_col":17}},"extent_utf16":{"start":{"line_number":27,"utf16_col":0},"end":{"line_number":73,"utf16_col":0}}},{"name":"3. Data contract","fully_qualified_name":"3. Data contract","kind":"section_2","ident_start":4878,"ident_end":4894,"extent_start":4875,"extent_end":7097,"ident_utf16":{"start":{"line_number":73,"utf16_col":3},"end":{"line_number":73,"utf16_col":19}},"extent_utf16":{"start":{"line_number":73,"utf16_col":0},"end":{"line_number":103,"utf16_col":0}}},{"name":"4. Objective and masking","fully_qualified_name":"4. Objective and masking","kind":"section_2","ident_start":7100,"ident_end":7124,"extent_start":7097,"extent_end":18916,"ident_utf16":{"start":{"line_number":103,"utf16_col":3},"end":{"line_number":103,"utf16_col":27}},"extent_utf16":{"start":{"line_number":103,"utf16_col":0},"end":{"line_number":236,"utf16_col":0}}},{"name":"5. Main knobs","fully_qualified_name":"5. Main knobs","kind":"section_2","ident_start":18919,"ident_end":18932,"extent_start":18916,"extent_end":22935,"ident_utf16":{"start":{"line_number":236,"utf16_col":3},"end":{"line_number":236,"utf16_col":16}},"extent_utf16":{"start":{"line_number":236,"utf16_col":0},"end":{"line_number":283,"utf16_col":0}}},{"name":"6. Metrics and validation","fully_qualified_name":"6. Metrics and validation","kind":"section_2","ident_start":22938,"ident_end":22963,"extent_start":22935,"extent_end":25014,"ident_utf16":{"start":{"line_number":283,"utf16_col":3},"end":{"line_number":283,"utf16_col":28}},"extent_utf16":{"start":{"line_number":283,"utf16_col":0},"end":{"line_number":309,"utf16_col":0}}},{"name":"7. Checkpoints, resume and export","fully_qualified_name":"7. Checkpoints, resume and export","kind":"section_2","ident_start":25017,"ident_end":25050,"extent_start":25014,"extent_end":49376,"ident_utf16":{"start":{"line_number":309,"utf16_col":3},"end":{"line_number":309,"utf16_col":36}},"extent_utf16":{"start":{"line_number":309,"utf16_col":0},"end":{"line_number":551,"utf16_col":0}}},{"name":"8. Extension points","fully_qualified_name":"8. Extension points","kind":"section_2","ident_start":49379,"ident_end":49398,"extent_start":49376,"extent_end":49576,"ident_utf16":{"start":{"line_number":551,"utf16_col":3},"end":{"line_number":551,"utf16_col":22}},"extent_utf16":{"start":{"line_number":551,"utf16_col":0},"end":{"line_number":555,"utf16_col":0}}}]}},"codeViewLayoutRoute":{"repo":{"id":1243757086,"defaultBranch":"main","name":"cosmos-framework","ownerLogin":"NVIDIA","currentUserCanPush":false,"isFork":false,"isEmpty":false,"createdAt":"2026-05-19T16:27:26.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/1728152?v=4","public":true,"private":false,"isOrgOwned":true,"isArchived":false},"currentUser":null,"uploadToken":"7urOAA8lFC_HOC4keLMzhwv5eWnsMOzuRc59V5HEYBwwYgrvW1UHxgyB41Y-GVob2LAl4lWfHYnEmRr-IE813Q","allShortcutsEnabled":false,"treeExpanded":true,"path":"docs/posttrain/guides/sft.md","symbolsExpanded":false,"refInfo":{"name":"main","listCacheKey":"v0:1792737840.0","canEdit":false,"currentOid":"9214f43fadef00919c07853c8fa1c2e7d75444e1"},"helpUrl":"https://docs.github.com","githubDevUrl":null},"codeViewFileTreeLayoutRoute":{"fileTree":{"docs/posttrain/guides":{"items":[{"name":"dpo.md","path":"docs/posttrain/guides/dpo.md","contentType":"file"},{"name":"grpo.md","path":"docs/posttrain/guides/grpo.md","contentType":"file"},{"name":"joint-ppo-gr00t-public.md","path":"docs/posttrain/guides/joint-ppo-gr00t-public.md","contentType":"file"},{"name":"joint-ppo-pi05-public.md","path":"docs/posttrain/guides/joint-ppo-pi05-public.md","contentType":"file"},{"name":"nft.md","path":"docs/posttrain/guides/nft.md","contentType":"file"},{"name":"opd.md","path":"docs/posttrain/guides/opd.md","contentType":"file"},{"name":"ppo.md","path":"docs/posttrain/guides/ppo.md","contentType":"file"},{"name":"sft.md","path":"docs/posttrain/guides/sft.md","contentType":"file"}],"totalCount":8},"docs/posttrain":{"items":[{"name":"guides","path":"docs/posttrain/guides","contentType":"directory"},{"name":"howto","path":"docs/posttrain/howto","contentType":"directory"},{"name":"reference","path":"docs/posttrain/reference","contentType":"directory"},{"name":"README.md","path":"docs/posttrain/README.md","contentType":"file"},{"name":"glossary.md","path":"docs/posttrain/glossary.md","contentType":"file"},{"name":"index.md","path":"docs/posttrain/index.md","contentType":"file"},{"name":"troubleshooting.md","path":"docs/posttrain/troubleshooting.md","contentType":"file"}],"totalCount":7},"docs":{"items":[{"name":"deploy","path":"docs/deploy","contentType":"directory"},{"name":"get_started","path":"docs/get_started","contentType":"directory"},{"name":"models","path":"docs/models","contentType":"directory"},{"name":"post_training","path":"docs/post_training","contentType":"directory"},{"name":"posttrain","path":"docs/posttrain","contentType":"directory"},{"name":".gitkeep","path":"docs/.gitkeep","contentType":"file"},{"name":"README.md","path":"docs/README.md","contentType":"file"},{"name":"action_fd_droid_posttrain.md","path":"docs/action_fd_droid_posttrain.md","contentType":"file"},{"name":"action_policy_droid_posttrain.md","path":"docs/action_policy_droid_posttrain.md","contentType":"file"},{"name":"action_policy_droid_server.md","path":"docs/action_policy_droid_server.md","contentType":"file"},{"name":"action_policy_libero_posttrain.md","path":"docs/action_policy_libero_posttrain.md","contentType":"file"},{"name":"automl-algorithms.md","path":"docs/automl-algorithms.md","contentType":"file"},{"name":"automl-platforms.md","path":"docs/automl-platforms.md","contentType":"file"},{"name":"automl-prompts.md","path":"docs/automl-prompts.md","contentType":"file"},{"name":"automl-slurm.md","path":"docs/automl-slurm.md","contentType":"file"},{"name":"automl.md","path":"docs/automl.md","contentType":"file"},{"name":"bimanual_data_preflight.md","path":"docs/bimanual_data_preflight.md","contentType":"file"},{"name":"bimanual_sessions.md","path":"docs/bimanual_sessions.md","contentType":"file"},{"name":"code_structure.md","path":"docs/code_structure.md","contentType":"file"},{"name":"custom_dataset.md","path":"docs/custom_dataset.md","contentType":"file"},{"name":"dataset_jsonl.md","path":"docs/dataset_jsonl.md","contentType":"file"},{"name":"environment_variables.md","path":"docs/environment_variables.md","contentType":"file"},{"name":"evaluation.md","path":"docs/evaluation.md","contentType":"file"},{"name":"faq.md","path":"docs/faq.md","contentType":"file"},{"name":"inference.md","path":"docs/inference.md","contentType":"file"},{"name":"inference_auto.md","path":"docs/inference_auto.md","contentType":"file"},{"name":"inference_bimanual.md","path":"docs/inference_bimanual.md","contentType":"file"},{"name":"inference_sim_auto.md","path":"docs/inference_sim_auto.md","contentType":"file"},{"name":"inference_transfer.md","path":"docs/inference_transfer.md","contentType":"file"},{"name":"prompt_upsampling.md","path":"docs/prompt_upsampling.md","contentType":"file"},{"name":"setup.md","path":"docs/setup.md","contentType":"file"},{"name":"sft_config.md","path":"docs/sft_config.md","contentType":"file"},{"name":"training.md","path":"docs/training.md","contentType":"file"},{"name":"training_sim_auto.md","path":"docs/training_sim_auto.md","contentType":"file"},{"name":"training_sim_transfer_stage0.md","path":"docs/training_sim_transfer_stage0.md","contentType":"file"},{"name":"training_transfer_auto.md","path":"docs/training_transfer_auto.md","contentType":"file"},{"name":"transfer_numerical_preservation.md","path":"docs/transfer_numerical_preservation.md","contentType":"file"}],"totalCount":37},"":{"items":[{"name":".agents","path":".agents","contentType":"directory"},{"name":".claude","path":".claude","contentType":"directory"},{"name":".config","path":".config","contentType":"directory"},{"name":".github","path":".github","contentType":"directory"},{"name":"ci","path":"ci","contentType":"directory"},{"name":"cosmos_framework","path":"cosmos_framework","contentType":"directory"},{"name":"docker","path":"docker","contentType":"directory"},{"name":"docs","path":"docs","contentType":"directory"},{"name":"examples","path":"examples","contentType":"directory"},{"name":"inputs","path":"inputs","contentType":"directory"},{"name":"packages","path":"packages","contentType":"directory"},{"name":"tests","path":"tests","contentType":"directory"},{"name":"tools","path":"tools","contentType":"directory"},{"name":".coveragerc","path":".coveragerc","contentType":"file"},{"name":".dockerignore","path":".dockerignore","contentType":"file"},{"name":".file_mapping.json","path":".file_mapping.json","contentType":"file"},{"name":".gitattributes","path":".gitattributes","contentType":"file"},{"name":".gitignore","path":".gitignore","contentType":"file"},{"name":".gitleaks.toml","path":".gitleaks.toml","contentType":"file"},{"name":".posttrain_file_mapping.json","path":".posttrain_file_mapping.json","contentType":"file"},{"name":".pre-commit-config.yaml","path":".pre-commit-config.yaml","contentType":"file"},{"name":".pytest.toml","path":".pytest.toml","contentType":"file"},{"name":".python-version","path":".python-version","contentType":"file"},{"name":".ruff.toml","path":".ruff.toml","contentType":"file"},{"name":"AGENTS.md","path":"AGENTS.md","contentType":"file"},{"name":"ATTRIBUTIONS.md","path":"ATTRIBUTIONS.md","contentType":"file"},{"name":"CHANGELOG.md","path":"CHANGELOG.md","contentType":"file"},{"name":"CONTRIBUTING.md","path":"CONTRIBUTING.md","contentType":"file"},{"name":"Dockerfile","path":"Dockerfile","contentType":"file"},{"name":"LICENSE","path":"LICENSE","contentType":"file"},{"name":"NOTICE","path":"NOTICE","contentType":"file"},{"name":"README.md","path":"README.md","contentType":"file"},{"name":"RELEASE.md","path":"RELEASE.md","contentType":"file"},{"name":"SECURITY.md","path":"SECURITY.md","contentType":"file"},{"name":"conftest.py","path":"conftest.py","contentType":"file"},{"name":"justfile","path":"justfile","contentType":"file"},{"name":"pyproject.toml","path":"pyproject.toml","contentType":"file"},{"name":"pyrefly.toml","path":"pyrefly.toml","contentType":"file"},{"name":"sitecustomize.py","path":"sitecustomize.py","contentType":"file"},{"name":"uv.lock","path":"uv.lock","contentType":"file"}],"totalCount":40}},"fileTreeProcessingTime":41.499744,"foldersToFetch":[],"refName":"main"},"codeViewBlobLayoutRoute":{"codeLineWrapEnabled":false,"refInfo":{"name":"main","listCacheKey":"v0:1792737840.0","canEdit":false,"refType":"branch","currentOid":"9214f43fadef00919c07853c8fa1c2e7d75444e1","canEditOnDefaultBranch":false,"fileExistsOnDefault":true},"path":"docs/posttrain/guides/sft.md","blob":{"copilotSWEAgentEnabled":false,"dependabotInfo":{"showConfigurationBanner":false,"configFilePath":null,"networkDependabotPath":"/NVIDIA/cosmos-framework/network/updates","dismissConfigurationNoticePath":"/settings/dismiss-notice/dependabot_configuration_notice","configurationNoticeDismissed":null},"displayName":"sft.md","displayUrl":"https://github.com/NVIDIA/cosmos-framework/blob/main/docs/posttrain/guides/sft.md?raw=true","headerInfo":{"blobSize":"48.4 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":"540b18f","siteNavLoginPath":"/login?return_to=https%3A%2F%2Fgithub.com%2FNVIDIA%2Fcosmos-framework%2Fblob%2Fmain%2Fdocs%2Fposttrain%2Fguides%2Fsft.md","isCSV":false,"isRichtext":true,"lineInfo":{"truncatedLoc":"555","truncatedSloc":"524"},"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":"/NVIDIA/cosmos-framework/blob/main/docs/posttrain/guides/sft.md","showFreeOrgGatedFeatureMessage":null,"showPlanSupportBanner":null,"upgradeDataAttributes":null,"upgradePath":null},"publishBannersInfo":{"dismissActionNoticePath":"/settings/dismiss-notice/publish_action_from_dockerfile","releasePath":"/NVIDIA/cosmos-framework/releases/new?marketplace=true","showPublishActionBanner":false},"rawBlobUrl":"https://github.com/NVIDIA/cosmos-framework/raw/refs/heads/main/docs/posttrain/guides/sft.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":["# SFT","","## 1. When to choose it","","Full-parameter supervised fine-tuning of Qwen conversations through the existing `LLMTrainer`.","The [multimodal recipe](../../../cosmos_framework/posttrain/configs/sft_qwen3p8_27b_multimodal.py) targets `Qwen/Qwen3.8-27B`","(the dense `qwen3_5` architecture), with text, images, videos and multiple assistant turns.","Local/torchrun FSDP is supported; Ray execution, LoRA, sequence packing and MTP training are not.","There is no rollout engine, reference model or reward function.","","SFT opts into Transformers 5.8.1; existing RL/GR00T defaults stay on 4.57.6. The SFT builder","supports Qwen text models, dense Qwen3.5/3.8 multimodal models and the Qwen3-VL / Qwen3-VL-MoE","families (all three ship `Qwen3VLProcessor`). A \"seat\" is the model construction path the SFT","objective sits on. Qwen3.5/3.8 sits on the HF backend (`model_backend='hf'`,","`model/hf.py::HFModel`). Qwen3-VL and Qwen3-VL-MoE sit on the i4-native policy builder","(`model_backend='i4'` with `config.model = NativePolicyBuildSpec(builder=model/qwen3_vl.py::","build_qwen3_vl_native_policy, ...)`, see [the native recipe](../../../cosmos_framework/posttrain/configs/sft_qwen3_vl_moe_native.py)):","the HF backend refuses MoE VLMs because the general weight loader has no fused-expert handling and","Transformers 5 stores the MoE expert tensors transposed relative to a Transformers 4 checkpoint.","On the native seat the parameters are stored in bfloat16 (the MoE expert kernel requires it), so the","recipe uses `attn_impl='sdpa'` and `OptimizerConfig(name='fusedadam')` (apex fp32 master weights and","moments inside the optimizer); `validate_config` refuses `adamw` there because its bfloat16 moments","round most updates to zero. The seat's masking contract is pinned against the official Qwen3-VL","processor template in `tests/test_data_packer_sft.py` (the collated `attention_mask` is `torch.int64`","0/1, the contract `main` pins in `test_model_qwen3_vl.py`; the native eager mask casts it to bool); its","GPU training path reuses the online adapters.","","## 2. Quick start","","Start the container and install uv 0.11.29 as in","[sections 1 and 2 of the run guide](../howto/run-posttrain.md#1-start-the-container), then run","from the repository root. SFT uses its own venv with the `sft` group","([locked environment project](../../../docker/posttrain/environment/pyproject.toml)):","","```bash","# `python3 -m uv` runs the pip-installed uv 0.11.29: a bare `uv` can resolve to an older release","# that ships with the container, which the environment project refuses.","# cu130-runtime matches the run guide's CUDA 13.0 image; use cu128-runtime on a CUDA 12.8 stack.","UV_PROJECT_ENVIRONMENT=\"$PWD/docker/posttrain/environment/.venv-sft\" \\","  python3 -m uv sync --project docker/posttrain/environment --frozen \\","  --no-group transformers4 --group sft --group cu130-runtime","export SFT_PYTHON=\"$PWD/docker/posttrain/environment/.venv-sft/bin/python\"","export PYTHONPATH=.","","# The reviewed Qwen3.8-27B snapshot (about 56 GB).","uvx hf@latest download Qwen/Qwen3.8-27B \\","  --revision 1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0 \\","  --local-dir artifacts/models/Qwen3.8-27B","export SFT_MODEL_PATH=\"$PWD/artifacts/models/Qwen3.8-27B\"","export SFT_DATA_ROOT=\"$PWD/.ene/scratch/sft-example\"","\"$SFT_PYTHON\" -m cosmos_framework.posttrain.scripts.prepare_sft_example --output \"$SFT_DATA_ROOT\"","\"$SFT_PYTHON\" -m cosmos_framework.posttrain.entrypoints.sft --validate-manifest","\"$SFT_PYTHON\" -m cosmos_framework.posttrain.entrypoints.sft --validate-rows","","# N is the allocated GPU count; this command does not allocate resources.","\"$SFT_PYTHON\" -m torch.distributed.run --standalone --nproc_per_node=\"$N\" \\","  -m cosmos_framework.posttrain.entrypoints.sft","```","","The generator creates 32 training and 8 validation conversations with local PNG/MP4 media;","it refuses to overwrite a nonempty directory. Video decoding requires TorchCodec 0.11.0","and compatible FFmpeg shared libraries. This is a functional example, not a quality benchmark.","Preflight checks configuration, local file availability and role wiring, not GPU memory or","remote access. `--validate-rows` then runs every row through the real packer on CPU and refuses","over-long rows, masks that disagree with the assistant turns, and mislabelled tool turns before any","trainer is built ([scripts/README.md](../../../cosmos_framework/posttrain/scripts/README.md#pre-launch-sft-row-validator)). Use torchrun even for one GPU; 27B FP32 training does not fit a single ordinary GPU.","","Use a complete immutable snapshot, not a mutable Hub branch or metadata-only test fixture.","The reviewed Qwen3.8 revision is `1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0`; its config selects","`Qwen3_5ForConditionalGeneration` and its processor is `Qwen3VLProcessor`. Preserve the","processor/tokenizer/template sidecars. The loader requires every dense model parameter and","ignores extra `mtp.*` weights; SFT does not train MTP.","","## 3. Data contract","","One complete conversation per JSONL record:","","```json","{\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"image\",\"image\":\"media/frame.png\"},{\"type\":\"text\",\"text\":\"What color is the object?\"}]},{\"role\":\"assistant\",\"content\":\"Red.\"},{\"role\":\"user\",\"content\":\"Repeat in uppercase.\"},{\"role\":\"assistant\",\"content\":\"RED.\"}]}","```","","- Roles: `system` (first only), `user`, `assistant`, and `tool`. Text is a string or a","  `{\"type\":\"text\",\"text\":\"...\"}` part. Videos use `{\"type\":\"video\",\"video\":\"...\"}`.","- Optional `tools`, assistant `tool_calls`, and `reasoning_content` are retained. Tool-only","  assistant content may be absent/null; it normalizes to empty text.","- Optional `supervise`, a string: `all_assistant` (the rule when the key is absent) or `last_assistant`","  (section 4). Any other value, `null` included, is refused at load with the row's label. The key is","  never added to a row that lacks it, so the fingerprint of an existing file does not change.","- Optional `opener`, a string: `self` (the rule when the key is absent) or `prefilled` (section 4);","  validated and never added the same way. A `meta.opener` (the exporter's record of its prefilled slice)","  must agree with the `opener` field, which is what the packer reads.","- `rl.data.path` and `rl.validation.data.path` accept local JSONL or `s3://bucket/key.jsonl`.","  Remote reads use each source's `credentials` path and the existing S3/GCS client.","- JSONL is read once per rank into memory. Fingerprints cover normalized content and local","  media bytes. Text-only identity excludes URI/credentials and survives cross-cluster moves.","- Local media resolves relative to the JSONL file unless `media_root` is set. S3 JSONL with","  media requires an explicit local `media_root`; automatic remote media fetching is not supported.","- Alternatively, `rl.data.factory` plus `factory_kwargs` selects a map-style source returning","  this schema with an immutable `cursor_fingerprint()` covering rows and media. Additional","  dataset cursor hooks must be supplied as a save/load pair.","- Training row count must divide DP world size. Rows shuffle and repeat by epoch; no training","  records are silently dropped or padded. Validation requires a separate source.","","## 4. Objective and masking","","The packer renders with the checkpoint's own chat template and passes `preserve_thinking=True`","only to a template that declares that variable (the toy test template does). The official","Qwen3-VL template has no such variable: it renders `reasoning_content` for every assistant turn","and passes inline `\u003cthink\u003e` text through as content, so nothing is passed to it; a kwarg the","template does not declare is one Transformers 5 reclassifies as a processor kwarg and warns about","on every render. Every assistant body and turn-ending token is supervised; headers,","user/system/tool content, media tokens, generated video timestamps and padding are ignored.","","**Row-level supervision (`supervise`).** A row's `supervise` field selects the assistant","turns that carry loss: `all_assistant` (the default and the behaviour before the field existed: every","assistant body and its `\u003c|im_end|\u003e`) or `last_assistant` (the LAST assistant turn's body through its","`\u003c|im_end|\u003e` only; every earlier assistant turn stays in the sequence as context at -100, like the tool","results and user turns around it). The packer records the row's contract string on","`SFTPolicyInput.masking` (`qwen_chatml_all_assistant_bodies_and_end_v2` or","`qwen_chatml_last_assistant_body_and_end_v1`); the packer-level resume identity keeps the all-assistant","string because the field is part of the row and therefore of the source fingerprint.","`rl.mask_think_opener` applies to the supervised turn only (the per-row `opener` field below applies the","same rule to one row). The rule exists for **prefix rows** (a term","defined here): one row per model call of an agent-harness episode, whose prompt is the served prefix of","that call -- the tokenizer template's rendering of the history, every earlier assistant turn","reasoning-free, exactly what the default serve renders when the request carries a tools array (measured","equal to the serving deployment's tokenize endpoint on 146 of 146 calls of one agent-harness episode) --","and whose completion is the student's own turn at that call, reasoning included.","A prefix row therefore matches the **default serve** of a default export token for token; a","whole-episode row with reasoning in every assistant turn does not (it is exact only under a serve that","renders the processor template with tools: a **unified export**, defined in section 7 as an export built","with the materializer's `--unified-chat-template`, whose two template files carry the canonical processor","template). Fixtures:","`tests/test_data_packer_sft.py::test_supervise_last_assistant_three_turn_row_exact_loss_counts`","(a three-turn row through the toy tokenizer: 96 = [91, 5] loss tokens under the default, 5 = [5] under","`last_assistant`, the ids identical) and","`test_supervise_last_assistant_official_template_keeps_history_at_minus_100` (the official template","with an image and a tool call; the opener mask then touches the last turn's opener only). Under","`last_assistant` the history turns must carry no reasoning: the packer refuses a history assistant turn","with a non-empty `reasoning_content` or a content opening with `\u003cthink\u003e` (the processor template renders","a history `reasoning_content` as a think block, 250 vs 236 ids on one probe, while the default serve's","prefix has none, and it strips an exact `\u003cthink\u003e\u003c/think\u003e` content prefix the tokenizer template keeps).","Fixture:","`test_last_assistant_row_prefix_is_the_served_prefix_under_both_templates_and_history_reasoning_is_refused`","(the base's two templates as repo fixtures: the row's text and ids begin with the tokenizer template's","served prefix, the two templates agree byte for byte when no turn carries reasoning, a history","`reasoning_content` or `\u003cthink\u003e\u003c/think\u003e` prefix diverges inside the history and is refused, an","`all_assistant` row with the same history still packs).","","**Row-level opener (`opener`).** A row's `opener` field says whose token the","`\u003cthink\u003e` opener of a supervised assistant turn is: `self` (the default and the behaviour before the","field: the opener is the student's first supervised token, as the agent harness's serve prefills nothing)","or `prefilled` (the serve prefills the opener token itself, `\u003c|im_start|\u003eassistant\\n\u003cthink\u003e`, id 151667, no","newline after it, as a thinking-on client without tools does: the packer masks the first `\u003cthink\u003e` token","of every supervised assistant block of that row, exactly the rule the run-level `rl.mask_think_opener=True`","applies to every row, and the supervised target begins with the newline that opens the reasoning text;","under `last_assistant` that is the last block only). One rule: a row with `opener: prefilled` in a run","with `mask_think_opener=True` is masked once, the count unchanged. Why per row: the exporter writes the","prefilled slice (20 percent of the supervised reasoning turns, a fixed seed) into the same row files","as the self rows, so the mask must be the row's, not the run's; the exporter records its choice as","`meta.opener` and must write the same value in the row's `opener` field, which is what the packer reads","(the loader refuses a `meta.opener` that disagrees with the field, a `prefilled` in `meta` without the","field included). The per-row contract string gains `_opener_prefilled_v1`","(`qwen_chatml_all_assistant_bodies_and_end_v2_opener_prefilled_v1`,","`qwen_chatml_last_assistant_body_and_end_v1_opener_prefilled_v1`); the packer-level identity keeps","recording the run-level knob. A `prefilled` row on a tokenizer without `\u003cthink\u003e` is refused. A `prefilled`","row needs a reasoning block in every supervised assistant turn: the packer","refuses the row unless its mask removed exactly one `\u003cthink\u003e` id in every supervised block (the refusal","names the bare blocks and the per-block counts), and the loader refuses a `prefilled` row whose supervised","turns (all of them under `all_assistant`, the last under `last_assistant`) lack a non-empty","`reasoning_content.strip()`, so the string `_opener_prefilled_v1` is only ever recorded when the masking","happened; the run-level knob on a bare turn masks nothing and refuses nothing (it is the run's variant,","recorded in the packer identity, not the row's contract). The loader also refuses a `meta.supervise` that","disagrees with the row's `supervise` field, as it does for `meta.opener`. Fixtures:","`tests/test_data_packer_sft.py::test_opener_prefilled_three_turn_row_exact_loss_counts_under_the_four_combinations`","(a three-turn row through the toy tokenizer: with reasoning in both assistant turns under `all_assistant`,","`self` 118 = [102, 16] and `prefilled` 116 = [101, 15]; under `last_assistant`, with the history turn","reasoning-free as that mode requires, 16 and 15; the difference exactly the opener token of each","supervised block), `test_opener_prefilled_and_the_global_mask_are_one_rule`,","`test_opener_refuses_unknown_values_and_a_tokenizer_without_think`,","`test_opener_prefilled_refuses_a_supervised_block_without_an_opener` (B1 / B2 / B3 refused, self rows and the","run-level knob unchanged),","`tests/test_roles_env_sft.py::test_opener_field_is_validated_by_the_loader_and_reaches_the_target` and","`::test_opener_prefilled_rows_require_reasoning_on_every_supervised_turn_and_meta_supervise_must_agree`. A row","validator that counts assistant tokens independently of the labels must count over","`data/packer/sft.py::supervised_assistant_blocks(n_assistant_blocks, supervise)`, the indices the packer","paints, or it reports every `last_assistant` row as a mask mismatch.","`rl.mask_think_opener=True` additionally unsupervises the `\u003cthink\u003e` token that opens an assistant","body, and only that token. Keep the default `False`: on the serving path of record (Codex","`--thinking high` sends `reasoning.effort` and the harness's tools array on every call) vLLM 0.24","prefills no opener -- with tools present the served prefix is `\u003c|im_start|\u003eassistant\\n` and nothing","more (the effort field adds 0 input tokens; `/tokenize` with tools and `enable_thinking` ends in","`assistant\\n`; measured live; the ids are the fixture","`tests/fixtures/served_prefix_with_tools.json`), so the student must emit `\u003cthink\u003e` itself as the","first token of every turn and then the reasoning, or the closer `\\n\\n\u003c/think\u003e\\n\\n` of the empty","block a turn without reasoning (a no-think turn) is rendered with; all of it is the student's and","the opener's loss is the only training signal for that token. `True` would leave it unsupervised;","what a `True`-trained student would emit there is UNMEASURED with tools present (no such student","exists, and the first token after `assistant\\n` with tools present was never sampled), so the","consequence is a RISK, not a measurement. The failure it could reopen has a measured trigger: the","qwen3 parser treats an output that carries no `\u003c/think\u003e` as reasoning in full, so a no-think TEXT","turn of the student never reaches Codex as an agent message, while a no-think TOOL-CALL turn is","unaffected (vLLM 0.24 `reasoning/basic_parsers.py` 173-181: without `\u003c/think\u003e` the whole output is","reasoning; with `\u003c/think\u003e` it is split even without `\u003cthink\u003e`); under the exporter's rendering the","closer stays supervised under `True`, so a turn that dropped only the opener would still carry","`\u003c/think\u003e`. The decision does not rest on the risk: `False` stays the default because the opener's","loss is the only training signal for a token the student must emit on the path of record. Selecting","the `prefilled_opener` variant sets the typed field `rl.serve_contract=prefills_opener` beside the","mask: the declaration that the student will be served by a path that prefills `\u003cthink\u003e` for it,","recorded in the resolved config and, being non-default, in the objective identity. `SFTConfig`","refuses the VALUE `rl.mask_think_opener=True` under the default contract `tools_no_prefill` from any","source, a `--` override on the `default` variant included, and the resolved variant name is stamped","into the attempt's provenance as `recipe_variant`. The prefill exists only for requests without","tools: there a present effort sets `enable_thinking` and the template appends `\u003cthink\u003e` (10 input","tokens instead of 9) -- not a path of record; under such a serve the supervised opener costs one","deterministic token per turn and the student continues after it, so `False` is right under both","conditions. (The Nemo-Chat processor rule also unsupervises an empty block, because its serve","supplies the whole block; that rule, applied here, would remove the closer's loss under a single-newline","rendering.) The native recipe's table (its `\u003cthink\u003e` opener row) records the decision with its","measurements. Templates that drop supplied reasoning or reorder messages are rejected, as are","reserved chat/media delimiters in source text.","","Masks use the **final processor-expanded token stream**, requiring an exact tokenizer round","trip; no prefix-length approximation or pre-expansion assistant mask is used. Labels are","unshifted at collation; the objective shifts exactly once. With `rl.ce_exponent=0` (the framework","default) the loss is the global supervised-token mean across ranks and accumulation; with","`ce_exponent=e` every row contributes its token sum divided by `n^e` over the DP-mean of","`sum_rows n^(1-e)` (`0.5` = the Cosmos post-training recipe's square-root weighting, `1` = every row","weighs the same). `rl.moe_lbl_coeff\u003e0` adds the MoE load-balancing term","`coeff * E * mean_layers(sum_e f_e * P_e)` from the sparse blocks' routing statistics of the same","forward (`f_e` the share of routed tokens, summed over the DP ranks under `moe_lbl_method='global'`;","`P_e` the mean router probability); `train/lbl_loss`, `train/moe_load_max_rel` (the largest","expert's share relative to uniform, 1.0 = balanced) and `train/objective` (the value descended)","then appear beside `train/loss_avg`, which stays the plain token-mean CE. Overlength conversations","fail rather than truncating targets.","","## 5. Main knobs","","Global conversations/update are `rl.micro_batch_size × rl.grad_accum × DP world size`.","`rl.max_steps` counts optimizer updates; `rl.max_length` limits the full expanded sequence.","`rl.optimizer.*` controls the optimizer, clipping and warmup (`warmup_steps` must be `\u003e= 0`);","`rl.lr_schedule.kind` selects what follows the warmup: `constant` (the pre-existing path) or","`cosine` (the Cosmos post-training recipe's `LambdaWarmUpCosineScheduler`: lr × `f_start` at the","first update, linear to lr at `warmup_steps`, cosine down to lr × `f_min` at `cycle_steps` or","`max_steps`). `rl.optimizer.lr_multipliers` scales the learning rate of the parameters whose name","contains a key (`{\"model.visual\": 0.1}` = the vision tower at a tenth). Precision differs by seat.","The dense HF recipe keeps FP32 parameters and optimizer state (`master_dtype='float32'`) under BF16","autocast. The native Qwen3-VL-MoE recipe stores the parameters in bfloat16","(`master_dtype='bfloat16'`, `param_dtype='bfloat16'`); its fp32 master weights and fp32 moments","live inside the apex fused Adam (`OptimizerConfig(name='fusedadam')`), which refreshes the bf16","parameters from the master on every step, and the saved artifact is that bf16 copy, never the","master: an update below half a bf16 ulp of a weight is carried in the master during the run and","reaches neither the artifact nor the training forward, which reads the same bf16 copy. Known limit,","measured over 1,401 training steps at lr 1e-5: `model.language_model.norm.weight`","(median |w| 3.08, bf16 ulp 0.0156 \u003e 1,401 × 1e-5 = 0.014) changed in 0 of 2,048 elements while","`layers.0.input_layernorm.weight` (median 0.0036) changed in 1,985 of 2,048; 36 of the 882 tensors","(34 vision norms, `layers.47.input_layernorm.weight`, the final norm) were bitwise the base's, i.e.","those 36 norm scales did not train. Trade-off: the served model is bf16 either way, and storing the","1-D parameters (the 426 norm scales and biases, a few MB in fp32) in fp32 would un-freeze them at","negligible memory cost, the export rounding each once (at most half an ulp lost). The materializer","records per export how many tensors equal the base (`tensors_equal_to_base` in `.materialized`).","`tests/test_config_sft.py::test_bf16_storage_freezes_large_scales_below_half_an_ulp` is a pin of the","mechanism on a tiny fixture (it records pure bf16 arithmetic, which the framework does not change), as","is `test_deterministic_knob_reaches_setup` (pre-existing setup behaviour); neither tests a change to","the framework. Both recipes use activation checkpointing and SDPA. Weight decay is decoupled;","`decay_groups=''` builds one parameter group (every trainable parameter decays, norms, biases,","embeddings and routers included -- the Cosmos post-training recipe's own grouping:","`cosmos3/utils/optimizer.py::_build_params_with_metadata` decays all 882 tensors of the backbone),","`decay_groups='hf'` reproduces the Transformers Trainer's [decay, no-decay] split (LayerNorm modules,","biases and `*norm*` names undecayed; the embedding, the head and the router gates decay), and","`decay_groups='qwen_moe'` (the native recipe) leaves every 1-D parameter (norm scales, biases) AND","the token embedding, the output head and the MoE router gates undecayed -- the seat's own choice,","whose protection and cost the recipe's table states in its weight-decay row. The native recipe's","docstring carries the per-knob decision table (Cosmos post-training recipe vs the A1 arms vs its","defaults).","","`rl.processor_kwargs` accepts HF `images_kwargs` and `videos_kwargs`. Pixel budgets use","`size.shortest_edge`/`longest_edge` (pixel area), not legacy `min_pixels`/`max_pixels`.","The example samples 8 video frames with `fps=None`; do not also request FPS-based sampling.","The processor's media tensors and `mm_token_type_ids` reach the model unchanged. The Qwen3.5","forward adapter orders image/video vision calls and backward graphs on every rank, including","dummy work for absent modalities; dummy grids never enter token positions or M-RoPE.","","## 6. Metrics and validation","","`train/loss_avg` and `val/loss_avg` are token-weighted means; valid token/sequence counts","are sums. Every committed frame is written to `\u003crun dir\u003e/metrics.jsonl` (one JSON line per step:","`train/grad_norm` = the pre-clip global norm, `train/learning_rate`, `train/valid_token_count`,","`timer/e2e_step_s`, `train/grad_clip_coef` = the factor `clip_grad_norm_` applied,","`min(1, grad_clip_norm / (norm + 1e-6))`, and `train/grad_clipped` = 1.0 exactly when that factor is","below 1 (one rule; both recorded by `LLMTrainer` from the norm it clipped),","`train/grad_clip_fraction` = the share of the run's updates clipped so far (the loop's running count),","plus the validation keys of that step) and the console line carries the headline subset. The file","holds one row per step across relaunches: an attempt that resumes at step `s` keeps the rows with","`step \u003c= s` and drops the later ones, which it re-emits (a crash past the last save leaves committed","rows the resumed attempt recomputes), and the clip counters continue from the kept rows, so the","fraction is the run's, not the attempt's; a fresh attempt starts the file empty. Held-out validation","uses finite batches with zero-weight tail padding and restores module modes, source cursor and RNGs.","Final validation is mandatory when enabled. The validation source must be held out row by row: setup","refuses it when any validation row has the content hash (messages + tools, media by file bytes so a","copy of the training media under another root is the same row) of a training row or the item id","(`meta.item`) of one, and when validation rows carry no item id while the training rows do (a row","without an item has only its content hash as identity, which one changed character defeats); a","whole-source fingerprint check is not enough, since it passes a strict subset of the training file.","","On the native Qwen3-VL-MoE seat, `train/grad_norm` varies from run to run because routing in the bf16","MoE forward is not deterministic. Read it as a per-run diagnostic, not as a quantity to compare","between two runs.","","## 7. Checkpoints, resume and export","","The generic example saves DCP every 10 updates and at its final step. Obj1k instead selects","consolidated `model.pt` for HF export. `rl.resume=auto` resumes the latest checkpoint for the","same job identity; an explicit iteration directory also works. Exact resume binds every rank's","data cursor, tokenizer/processor/masking semantics, precision and batching. Preemption saves","only at complete optimizer boundaries.","","For storage and retention see [checkpointing](../reference/checkpoint.md). The","[HF materializer](../howto/checkpoint-artifacts.md#materialize-an-opd-teacher) consumes consolidated","`model.pt`, not DCP; it preserves tokenizer/processor sidecars, writes the base's `config.json` into the","export (the transformers-written one is kept unpublished as `config.json.trainer.bak`, the export's own file","before the base overlay), and verifies every tensor of `model.pt` bitwise against the shards before it","returns, keeping a sha256 per tensor and the list of tensors bitwise equal to the base in `.materialized`. A","`processor_config.json` in the export is the base's own file or none (the reference base carries none);","`conversion.hf.service_processor_config` composes one from the base's sidecars but has no production caller,","and the file served beside one deployed export (placed by hand) differs from it in the image processor class","and 17 explicit defaults, so connecting the helper is a separate change: a contract bump, `verify_sidecars`","accepting the composed file and a re-anchored serve. Select `rl.checkpoint_format=consolidated` if export is","required and budget rank-0 host memory. `rl.export_*` is not wired and is rejected.","","**Unified chat template (`--unified-chat-template`).** The base ships two chat templates: `chat_template.json`","(the **processor template**, 5,614 chars, text sha256 `97de86bf6ddb765a...`) and `tokenizer_config.json`'s","`chat_template` (the **tokenizer template**, 5,292 chars, `3636d0f0bd6bef02...`). They differ in what they","render for an assistant turn in the HISTORY: the processor template renders `reasoning_content`","(`\u003cthink\u003e...\u003c/think\u003e`) in every assistant turn, the tokenizer template renders none. vLLM 0.24 renders a","request that carries a tools array with the tokenizer template (measured: a captured agent-harness request,","req_012, tokenizes to 8,946 ids on the default serve and to 8,969 with the processor template forced, the 23","extra ids an earlier turn's think block; the first differing id sits at position 7,247, `\u003cthink\u003e` vs","`\u003ctool_call\u003e`). The materializer option writes BOTH template files of the export, `tokenizer_config.json`'s","`chat_template` and `chat_template.json`'s `chat_template`, as the processor template in its CANONICAL form,","every other key of each file unchanged (every other line byte-equal when the base's file is a plain","`json.dumps` rendering, which both of the reference base's are). The **canonical form**","(`template_mode: processor-canonical`) is the processor template with ONE change in its reasoning branch,","`'\u003cthink\u003e\\n' ~ (message.reasoning_content | trim) ~ '\\n\u003c/think\u003e\\n'` instead of the untrimmed rendering: a","replayed reasoning string that arrives with a newline at both ends (the agent harness's form) then renders the","canonical block `\u003cthink\u003e\\n\u003ctext\u003e\\n\u003c/think\u003e\\n`, the student's own emission form, instead of the padded","`\u003cthink\u003e\\n\\n\u003ctext\u003e\\n\\n\u003c/think\u003e\\n` (`conversion.hf.canonicalize_processor_template`; a base whose processor","template lacks the exact line is refused). The marker records the processor template's sha, the shipped sha of","each file (`shipped`) and the one-hunk diff under `chat_template` (`template_mode`, `files`, `canonical_diff`;","also `options.unified_chat_template` and `sidecars.chat_template`), makes the option part of the output's","identity (a request without it on such an output is refused until `--force`, and the reverse) and verifies","both files by rule instead of byte identity (`verify_sidecars`: each file's mapping equals the base's on every","key but `chat_template`, whose value is the canonical text; `verify_with_torch`: the loaded tokenizer's and","the loaded processor's templates are that text). Default off: the default export stays byte-identical to the","base's sidecars. The rows for this template write `reasoning_content` as the model's TRIMMED reasoning text","(the `str.strip()` of the model's reasoning bytes; the packer renders the base's own processor template, which","yields the same canonical block for a stripped string, so training bytes are canonical with or without the","option), and no-reasoning turns stay BARE, no think block (matching the student's measured emission and the","serve's history form). Serving condition: **unified rows** (a term defined here: whole-episode rows in which","every assistant turn is supervised and the history turns carry their reasoning, the row shape of a unified","export's training set) are exact under ANY serve of a unified export and without a serve-side template flag:","both template files of a unified export carry the canonical text, so a request with or without tools renders","the same reasoning form (a tokenizer-only loader reads `tokenizer_config.json`, a processor loader reads","`chat_template.json`). Two row conditions carry this claim, both measured on the captured request req_012: (a)","tool-call `arguments` travel in the row as the PARSED OBJECT, which the template renders through `tojson`","(`{\"query\": \"value\"}`, with `\": \"` and `\", \"`), exactly as the serve re-serialises the parsed arguments; a row","that keeps the model's compact JSON string (`{\"query\":\"value\"}`) renders it verbatim and differs from the","served prefix at the first argument (3 of 3 argument strings of req_012 differ from their re-serialised form);","the packer also accepts `arguments` as a string and renders it verbatim, and such a string matches only when","it equals `json.dumps(obj, ensure_ascii=False)` of its parsed object (the `tojson` form the serve emits): the","model's compact string and `json.dumps(obj)` with the default `ensure_ascii=True` (non-ASCII escaped as","`\\uXXXX`) both differ; (b) `reasoning_content` is the `str.strip()` of the model's reasoning bytes (Jinja's","`trim`), not the text with one newline removed at each end: a trailing space or a second newline survives the","latter and breaks the match. Pins: the string-vs-object and whitespace cases of","`tests/test_data_packer_sft.py::test_processor_canonical_template_trims_the_replayed_reasoning_where_the_verbatim_template_pads_it`","(the `ensure_ascii=True` case included). Supported-base contract under the option: a base ships its templates","in the two JSON files, `chat_template.json` and `tokenizer_config.json`'s `chat_template`, as the evidenced","Cosmos base does, and carries NO template sidecar a loader prefers over them; the materializer's preflight","enforces it. The materializer's preflight is the torch-free set of checks in","`checkpoint/tools/materialize_hf.py` that read the base alone before anything is removed or written (not the","trainer's preflight of section 2, which checks the training configuration). Read on transformers 4.57.6 and","5.8.1, the two pinned versions, those are `chat_template.jinja` (the tokenizer loader takes it over","`tokenizer_config.json`'s key; the processor loader reads it only when `chat_template.json` is absent), the","`additional_chat_templates/` directory (named templates the tokenizer loader prefers over the key; beside","`chat_template.json` the processor loader refuses the combination; the directory is refused whatever it holds,","empty or with nested directories only included, by the one helper the materializer's preflight and","`verify_sidecars` share: both loaders discover named templates with `glob(\"*.jinja\")` and ignore an empty","directory, and the rule still refuses it, fail closed) and a `chat_template` key in `processor_config.json`","(the processor loader prefers it on 5.8.1). With such a sidecar the export would ship both canonical JSON","files while `AutoTokenizer` renders the sidecar, so the materializer REFUSES the base in unified mode before","anything is published, with or without `--no-verify`, naming the file. That refusal is part of the","materializer's preflight, which runs before any destructive step: under `--force` the existing output is","removed, `\u003cout\u003e.tmp` created and the overlay run only after it has passed, so a refused request leaves the","existing output byte-identical. The same preflight also parses every JSON sidecar of the base","(`tokenizer_config.json` and `chat_template.json` as objects; the overlay and the template record read them","after the overlay), refuses in the default path an `additional_chat_templates/` whose entries are not all","regular files (the default path copies the directory verbatim and its verifier refuses a sub-directory), and","turns an unreadable base into a named refusal instead of a traceback (fixtures","`tests/test_checkpoint_materialize_hf.py::test_force_rebuild_keeps_the_existing_output_when_a_base_json_sidecar_does_not_parse`,","`::test_default_preflight_refuses_a_named_template_directory_with_entries_that_are_not_regular_files` and","`::test_preflight_refuses_an_unreadable_base_with_a_named_reason_instead_of_a_traceback`). The same preflight","also runs on every base shard the index lists the safetensors header check the output gets","(`conversion.hf.shard_status`: present, readable, header parsed, size = 8 + header + data, header keys = the","tensors the index maps to it), because the overlay's `from_pretrained` opens every shard in the staged build","and a shard truncated by one byte, with a garbage header or unreadable would otherwise pass (the identity","records sizes only); requires every JSON sidecar of the base to be a JSON object and `chat_template.json`,","when present, to carry a non-empty `chat_template` string (the loaders index these after the overlay: a `[]`","sidecar fails `AutoProcessor` / `GenerationConfig` and a `{}` template file is the processor loader's","KeyError, read on the container's transformers 5.13.0); validates the index's `weight_map` (a non-empty object","of tensor name -\u003e shard name, so no index shape escapes as AttributeError / TypeError); and raises every","refusal in the one message family","`REFUSED before anything is published: \u003cwhat was found; what the staged build would have done with it\u003e`","(fixtures","`::test_preflight_refuses_a_base_shard_the_safetensors_header_check_rejects_before_anything_is_removed`,","`::test_preflight_refuses_a_json_sidecar_the_loaders_reject_although_it_parses`,","`::test_preflight_refuses_an_index_whose_weight_map_is_not_tensor_to_shard_names_without_a_traceback` and","`::test_every_preflight_refusal_is_in_the_one_message_family_and_names_what_it_found`). ONE JSON decoder","serves the whole preflight and the materializer's own readers (`conversion.hf.decode_json_bytes`: strict UTF-8","text, what `model_identity`, `_read_json_file` and transformers' loaders decode in the staged build), so a","UTF-8 byte-order mark in front of valid JSON (config.json, any JSON sidecar, the index) is refused by name","instead of passing through `json.loads(bytes)`, which strips it (on the reference base's files a leading mark","fails AutoConfig, AutoProcessor, AutoTokenizer and GenerationConfig: `Unexpected UTF-8 BOM` /","`not a valid JSON file`); and `shard_status` validates the safetensors header's shape (a JSON object of tensor","entries with a dtype string, a shape list and `data_offsets` of two non-negative integers begin \u003c= end, an","optional `__metadata__` object), so a malformed header is a named refusal in the preflight and a named failure","of the output verifier, never a traceback (fixtures","`::test_preflight_refuses_a_utf8_byte_order_mark_in_front_of_valid_json_as_the_loaders_do` and","`::test_shard_status_refuses_a_header_without_the_safetensors_shape_and_the_preflight_names_it`). The","construction is STAGED. The whole build happens in `\u003cout\u003e.tmp` beside an existing output: the overlay (the","base read by its real readers: the pinned safetensors reader on every shard, transformers on the sidecars),","the sidecar sync, `config.json \u003c- base`, the verification (index, sidecars and, unless `--no-verify`, the","torch probe, all on the staged copy) and the `.materialized` marker, the last file written there (its","semantics unchanged); only then the swap replaces the existing output by renames (`\u003cout\u003e` -\u003e `\u003cout\u003e.previous`,","`\u003cout\u003e.tmp` -\u003e `\u003cout\u003e`, `\u003cout\u003e.previous` removed; `materialize_hf.publish_staging`). On any failure before the","swap the staging directory is removed, the error names its stage and the existing output is byte-identical,","under `--force --no-verify` too. Transient disk: two exports side by side from the overlay to the swap (the","staged shards are written by `save_pretrained`, not linked). A leftover `\u003cout\u003e.previous` is refused before the","build unless `--force`, which discards it. Before the staging, the same preflight asks the pinned safetensors","reader itself (`conversion.hf.safetensors_reader_error`: `safe_open` on the header of every base shard the","index lists; dtype names, string metadata values, contiguous offsets, byte count per tensor, file length: a","BF16 `[3]` tensor over four bytes, an unknown dtype, a non-string metadata value and an offset gap all passed","the shape check) and decodes, strictly as UTF-8, every Jinja template the tokenizer and processor loaders read","(`chat_template.jinja` and each `additional_chat_templates/*.jinja` named template;","`conversion.hf.loader_template_files` cites the loader lines), refusing by file and reader message / decode","position in the one family (fixtures","`::test_preflight_refuses_a_base_shard_the_pinned_safetensors_reader_rejects_and_keeps_the_export`,","`::test_preflight_decodes_the_jinja_templates_the_loaders_read_as_strict_utf8_and_keeps_the_export`,","`::test_a_failure_after_the_preflight_keeps_the_existing_export_and_removes_the_staging_directory`,","`::test_the_swap_publishes_by_rename_and_a_leftover_previous_output_is_refused_without_force` and","`::test_preflight_refuses_when_the_pinned_safetensors_reader_cannot_be_imported`). Under `--force` no complete","marked tree is discarded while it is the only one: in the crash state between the swap's two renames","(`\u003cout\u003e.previous` = the old export, `\u003cout\u003e.tmp` = the new one complete and marked, no `\u003cout\u003e`)","`\u003cout\u003e.previous` is renamed back to `\u003cout\u003e` first and the build happens beside it; a leftover `\u003cout\u003e.previous`","beside an existing `\u003cout\u003e` is removed at the swap, after the new tree is verified. `--force` rebuilds from the","source; a death-left `\u003cout\u003e.tmp` is discarded once `\u003cout\u003e` is complete again whatever its marker says (a","marker match covers the identity, the shard sizes and tensor counts, not the shard bytes, and the base digest","excludes the base shards' bytes), a complete marked `\u003cout\u003e.tmp` that is the only complete tree is refused by","name rather than discarded, and a kept staged copy is published only by a request without `--force`, after the","same verification as a fresh build (index, sidecars, the torch probe unless `--no-verify`, which trusts the","kept copy's bytes on size and tensor count). One materializer per output: `\u003cout\u003e.lock` beside the output, held","with `fcntl.flock` from before the staging to after the swap; a second materializer on the same `--out` is","refused by name (pid, host, start time of the holder) without touching anything; the lock file stays beside","the output (it is not part of the export) and the file system must support flock (Lustre: the `flock` mount","option; a mount that refuses it is a named refusal). Fixtures","`::test_force_after_a_death_between_the_swap_renames_restores_the_old_export_before_building`,","`::test_two_materializers_on_one_output_exclude_each_other_through_the_per_output_lock`,","`::test_the_per_output_lock_refuses_by_name_in_process_and_fails_closed_without_flock`,","`::test_force_rebuilds_from_the_source_instead_of_publishing_a_death_left_copy` and","`::test_a_death_left_copy_is_published_only_by_a_request_without_force_after_verification`. An inherited sole","complete marked `\u003cout\u003e.tmp` (a first publication that died after `.materialized` and before the rename) is","never deleted: the unforced recovery checks its marker against the request (else refused by name), repairs a","missing staged `config.json` from the base through a temporary file and a rename, re-syncs the sidecars the","same way (never a shard), then verifies, re-marks and swaps; a failed recovery check refuses by name and KEEPS","the tree (its shards and its marker untouched, its sidecars possibly repaired from the base before the check:","config.json rewritten, a differing one kept as `config.json.trainer.bak`, a stray sidecar removed, a","`.copying` or `.writing` temporary left by an interrupted copy or unified-template rewrite, and under","`--unified-chat-template` the two template files back in the base's form when that rewrite did not reach its","rename; the refusal says so and names the state at `\u003cout\u003e`: absent, standing but not a complete marked export,","or a complete marked export), and the overlay is never run while the copy is the sole complete tree. The","marker / skip / mismatch decision is taken under the per-output lock, so a materializer that paused before the","lock while another published a different source is refused on that export's marker instead of overwriting it;","a held lock is waited for up to 120 s (`--lock-wait-seconds`, polling), so two simultaneous identical requests","of a published source both end with 0 (the second skips once the holder has finished), a differing request is","refused on the marker, and a holder still there after the bound is refused by name with the bound stated.","Fixtures: `::test_a_failed_recovery_check_leaves_the_inherited_sole_marked_copy_as_found`,","`::test_the_marker_decision_is_taken_under_the_output_lock_so_a_paused_materializer_cannot_overwrite_a_newer_export`,","`::test_a_repair_then_failed_recovery_check_keeps_the_shards_and_the_marker_and_says_what_it_changed`,","`::test_an_identical_request_waits_for_the_lock_holder_and_skips_with_0`,","`::test_the_lock_wait_is_bounded_and_the_refusal_names_the_bound` and","`::test_a_failed_unified_rewrite_during_recovery_leaves_the_writing_temporary_and_the_refusal_names_it`; the","lock bound must be a finite number \u003e= 0 (`inf` and `nan` are refused by name:","`::test_lock_wait_seconds_refuses_non_finite_values`). The source's identity of record (sha256 + bytes of","`model.pt`) is read UNDER the output lock, not before the wait, through a file object opened once there, and","the overlay memory-maps that SAME open file (through `/proc/self/fd`; where that reference does not exist the","loader reads the payload whole through the file object, no mmap, with the whole payload in RAM), so by","construction the skip / mismatch decision, the source record and the marker name the bytes the overlay","consumed, and the default verification (the torch probe) compares the staged shards against that same open","file (a path replaced during the overlay can neither fail a correct build nor pass a wrong one), whatever the","path names meanwhile: the merge tool (tmp + os.replace over `model.pt`) is not excluded by the lock and may","replace the path while the request waits (adopted with a WARNING naming both hashes) or while the overlay runs","(logged; nothing of what was built changes). The opened inode is fstat'd before the hash and after the","overlay: a change of its size or mtime refuses the build by name, with no \"same bytes\" acceptance, since the","digest of the file after the fact does not say what a reader consumed; that check is best effort against a","writer into the opened inode (a client may report an open inode's attributes late), which the merge tool never","is: the guarantee of record is against a replaced path, by construction (fixtures","`::test_the_marker_records_the_source_the_overlay_read_when_the_source_changes_during_the_lock_wait`,","`::test_a_source_replaced_during_the_overlay_does_not_change_what_was_built_or_recorded`,","`::test_the_marker_names_the_bytes_the_overlay_consumed_when_forced_merges_race_the_overlay` with the real","merge tool, `::test_the_default_verification_receives_the_held_payload`, the verification suite's","`test_checkpoint_hf_verification.py::test_default_verification_consumes_the_held_payload_when_the_path_is_replaced`","with the real merge tool and the real torch verifier, and the loader's","`test_checkpoint_hf_overlay.py::test_load_consolidated_state_dict_reads_the_open_file_not_the_path`). The","weights-free loader calls themselves (`AutoProcessor` / `AutoTokenizer` / `GenerationConfig` `from_pretrained`","on the base) are NOT part of the preflight, by design: they are not torch-free (the processor instantiates the","image and video processors, which import torch), their verdicts depend on the installed transformers rather","than on the files, and the synthetic bases of the tests are not loadable by them; a base that passes every","file check but fails a loader on a schema fact the files do not state (`tokenizer.json` = `{}`, a","`preprocessor_config.json` without `image_processor_type`) is still refused by the overlay, in the staged","build, with the existing output kept. A `chat_template.jinja` (or a `processor_config.json` key) whose text","equals the canonical text is allowed, synced verbatim and recorded under `chat_template.preferred_sidecars`;","`verify_sidecars` applies the same rule to the export. Fixtures:","`tests/test_checkpoint_materialize_hf.py::test_unified_chat_template_refuses_a_base_whose_preferred_template_sidecar_diverges`","and `tests/test_data_packer_sft.py::test_unified_export_tokenizer_loads_the_canonical_text_and_a_divergent_jinja_sidecar_is_refused`","(a real tokenizer load from a unified export of a toy base: canonical; with the Jinja beside it: the Jinja);","the directory rule and the preflight order:","`tests/test_checkpoint_materialize_hf.py::test_unified_template_directory_rule_is_one_helper_for_preflight_and_verifier`","and `tests/test_checkpoint_materialize_hf.py::test_force_rebuild_keeps_the_existing_output_when_a_torch_free_preflight_refuses`.","Prefix rows (section 4) are exact under the default serve of a default export. Offline proof on the real","base's sidecars: the tokenizer loaded from a unified scratch export renders req_012 (messages normalised as","vLLM does: `developer` to `system`, `content: null` to `\"\"`, `reasoning` as `reasoning_content`, argument","strings parsed, the image placeholder expanded to its 209 tokens; its two replayed reasoning strings begin and","end with a newline) to 8,969 ids with positions 7248, 7254, 8016, 8025 reading 198, 624, 198, 624 (the","stripped form: `\\n` and `.\\n`); the verbatim processor template renders 8,969 ids with 271, 382, 271, 382 at","the same positions (the padded form: `\\n\\n` and `.\\n\\n`), pinned beside it; the base's tokenizer renders","8,946. Consequence: the shared-vocabulary identity of `config/build.py` hashes the tokenizer's","`chat_template`, so a unified export is not an OPD teacher for a student loaded from the default sidecars (and","the reverse); pair teacher and student on the same choice. Serve assumption, recorded in `.materialized`","beside the shas (`chat_template.serve_assumption`): the serve sets no `enable_thinking`. Under the unified","template a request that sets `enable_thinking=true` is prefilled with the opener token itself,","`\u003c|im_start|\u003eassistant\\n\u003cthink\u003e` (id 151667, no newline after it: 251 vs 250 ids; the same tail without tools,","`\\n`, `\u003c|im_start|\u003e`, `assistant`, `\\n`, `\u003cthink\u003e`, 10 ids against 9), while the rows supervise the opener as","the student's first token; under such a serve `rl.mask_think_opener=True` masks exactly that one token and the","supervised target begins with the newline that opens the reasoning text (the rule of an `opener: prefilled`","row, section 4). The agent harness sends no `enable_thinking`, and the student's serve recipe must not set it.","Fixtures:","`tests/test_checkpoint_materialize_hf.py::test_unified_chat_template_rewrites_the_tokenizer_template_only_and_is_verified_by_rule`","and `test_main_unified_chat_template_option_identity_and_skip`; the padded and stripped forms side by side on","the official template through the toy tokenizer (same count, `\\n\\n` tokens become `\\n` tokens; a trimmed","string renders identically under both):","`tests/test_data_packer_sft.py::test_processor_canonical_template_trims_the_replayed_reasoning_where_the_verbatim_template_pads_it`.","","## 8. Extension points","","Keep tensor shaping in `data/packer/sft.py`, objective math in `algorithm/sft.py`, model","adaptation in `model/qwen3_5.py`, and lifecycle orchestration in `entrypoints/sft.py`."],"stylingDirectives":[[[0,5,"pl-mh"],[2,5,"pl-en"]],[],[[0,23,"pl-mh"],[3,23,"pl-en"]],[],[[81,82,"pl-s"],[82,92,"pl-c1"],[92,93,"pl-s"]],[[4,5,"pl-s"],[22,23,"pl-s"],[23,24,"pl-s"],[24,97,"pl-corl"],[97,98,"pl-s"],[107,108,"pl-s"],[108,124,"pl-c1"],[124,125,"pl-s"]],[[11,12,"pl-s"],[12,19,"pl-c1"],[19,20,"pl-s"]],[],[],[],[],[],[[25,26,"pl-s"],[26,42,"pl-c1"],[42,43,"pl-s"]],[[55,56,"pl-s"],[56,74,"pl-c1"],[74,75,"pl-s"]],[[0,1,"pl-s"],[1,21,"pl-c1"],[21,22,"pl-s"]],[[1,2,"pl-s"],[2,20,"pl-c1"],[20,21,"pl-s"]],[[41,42,"pl-s"],[59,60,"pl-s"],[60,61,"pl-s"],[61,131,"pl-corl"],[131,132,"pl-s"]],[],[],[],[[12,13,"pl-s"],[13,29,"pl-c1"],[29,30,"pl-s"],[35,36,"pl-s"],[36,69,"pl-c1"],[69,70,"pl-s"]],[[31,32,"pl-s"],[32,47,"pl-c1"],[47,48,"pl-s"],[57,58,"pl-s"],[58,63,"pl-c1"],[63,64,"pl-s"]],[],[[22,23,"pl-s"],[23,52,"pl-c1"],[52,53,"pl-s"],[68,69,"pl-s"],[69,83,"pl-c1"],[83,84,"pl-s"],[88,89,"pl-s"],[89,100,"pl-c1"],[100,101,"pl-s"]],[[18,19,"pl-s"],[19,23,"pl-c1"],[23,24,"pl-s"],[33,34,"pl-s"],[34,56,"pl-c1"],[56,57,"pl-s"]],[],[],[[0,17,"pl-mh"],[3,17,"pl-en"]],[],[],[[0,1,"pl-s"],[34,35,"pl-s"],[35,36,"pl-s"],[36,83,"pl-corl"],[83,84,"pl-s"]],[[57,58,"pl-s"],[58,61,"pl-c1"],[61,62,"pl-s"]],[[1,2,"pl-s"],[28,29,"pl-s"],[29,30,"pl-s"],[30,82,"pl-corl"],[82,83,"pl-s"]],[],[[0,3,"pl-s"],[3,7,"pl-en"]],[[0,96,"pl-c"],[0,1,"pl-c"]],[[0,71,"pl-c"],[0,1,"pl-c"]],[[0,96,"pl-c"],[0,1,"pl-c"]],[[23,68,"pl-s"],[23,24,"pl-pds"],[24,28,"pl-smi"],[67,68,"pl-pds"]],[],[],[[0,6,"pl-k"],[18,74,"pl-s"],[18,19,"pl-pds"],[19,23,"pl-smi"],[73,74,"pl-pds"]],[[0,6,"pl-k"]],[],[[0,50,"pl-c"],[0,1,"pl-c"]],[],[],[],[[0,6,"pl-k"],[22,57,"pl-s"],[22,23,"pl-pds"],[23,27,"pl-smi"],[56,57,"pl-pds"]],[[0,6,"pl-k"],[21,52,"pl-s"],[21,22,"pl-pds"],[22,26,"pl-smi"],[51,52,"pl-pds"]],[[0,13,"pl-s"],[0,1,"pl-pds"],[1,12,"pl-smi"],[12,13,"pl-pds"],[81,97,"pl-s"],[81,82,"pl-pds"],[82,96,"pl-smi"],[96,97,"pl-pds"]],[[0,13,"pl-s"],[0,1,"pl-pds"],[1,12,"pl-smi"],[12,13,"pl-pds"]],[[0,13,"pl-s"],[0,1,"pl-pds"],[1,12,"pl-smi"],[12,13,"pl-pds"]],[],[[0,73,"pl-c"],[0,1,"pl-c"]],[[0,13,"pl-s"],[0,1,"pl-pds"],[1,12,"pl-smi"],[12,13,"pl-pds"],[69,73,"pl-s"],[69,70,"pl-pds"],[70,72,"pl-smi"],[72,73,"pl-pds"]],[],[[0,3,"pl-s"]],[],[],[],[],[],[[15,16,"pl-s"],[16,31,"pl-c1"],[31,32,"pl-s"]],[],[[18,19,"pl-s"],[36,37,"pl-s"],[37,38,"pl-s"],[38,120,"pl-corl"],[120,121,"pl-s"]],[],[],[[33,34,"pl-s"],[34,74,"pl-c1"],[74,75,"pl-s"]],[[0,1,"pl-s"],[1,32,"pl-c1"],[32,33,"pl-s"],[55,56,"pl-s"],[56,72,"pl-c1"],[72,73,"pl-s"]],[],[[14,15,"pl-s"],[15,20,"pl-c1"],[20,21,"pl-s"]],[],[[0,19,"pl-mh"],[3,19,"pl-en"]],[],[],[],[[0,3,"pl-s"],[3,7,"pl-en"]],[[1,11,"pl-ent"],[14,20,"pl-ent"],[21,27,"pl-s"],[21,22,"pl-pds"],[26,27,"pl-pds"],[28,37,"pl-ent"],[40,46,"pl-ent"],[47,54,"pl-s"],[47,48,"pl-pds"],[53,54,"pl-pds"],[55,62,"pl-ent"],[63,80,"pl-s"],[63,64,"pl-pds"],[79,80,"pl-pds"],[83,89,"pl-ent"],[90,96,"pl-s"],[90,91,"pl-pds"],[95,96,"pl-pds"],[97,103,"pl-ent"],[104,131,"pl-s"],[104,105,"pl-pds"],[130,131,"pl-pds"],[136,142,"pl-ent"],[143,154,"pl-s"],[143,144,"pl-pds"],[153,154,"pl-pds"],[155,164,"pl-ent"],[165,171,"pl-s"],[165,166,"pl-pds"],[170,171,"pl-pds"],[174,180,"pl-ent"],[181,187,"pl-s"],[181,182,"pl-pds"],[186,187,"pl-pds"],[188,197,"pl-ent"],[198,220,"pl-s"],[198,199,"pl-pds"],[219,220,"pl-pds"],[223,229,"pl-ent"],[230,241,"pl-s"],[230,231,"pl-pds"],[240,241,"pl-pds"],[242,251,"pl-ent"],[252,258,"pl-s"],[252,253,"pl-pds"],[257,258,"pl-pds"]],[[0,3,"pl-s"]],[],[[0,1,"pl-v"],[9,10,"pl-s"],[10,16,"pl-c1"],[16,17,"pl-s"],[32,33,"pl-s"],[33,37,"pl-c1"],[37,38,"pl-s"],[40,41,"pl-s"],[41,50,"pl-c1"],[50,51,"pl-s"],[57,58,"pl-s"],[58,62,"pl-c1"],[62,63,"pl-s"]],[[2,3,"pl-s"],[3,31,"pl-c1"],[31,32,"pl-s"],[50,51,"pl-s"],[51,81,"pl-c1"],[81,82,"pl-s"]],[[0,1,"pl-v"],[11,12,"pl-s"],[12,17,"pl-c1"],[17,18,"pl-s"],[30,31,"pl-s"],[31,41,"pl-c1"],[41,42,"pl-s"],[48,49,"pl-s"],[49,66,"pl-c1"],[66,67,"pl-s"]],[],[[0,1,"pl-v"],[11,12,"pl-s"],[12,21,"pl-c1"],[21,22,"pl-s"],[34,35,"pl-s"],[35,48,"pl-c1"],[48,49,"pl-s"],[87,88,"pl-s"],[88,102,"pl-c1"],[102,103,"pl-s"]],[[32,33,"pl-s"],[33,37,"pl-c1"],[37,38,"pl-s"]],[],[[0,1,"pl-v"],[11,12,"pl-s"],[12,18,"pl-c1"],[18,19,"pl-s"],[31,32,"pl-s"],[32,36,"pl-c1"],[36,37,"pl-s"],[75,76,"pl-s"],[76,85,"pl-c1"],[85,86,"pl-s"]],[[44,45,"pl-s"],[45,56,"pl-c1"],[56,57,"pl-s"]],[[22,23,"pl-s"],[23,29,"pl-c1"],[29,30,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,15,"pl-c1"],[15,16,"pl-s"],[21,22,"pl-s"],[22,45,"pl-c1"],[45,46,"pl-s"],[69,70,"pl-s"],[70,91,"pl-c1"],[91,92,"pl-s"]],[[33,34,"pl-s"],[34,45,"pl-c1"],[45,46,"pl-s"]],[[0,1,"pl-v"]],[],[[0,1,"pl-v"],[57,58,"pl-s"],[58,68,"pl-c1"],[68,69,"pl-s"]],[[35,36,"pl-s"],[36,46,"pl-c1"],[46,47,"pl-s"]],[[0,1,"pl-v"],[17,18,"pl-s"],[18,33,"pl-c1"],[33,34,"pl-s"],[40,41,"pl-s"],[41,55,"pl-c1"],[55,56,"pl-s"]],[[32,33,"pl-s"],[33,53,"pl-c1"],[53,54,"pl-s"]],[],[[0,1,"pl-v"]],[],[],[[0,27,"pl-mh"],[3,27,"pl-en"]],[],[[70,71,"pl-s"],[71,93,"pl-c1"],[93,94,"pl-s"]],[],[[51,52,"pl-s"],[52,69,"pl-c1"],[69,70,"pl-s"]],[[18,19,"pl-s"],[19,26,"pl-c1"],[26,27,"pl-s"]],[],[],[],[],[[0,2,"pl-s"],[25,26,"pl-s"],[26,35,"pl-c1"],[35,36,"pl-s"],[38,40,"pl-s"],[49,50,"pl-s"],[50,59,"pl-c1"],[59,60,"pl-s"]],[[23,24,"pl-s"],[24,37,"pl-c1"],[37,38,"pl-s"]],[[23,24,"pl-s"],[24,34,"pl-c1"],[34,35,"pl-s"],[40,41,"pl-s"],[41,55,"pl-c1"],[55,56,"pl-s"]],[[0,1,"pl-s"],[1,11,"pl-c1"],[11,12,"pl-s"]],[],[[0,1,"pl-s"],[1,23,"pl-c1"],[23,24,"pl-s"],[26,27,"pl-s"],[27,70,"pl-c1"],[70,71,"pl-s"]],[[0,1,"pl-s"],[1,43,"pl-c1"],[43,44,"pl-s"]],[],[[0,1,"pl-s"],[1,21,"pl-c1"],[21,22,"pl-s"],[72,73,"pl-s"],[73,79,"pl-c1"],[79,80,"pl-s"]],[[43,45,"pl-s"],[56,58,"pl-s"]],[],[],[],[],[],[[35,37,"pl-s"],[50,52,"pl-s"]],[],[[45,47,"pl-s"],[61,63,"pl-s"]],[[24,25,"pl-s"],[25,48,"pl-c1"],[48,49,"pl-s"]],[],[[0,1,"pl-s"],[1,94,"pl-c1"],[94,95,"pl-s"]],[[50,51,"pl-s"],[56,57,"pl-s"],[93,94,"pl-s"],[95,96,"pl-s"]],[[0,1,"pl-s"],[1,15,"pl-c1"],[15,16,"pl-s"]],[[0,1,"pl-s"],[1,75,"pl-c1"],[75,76,"pl-s"]],[],[[0,1,"pl-s"],[1,15,"pl-c1"],[15,16,"pl-s"]],[[17,18,"pl-s"],[18,35,"pl-c1"],[35,36,"pl-s"],[63,64,"pl-s"],[64,71,"pl-c1"],[71,72,"pl-s"]],[[10,11,"pl-s"],[11,28,"pl-c1"],[28,29,"pl-s"]],[[40,41,"pl-s"],[41,56,"pl-c1"],[56,57,"pl-s"]],[],[[0,1,"pl-s"],[1,106,"pl-c1"],[106,107,"pl-s"]],[],[],[[0,1,"pl-s"],[1,18,"pl-c1"],[18,19,"pl-s"],[23,24,"pl-s"],[24,39,"pl-c1"],[39,40,"pl-s"]],[[0,1,"pl-s"],[1,14,"pl-c1"],[14,15,"pl-s"]],[],[[0,2,"pl-s"],[20,21,"pl-s"],[21,27,"pl-c1"],[27,28,"pl-s"],[30,32,"pl-s"],[41,42,"pl-s"],[42,48,"pl-c1"],[48,49,"pl-s"]],[[0,1,"pl-s"],[1,8,"pl-c1"],[8,9,"pl-s"],[52,53,"pl-s"],[53,57,"pl-c1"],[57,58,"pl-s"]],[],[[3,4,"pl-s"],[4,13,"pl-c1"],[13,14,"pl-s"],[60,61,"pl-s"],[61,91,"pl-c1"],[91,92,"pl-s"]],[[89,90,"pl-s"],[90,97,"pl-c1"],[97,98,"pl-s"]],[[80,81,"pl-s"],[81,106,"pl-c1"],[106,107,"pl-s"]],[],[[6,7,"pl-s"],[7,21,"pl-c1"],[21,22,"pl-s"],[74,75,"pl-s"],[75,92,"pl-c1"],[92,93,"pl-s"]],[[5,6,"pl-s"],[6,28,"pl-c1"],[28,29,"pl-s"]],[],[],[[0,1,"pl-s"],[1,12,"pl-c1"],[12,13,"pl-s"],[57,58,"pl-s"],[58,64,"pl-c1"],[64,65,"pl-s"]],[[22,23,"pl-s"],[23,34,"pl-c1"],[34,35,"pl-s"],[69,70,"pl-s"],[70,79,"pl-c1"],[79,80,"pl-s"],[84,85,"pl-s"],[85,89,"pl-c1"],[89,90,"pl-s"]],[[51,52,"pl-s"],[52,72,"pl-c1"],[72,73,"pl-s"]],[[1,2,"pl-s"],[2,65,"pl-c1"],[65,66,"pl-s"]],[[0,1,"pl-s"],[1,63,"pl-c1"],[63,64,"pl-s"]],[[32,33,"pl-s"],[33,42,"pl-c1"],[42,43,"pl-s"],[71,72,"pl-s"],[72,79,"pl-c1"],[79,80,"pl-s"],[95,96,"pl-s"],[96,105,"pl-c1"],[105,106,"pl-s"]],[],[[52,53,"pl-s"],[53,60,"pl-c1"],[60,61,"pl-s"]],[[74,75,"pl-s"],[75,84,"pl-c1"],[84,85,"pl-s"]],[[25,26,"pl-s"],[26,39,"pl-c1"],[39,40,"pl-s"],[57,58,"pl-s"],[58,72,"pl-c1"],[72,73,"pl-s"]],[[0,1,"pl-s"],[1,26,"pl-c1"],[26,27,"pl-s"],[43,44,"pl-s"],[44,64,"pl-c1"],[64,65,"pl-s"]],[],[[84,85,"pl-s"],[85,99,"pl-c1"],[99,100,"pl-s"]],[[25,26,"pl-s"],[26,35,"pl-c1"],[35,36,"pl-s"],[59,60,"pl-s"],[60,71,"pl-c1"],[71,72,"pl-s"]],[[0,1,"pl-s"],[1,114,"pl-c1"],[114,115,"pl-s"]],[[90,91,"pl-s"],[91,104,"pl-c1"],[104,105,"pl-s"]],[[0,1,"pl-s"],[1,5,"pl-c1"],[5,6,"pl-s"],[13,14,"pl-s"],[21,22,"pl-s"],[27,28,"pl-s"],[28,37,"pl-c1"],[37,38,"pl-s"],[45,46,"pl-s"],[53,54,"pl-s"],[62,63,"pl-s"],[63,77,"pl-c1"],[77,78,"pl-s"]],[],[[19,20,"pl-s"],[20,74,"pl-c1"],[74,75,"pl-s"]],[[0,1,"pl-s"],[1,65,"pl-c1"],[65,66,"pl-s"]],[[0,1,"pl-s"],[1,67,"pl-c1"],[67,68,"pl-s"]],[],[[0,1,"pl-s"],[1,97,"pl-c1"],[97,98,"pl-s"]],[[0,1,"pl-s"],[1,102,"pl-c1"],[102,103,"pl-s"]],[],[[0,1,"pl-s"],[1,79,"pl-c1"],[79,80,"pl-s"]],[[28,29,"pl-s"],[29,43,"pl-c1"],[43,44,"pl-s"]],[[0,1,"pl-s"],[1,26,"pl-c1"],[26,27,"pl-s"],[58,59,"pl-s"],[59,66,"pl-c1"],[66,67,"pl-s"]],[[44,45,"pl-s"],[45,50,"pl-c1"],[50,51,"pl-s"]],[[0,1,"pl-s"],[1,16,"pl-c1"],[16,17,"pl-s"],[24,25,"pl-s"],[25,41,"pl-c1"],[41,42,"pl-s"]],[[62,63,"pl-s"],[63,86,"pl-c1"],[86,87,"pl-s"]],[[44,45,"pl-s"],[45,54,"pl-c1"],[54,55,"pl-s"],[71,72,"pl-s"],[72,87,"pl-c1"],[87,88,"pl-s"]],[[0,1,"pl-s"],[1,12,"pl-c1"],[12,13,"pl-s"]],[[0,1,"pl-s"],[1,45,"pl-c1"],[45,46,"pl-s"],[74,75,"pl-s"],[75,82,"pl-c1"],[82,83,"pl-s"]],[[64,65,"pl-s"],[65,81,"pl-c1"],[81,82,"pl-s"]],[],[[62,63,"pl-s"],[63,67,"pl-c1"],[67,68,"pl-s"]],[[7,8,"pl-s"],[8,12,"pl-c1"],[12,13,"pl-s"]],[[34,35,"pl-s"],[35,46,"pl-c1"],[46,47,"pl-s"]],[],[[46,47,"pl-s"],[47,55,"pl-c1"],[55,56,"pl-s"]],[],[[22,23,"pl-s"],[23,49,"pl-c1"],[49,50,"pl-s"],[68,69,"pl-s"],[69,77,"pl-c1"],[77,78,"pl-s"]],[[16,17,"pl-s"],[17,25,"pl-c1"],[25,26,"pl-s"],[52,53,"pl-s"],[53,60,"pl-c1"],[60,61,"pl-s"]],[[30,31,"pl-s"],[31,35,"pl-c1"],[35,36,"pl-s"]],[[0,1,"pl-s"],[1,9,"pl-c1"],[9,10,"pl-s"],[52,53,"pl-s"],[53,58,"pl-c1"],[58,59,"pl-s"]],[],[[4,5,"pl-s"],[5,21,"pl-c1"],[21,22,"pl-s"],[52,53,"pl-s"],[53,86,"pl-c1"],[86,87,"pl-s"]],[[78,79,"pl-s"],[79,86,"pl-c1"],[86,87,"pl-s"]],[[83,84,"pl-s"],[84,93,"pl-c1"],[93,94,"pl-s"]],[[18,19,"pl-s"],[19,44,"pl-c1"],[44,45,"pl-s"],[73,74,"pl-s"],[74,90,"pl-c1"],[90,91,"pl-s"]],[[10,11,"pl-s"],[11,13,"pl-c1"],[13,14,"pl-s"],[31,32,"pl-s"],[32,39,"pl-c1"],[39,40,"pl-s"]],[[33,34,"pl-s"],[34,48,"pl-c1"],[48,49,"pl-s"]],[[35,36,"pl-s"],[36,51,"pl-c1"],[51,52,"pl-s"],[78,79,"pl-s"],[79,86,"pl-c1"],[86,87,"pl-s"]],[],[[68,69,"pl-s"],[69,74,"pl-c1"],[74,75,"pl-s"]],[],[],[[43,44,"pl-s"],[44,51,"pl-c1"],[51,52,"pl-s"]],[],[],[],[[14,16,"pl-s"],[53,55,"pl-s"]],[],[[64,65,"pl-s"],[65,81,"pl-c1"],[81,82,"pl-s"]],[],[[0,1,"pl-s"],[1,14,"pl-c1"],[14,15,"pl-s"],[63,64,"pl-s"],[64,67,"pl-c1"],[67,68,"pl-s"]],[[0,1,"pl-s"],[1,17,"pl-c1"],[17,18,"pl-s"],[20,21,"pl-s"],[21,24,"pl-c1"],[24,25,"pl-s"],[85,86,"pl-s"],[86,87,"pl-c1"],[87,88,"pl-s"]],[[18,19,"pl-s"],[19,37,"pl-c1"],[37,38,"pl-s"]],[[0,1,"pl-s"],[1,41,"pl-c1"],[41,42,"pl-s"]],[[9,10,"pl-s"],[10,13,"pl-c1"],[13,14,"pl-s"],[74,75,"pl-s"],[75,98,"pl-c1"],[98,99,"pl-s"]],[[0,1,"pl-s"],[1,4,"pl-c1"],[4,5,"pl-s"],[36,37,"pl-s"],[37,51,"pl-c1"],[51,52,"pl-s"],[54,55,"pl-s"],[55,77,"pl-c1"],[77,78,"pl-s"]],[[56,57,"pl-s"],[57,72,"pl-c1"],[72,73,"pl-s"]],[[19,20,"pl-s"],[20,34,"pl-c1"],[34,35,"pl-s"]],[],[],[[0,16,"pl-mh"],[3,16,"pl-en"]],[],[[32,33,"pl-s"],[33,84,"pl-c1"],[84,85,"pl-s"]],[[0,1,"pl-s"],[1,13,"pl-c1"],[13,14,"pl-s"],[41,42,"pl-s"],[42,55,"pl-c1"],[55,56,"pl-s"]],[[0,1,"pl-s"],[1,15,"pl-c1"],[15,16,"pl-s"],[62,63,"pl-s"],[63,75,"pl-c1"],[75,76,"pl-s"],[85,86,"pl-s"],[86,90,"pl-c1"],[90,91,"pl-s"]],[[0,1,"pl-s"],[1,20,"pl-c1"],[20,21,"pl-s"],[55,56,"pl-s"],[56,64,"pl-c1"],[64,65,"pl-s"]],[[0,1,"pl-s"],[1,7,"pl-c1"],[7,8,"pl-s"],[44,45,"pl-s"],[45,72,"pl-c1"],[72,73,"pl-s"],[80,81,"pl-s"],[81,88,"pl-c1"],[88,89,"pl-s"]],[[30,31,"pl-s"],[31,43,"pl-c1"],[43,44,"pl-s"],[66,67,"pl-s"],[67,72,"pl-c1"],[72,73,"pl-s"],[77,78,"pl-s"],[78,89,"pl-c1"],[89,90,"pl-s"]],[[0,1,"pl-s"],[1,10,"pl-c1"],[10,11,"pl-s"],[14,15,"pl-s"],[15,42,"pl-c1"],[42,43,"pl-s"]],[[16,17,"pl-s"],[17,38,"pl-c1"],[38,39,"pl-s"]],[[63,64,"pl-s"],[64,86,"pl-c1"],[86,87,"pl-s"]],[],[[1,2,"pl-s"],[2,25,"pl-c1"],[25,26,"pl-s"],[28,29,"pl-s"],[29,51,"pl-c1"],[51,52,"pl-s"]],[[33,34,"pl-s"],[34,67,"pl-c1"],[67,68,"pl-s"]],[],[],[],[[47,48,"pl-s"],[48,80,"pl-c1"],[80,81,"pl-s"]],[],[[0,1,"pl-s"],[1,32,"pl-c1"],[32,33,"pl-s"]],[[18,19,"pl-s"],[19,51,"pl-c1"],[51,52,"pl-s"]],[],[],[],[[52,53,"pl-s"],[53,74,"pl-c1"],[74,75,"pl-s"],[79,80,"pl-s"],[80,93,"pl-c1"],[93,94,"pl-s"]],[[0,1,"pl-s"],[1,83,"pl-c1"],[83,84,"pl-s"]],[],[[3,4,"pl-s"],[4,41,"pl-c1"],[41,42,"pl-s"]],[],[[0,1,"pl-s"],[1,16,"pl-c1"],[16,17,"pl-s"]],[],[[0,1,"pl-s"],[1,56,"pl-c1"],[56,57,"pl-s"]],[[0,1,"pl-s"],[1,18,"pl-c1"],[18,19,"pl-s"],[58,59,"pl-s"],[74,75,"pl-s"]],[[11,12,"pl-s"],[12,18,"pl-c1"],[18,19,"pl-s"]],[[0,1,"pl-s"],[1,24,"pl-c1"],[24,25,"pl-s"]],[],[],[],[],[],[[0,1,"pl-s"],[1,20,"pl-c1"],[20,21,"pl-s"],[33,34,"pl-s"],[34,47,"pl-c1"],[47,48,"pl-s"],[53,54,"pl-s"],[54,67,"pl-c1"],[67,68,"pl-s"]],[[0,1,"pl-s"],[1,19,"pl-c1"],[19,20,"pl-s"],[21,22,"pl-s"],[22,34,"pl-c1"],[34,35,"pl-s"],[61,62,"pl-s"],[62,72,"pl-c1"],[72,73,"pl-s"],[74,75,"pl-s"],[75,85,"pl-c1"],[85,86,"pl-s"]],[[40,41,"pl-s"],[41,49,"pl-c1"],[49,50,"pl-s"]],[[34,35,"pl-s"],[35,52,"pl-c1"],[52,53,"pl-s"]],[],[],[],[[0,28,"pl-mh"],[3,28,"pl-en"]],[],[[0,1,"pl-s"],[1,15,"pl-c1"],[15,16,"pl-s"],[21,22,"pl-s"],[22,34,"pl-c1"],[34,35,"pl-s"]],[[46,47,"pl-s"],[47,70,"pl-c1"],[70,71,"pl-s"]],[[0,1,"pl-s"],[1,16,"pl-c1"],[16,17,"pl-s"],[46,47,"pl-s"],[47,66,"pl-c1"],[66,67,"pl-s"],[69,70,"pl-s"],[70,93,"pl-c1"],[93,94,"pl-s"]],[[0,1,"pl-s"],[1,17,"pl-c1"],[17,18,"pl-s"],[20,21,"pl-s"],[21,41,"pl-c1"],[41,42,"pl-s"],[56,57,"pl-s"],[57,72,"pl-c1"],[72,73,"pl-s"]],[[0,1,"pl-s"],[1,39,"pl-c1"],[39,40,"pl-s"],[46,47,"pl-s"],[47,65,"pl-c1"],[65,66,"pl-s"]],[[36,37,"pl-s"],[37,47,"pl-c1"],[47,48,"pl-s"]],[[0,1,"pl-s"],[1,25,"pl-c1"],[25,26,"pl-s"]],[],[[74,75,"pl-s"],[75,76,"pl-c1"],[76,77,"pl-s"]],[[0,1,"pl-s"],[1,10,"pl-c1"],[10,11,"pl-s"]],[],[],[],[],[],[],[[1,2,"pl-s"],[2,11,"pl-c1"],[11,12,"pl-s"]],[],[],[],[[33,34,"pl-s"],[34,49,"pl-c1"],[49,50,"pl-s"]],[],[],[],[[0,36,"pl-mh"],[3,36,"pl-en"]],[],[],[[13,14,"pl-s"],[14,22,"pl-c1"],[22,23,"pl-s"],[39,40,"pl-s"],[40,54,"pl-c1"],[54,55,"pl-s"]],[],[],[],[],[[30,31,"pl-s"],[44,45,"pl-s"],[45,46,"pl-s"],[46,72,"pl-corl"],[72,73,"pl-s"]],[[0,1,"pl-s"],[16,17,"pl-s"],[17,18,"pl-s"],[18,77,"pl-corl"],[77,78,"pl-s"]],[[0,1,"pl-s"],[1,9,"pl-c1"],[9,10,"pl-s"],[82,83,"pl-s"],[83,94,"pl-c1"],[94,95,"pl-s"]],[[60,61,"pl-s"],[61,84,"pl-c1"],[84,85,"pl-s"]],[[55,56,"pl-s"],[56,64,"pl-c1"],[64,65,"pl-s"]],[[90,91,"pl-s"],[91,104,"pl-c1"],[104,105,"pl-s"]],[[0,1,"pl-s"],[1,22,"pl-c1"],[22,23,"pl-s"]],[[0,1,"pl-s"],[1,39,"pl-c1"],[39,40,"pl-s"]],[],[[90,91,"pl-s"],[91,106,"pl-c1"],[106,107,"pl-s"]],[[60,61,"pl-s"],[61,94,"pl-c1"],[94,95,"pl-s"]],[[40,41,"pl-s"],[41,52,"pl-c1"],[52,53,"pl-s"]],[],[[0,2,"pl-s"],[25,26,"pl-s"],[26,49,"pl-c1"],[49,50,"pl-s"],[52,54,"pl-s"],[90,91,"pl-s"],[91,109,"pl-c1"],[109,110,"pl-s"]],[[5,7,"pl-s"],[25,27,"pl-s"],[54,55,"pl-s"],[55,74,"pl-c1"],[74,75,"pl-s"],[81,82,"pl-s"],[82,103,"pl-c1"],[103,104,"pl-s"]],[[0,1,"pl-s"],[1,14,"pl-c1"],[14,15,"pl-s"],[21,23,"pl-s"],[41,43,"pl-s"],[58,59,"pl-s"],[59,78,"pl-c1"],[78,79,"pl-s"]],[[76,77,"pl-s"],[77,94,"pl-c1"],[94,95,"pl-s"]],[[1,2,"pl-s"],[2,20,"pl-c1"],[20,21,"pl-s"]],[],[],[[88,89,"pl-s"],[89,96,"pl-c1"],[96,97,"pl-s"]],[[0,1,"pl-s"],[1,12,"pl-c1"],[12,13,"pl-s"],[82,83,"pl-s"],[83,104,"pl-c1"],[104,105,"pl-s"]],[[0,1,"pl-s"],[1,14,"pl-c1"],[14,15,"pl-s"],[20,21,"pl-s"],[21,39,"pl-c1"],[39,40,"pl-s"],[43,44,"pl-s"],[44,57,"pl-c1"],[57,58,"pl-s"]],[],[[0,1,"pl-s"],[1,11,"pl-c1"],[11,12,"pl-s"],[69,71,"pl-s"],[85,87,"pl-s"]],[[1,2,"pl-s"],[2,36,"pl-c1"],[36,37,"pl-s"]],[[0,1,"pl-s"],[1,66,"pl-c1"],[66,67,"pl-s"]],[],[[16,17,"pl-s"],[17,44,"pl-c1"],[44,45,"pl-s"]],[[0,1,"pl-s"],[1,32,"pl-c1"],[32,33,"pl-s"],[35,36,"pl-s"],[36,81,"pl-c1"],[81,82,"pl-s"]],[],[[11,12,"pl-s"],[12,19,"pl-c1"],[19,20,"pl-s"],[50,51,"pl-s"],[51,64,"pl-c1"],[64,65,"pl-s"],[67,68,"pl-s"],[68,81,"pl-c1"],[81,82,"pl-s"],[84,85,"pl-s"],[85,90,"pl-c1"],[90,91,"pl-s"],[93,94,"pl-s"],[94,108,"pl-c1"],[108,109,"pl-s"]],[[5,6,"pl-s"],[6,35,"pl-c1"],[35,36,"pl-s"],[41,42,"pl-s"],[42,64,"pl-c1"],[64,65,"pl-s"]],[[66,67,"pl-s"],[67,74,"pl-c1"],[74,75,"pl-s"]],[[45,46,"pl-s"],[46,61,"pl-c1"],[61,62,"pl-s"]],[[8,9,"pl-s"],[9,22,"pl-c1"],[22,23,"pl-s"],[60,61,"pl-s"],[61,78,"pl-c1"],[78,79,"pl-s"]],[],[[50,51,"pl-s"],[51,68,"pl-c1"],[68,69,"pl-s"]],[[5,6,"pl-s"],[6,17,"pl-c1"],[17,18,"pl-s"]],[],[],[[42,44,"pl-s"],[56,58,"pl-s"]],[],[],[],[[55,56,"pl-s"],[56,77,"pl-c1"],[77,78,"pl-s"]],[[0,1,"pl-s"],[1,19,"pl-c1"],[19,20,"pl-s"]],[[10,11,"pl-s"],[11,20,"pl-c1"],[20,21,"pl-s"],[97,98,"pl-s"],[98,104,"pl-c1"],[104,105,"pl-s"]],[[1,2,"pl-s"],[2,20,"pl-c1"],[20,21,"pl-s"],[28,29,"pl-s"],[29,33,"pl-c1"],[33,34,"pl-s"],[39,40,"pl-s"],[40,44,"pl-c1"],[44,45,"pl-s"]],[[44,45,"pl-s"],[45,62,"pl-c1"],[62,63,"pl-s"]],[],[[24,25,"pl-s"],[25,34,"pl-c1"],[34,35,"pl-s"]],[[10,11,"pl-s"],[11,46,"pl-c1"],[46,47,"pl-s"],[74,75,"pl-s"],[75,81,"pl-c1"],[81,82,"pl-s"]],[[27,28,"pl-s"],[28,43,"pl-c1"],[43,44,"pl-s"],[62,63,"pl-s"],[63,80,"pl-c1"],[80,81,"pl-s"]],[[0,1,"pl-s"],[1,7,"pl-c1"],[7,8,"pl-s"],[27,28,"pl-s"],[28,45,"pl-c1"],[45,46,"pl-s"],[54,55,"pl-s"],[55,66,"pl-c1"],[66,67,"pl-s"]],[[0,1,"pl-s"],[1,5,"pl-c1"],[5,6,"pl-s"]],[],[[0,1,"pl-s"],[1,130,"pl-c1"],[130,131,"pl-s"]],[[5,6,"pl-s"],[6,23,"pl-c1"],[23,24,"pl-s"]],[[23,24,"pl-s"],[24,42,"pl-c1"],[42,43,"pl-s"],[48,49,"pl-s"],[49,70,"pl-c1"],[70,71,"pl-s"],[74,75,"pl-s"],[75,88,"pl-c1"],[88,89,"pl-s"]],[],[],[[0,1,"pl-s"],[1,35,"pl-c1"],[35,36,"pl-s"]],[],[[42,43,"pl-s"],[43,62,"pl-c1"],[62,63,"pl-s"]],[[0,1,"pl-s"],[1,22,"pl-c1"],[22,23,"pl-s"],[71,72,"pl-s"],[72,90,"pl-c1"],[90,91,"pl-s"]],[[0,1,"pl-s"],[1,27,"pl-c1"],[27,28,"pl-s"]],[[0,1,"pl-s"],[1,19,"pl-c1"],[19,20,"pl-s"]],[],[[0,1,"pl-s"],[1,16,"pl-c1"],[16,17,"pl-s"],[68,69,"pl-s"],[69,84,"pl-c1"],[84,85,"pl-s"]],[[61,62,"pl-s"],[62,75,"pl-c1"],[75,76,"pl-s"],[84,85,"pl-s"],[85,106,"pl-c1"],[106,107,"pl-s"]],[],[[12,13,"pl-s"],[13,26,"pl-c1"],[26,27,"pl-s"]],[[39,40,"pl-s"],[40,51,"pl-c1"],[51,52,"pl-s"]],[[72,73,"pl-s"],[73,80,"pl-c1"],[80,81,"pl-s"]],[[9,10,"pl-s"],[10,19,"pl-c1"],[19,20,"pl-s"]],[],[[1,2,"pl-s"],[2,23,"pl-c1"],[23,24,"pl-s"],[29,30,"pl-s"],[30,48,"pl-c1"],[48,49,"pl-s"]],[[51,52,"pl-s"],[52,78,"pl-c1"],[78,79,"pl-s"]],[],[],[[0,1,"pl-s"],[1,126,"pl-c1"],[126,127,"pl-s"]],[[0,1,"pl-s"],[1,100,"pl-c1"],[100,101,"pl-s"]],[[0,1,"pl-s"],[1,87,"pl-c1"],[87,88,"pl-s"]],[],[[1,2,"pl-s"],[2,28,"pl-c1"],[28,29,"pl-s"]],[[53,54,"pl-s"],[54,69,"pl-c1"],[69,70,"pl-s"]],[],[[85,86,"pl-s"],[86,104,"pl-c1"],[104,105,"pl-s"]],[[35,36,"pl-s"],[36,49,"pl-c1"],[49,50,"pl-s"],[104,105,"pl-s"],[105,107,"pl-c1"],[107,108,"pl-s"]],[[14,15,"pl-s"],[15,28,"pl-c1"],[28,29,"pl-s"],[32,33,"pl-s"],[33,49,"pl-c1"],[49,50,"pl-s"],[57,58,"pl-s"],[58,60,"pl-c1"],[60,61,"pl-s"]],[[78,79,"pl-s"],[79,89,"pl-c1"],[89,90,"pl-s"]],[],[],[[0,1,"pl-s"],[1,102,"pl-c1"],[102,103,"pl-s"]],[],[[0,1,"pl-s"],[1,102,"pl-c1"],[102,103,"pl-s"]],[[0,1,"pl-s"],[1,78,"pl-c1"],[78,79,"pl-s"]],[[0,1,"pl-s"],[1,100,"pl-c1"],[100,101,"pl-s"]],[[0,1,"pl-s"],[1,84,"pl-c1"],[84,85,"pl-s"]],[[63,64,"pl-s"],[64,95,"pl-c1"],[95,96,"pl-s"]],[[11,12,"pl-s"],[12,26,"pl-c1"],[26,27,"pl-s"],[29,30,"pl-s"],[30,45,"pl-c1"],[45,46,"pl-s"]],[],[[27,28,"pl-s"],[28,45,"pl-c1"],[45,46,"pl-s"]],[[69,70,"pl-s"],[70,90,"pl-c1"],[90,91,"pl-s"]],[[0,1,"pl-s"],[1,22,"pl-c1"],[22,23,"pl-s"],[30,31,"pl-s"],[31,43,"pl-c1"],[43,44,"pl-s"]],[[46,47,"pl-s"],[47,59,"pl-c1"],[59,60,"pl-s"]],[[9,10,"pl-s"],[10,22,"pl-c1"],[22,23,"pl-s"]],[],[[0,1,"pl-s"],[1,89,"pl-c1"],[89,90,"pl-s"]],[[0,1,"pl-s"],[1,94,"pl-c1"],[94,95,"pl-s"]],[[51,52,"pl-s"],[52,61,"pl-c1"],[61,62,"pl-s"]],[],[[18,19,"pl-s"],[19,38,"pl-c1"],[38,39,"pl-s"],[87,88,"pl-s"],[88,99,"pl-c1"],[99,100,"pl-s"]],[[45,46,"pl-s"],[46,59,"pl-c1"],[59,60,"pl-s"]],[[82,83,"pl-s"],[83,88,"pl-c1"],[88,89,"pl-s"],[93,94,"pl-s"],[94,108,"pl-c1"],[108,109,"pl-s"]],[[0,1,"pl-s"],[1,10,"pl-c1"],[10,11,"pl-s"],[15,16,"pl-s"],[16,21,"pl-c1"],[21,22,"pl-s"],[24,25,"pl-s"],[25,39,"pl-c1"],[39,40,"pl-s"],[50,51,"pl-s"],[51,81,"pl-c1"],[81,82,"pl-s"]],[],[[6,7,"pl-s"],[7,26,"pl-c1"],[26,27,"pl-s"]],[[29,30,"pl-s"],[30,45,"pl-c1"],[45,46,"pl-s"],[72,73,"pl-s"],[73,87,"pl-c1"],[87,88,"pl-s"]],[[13,14,"pl-s"],[14,21,"pl-c1"],[21,22,"pl-s"]],[[15,16,"pl-s"],[16,54,"pl-c1"],[54,55,"pl-s"],[57,58,"pl-s"],[58,67,"pl-c1"],[67,68,"pl-s"]],[],[[5,6,"pl-s"],[6,9,"pl-c1"],[9,10,"pl-s"]],[],[[1,2,"pl-s"],[2,21,"pl-c1"],[21,22,"pl-s"],[32,33,"pl-s"],[33,66,"pl-c1"],[66,67,"pl-s"]],[[0,1,"pl-s"],[1,36,"pl-c1"],[36,37,"pl-s"]],[],[[0,1,"pl-s"],[1,97,"pl-c1"],[97,98,"pl-s"]],[[0,1,"pl-s"],[1,98,"pl-c1"],[98,99,"pl-s"]],[[0,1,"pl-s"],[1,97,"pl-c1"],[97,98,"pl-s"]],[[0,1,"pl-s"],[1,92,"pl-c1"],[92,93,"pl-s"]],[[0,1,"pl-s"],[1,79,"pl-c1"],[79,80,"pl-s"],[89,90,"pl-s"],[90,97,"pl-c1"],[97,98,"pl-s"]],[],[[1,2,"pl-s"],[2,16,"pl-c1"],[16,17,"pl-s"],[36,37,"pl-s"],[37,46,"pl-c1"],[46,47,"pl-s"],[86,87,"pl-s"],[87,92,"pl-c1"],[92,93,"pl-s"]],[[0,1,"pl-s"],[1,15,"pl-c1"],[15,16,"pl-s"],[36,37,"pl-s"],[37,42,"pl-c1"],[42,43,"pl-s"],[94,95,"pl-s"],[95,109,"pl-c1"],[109,110,"pl-s"]],[[19,20,"pl-s"],[20,25,"pl-c1"],[25,26,"pl-s"],[83,84,"pl-s"],[84,91,"pl-c1"],[91,92,"pl-s"]],[[21,22,"pl-s"],[22,31,"pl-c1"],[31,32,"pl-s"],[51,52,"pl-s"],[52,57,"pl-c1"],[57,58,"pl-s"]],[],[[52,53,"pl-s"],[53,62,"pl-c1"],[62,63,"pl-s"]],[[90,91,"pl-s"],[91,98,"pl-c1"],[98,99,"pl-s"]],[[76,77,"pl-s"],[77,88,"pl-c1"],[88,89,"pl-s"]],[[74,75,"pl-s"],[75,85,"pl-c1"],[85,86,"pl-s"]],[[5,6,"pl-s"],[6,17,"pl-c1"],[17,18,"pl-s"],[96,97,"pl-s"],[97,102,"pl-c1"],[102,103,"pl-s"]],[],[[94,95,"pl-s"],[95,100,"pl-c1"],[100,101,"pl-s"]],[],[[0,1,"pl-s"],[1,92,"pl-c1"],[92,93,"pl-s"]],[[0,1,"pl-s"],[1,86,"pl-c1"],[86,87,"pl-s"]],[[0,1,"pl-s"],[1,85,"pl-c1"],[85,86,"pl-s"]],[[0,1,"pl-s"],[1,78,"pl-c1"],[78,79,"pl-s"]],[[0,1,"pl-s"],[1,89,"pl-c1"],[89,90,"pl-s"]],[[16,17,"pl-s"],[17,26,"pl-c1"],[26,27,"pl-s"],[65,66,"pl-s"],[66,79,"pl-c1"],[79,80,"pl-s"]],[],[[15,16,"pl-s"],[16,27,"pl-c1"],[27,28,"pl-s"]],[],[],[[47,48,"pl-s"],[48,71,"pl-c1"],[71,72,"pl-s"]],[[0,1,"pl-s"],[1,9,"pl-c1"],[9,10,"pl-s"],[14,15,"pl-s"],[15,23,"pl-c1"],[23,24,"pl-s"]],[[0,1,"pl-s"],[1,24,"pl-c1"],[24,25,"pl-s"]],[[51,52,"pl-s"],[52,57,"pl-c1"],[57,58,"pl-s"]],[],[],[],[[39,40,"pl-s"],[40,59,"pl-c1"],[59,60,"pl-s"]],[],[],[[10,11,"pl-s"],[11,88,"pl-c1"],[88,89,"pl-s"]],[[0,1,"pl-s"],[1,115,"pl-c1"],[115,116,"pl-s"]],[[0,1,"pl-s"],[1,100,"pl-c1"],[100,101,"pl-s"]],[[0,1,"pl-s"],[1,71,"pl-c1"],[71,72,"pl-s"]],[[0,1,"pl-s"],[1,64,"pl-c1"],[64,65,"pl-s"]],[[0,1,"pl-s"],[1,102,"pl-c1"],[102,103,"pl-s"]],[[41,42,"pl-s"],[42,45,"pl-c1"],[45,46,"pl-s"],[51,52,"pl-s"],[52,55,"pl-c1"],[55,56,"pl-s"]],[[0,1,"pl-s"],[1,51,"pl-c1"],[51,52,"pl-s"]],[[0,1,"pl-s"],[1,9,"pl-c1"],[9,10,"pl-s"]],[[53,54,"pl-s"],[54,67,"pl-c1"],[67,68,"pl-s"]],[],[],[],[],[[60,61,"pl-s"],[61,69,"pl-c1"],[69,70,"pl-s"]],[],[],[],[],[],[],[[0,1,"pl-s"],[1,99,"pl-c1"],[99,100,"pl-s"]],[[0,1,"pl-s"],[1,87,"pl-c1"],[87,88,"pl-s"]],[[0,1,"pl-s"],[1,91,"pl-c1"],[91,92,"pl-s"]],[[12,13,"pl-s"],[13,70,"pl-c1"],[70,71,"pl-s"]],[[0,1,"pl-s"],[1,114,"pl-c1"],[114,115,"pl-s"]],[],[[0,1,"pl-s"],[1,98,"pl-c1"],[98,99,"pl-s"]],[[38,39,"pl-s"],[39,52,"pl-c1"],[52,53,"pl-s"],[56,57,"pl-s"],[57,70,"pl-c1"],[70,71,"pl-s"],[74,75,"pl-s"],[75,91,"pl-c1"],[91,92,"pl-s"],[93,94,"pl-s"],[94,109,"pl-c1"],[109,110,"pl-s"]],[],[],[],[[71,72,"pl-s"],[72,86,"pl-c1"],[86,87,"pl-s"],[90,91,"pl-s"],[91,93,"pl-c1"],[93,94,"pl-s"]],[[0,1,"pl-s"],[1,25,"pl-c1"],[25,26,"pl-s"],[35,36,"pl-s"],[36,56,"pl-c1"],[56,57,"pl-s"]],[[40,41,"pl-s"],[41,60,"pl-c1"],[60,61,"pl-s"],[68,69,"pl-s"],[69,90,"pl-c1"],[90,91,"pl-s"]],[[73,74,"pl-s"],[74,106,"pl-c1"],[106,107,"pl-s"]],[[0,1,"pl-s"],[1,16,"pl-c1"],[16,17,"pl-s"]],[[0,1,"pl-s"],[1,125,"pl-c1"],[125,126,"pl-s"]],[[4,5,"pl-s"],[5,131,"pl-c1"],[131,132,"pl-s"]],[],[],[[0,1,"pl-s"],[1,119,"pl-c1"],[119,120,"pl-s"]],[[4,5,"pl-s"],[5,126,"pl-c1"],[126,127,"pl-s"]],[],[],[[11,12,"pl-s"],[12,21,"pl-c1"],[21,22,"pl-s"],[26,27,"pl-s"],[27,33,"pl-c1"],[33,34,"pl-s"],[36,37,"pl-s"],[37,50,"pl-c1"],[50,51,"pl-s"],[55,56,"pl-s"],[56,58,"pl-c1"],[58,59,"pl-s"],[61,62,"pl-s"],[62,71,"pl-c1"],[71,72,"pl-s"],[76,77,"pl-s"],[77,94,"pl-c1"],[94,95,"pl-s"]],[],[],[[15,16,"pl-s"],[16,18,"pl-c1"],[18,19,"pl-s"],[24,25,"pl-s"],[25,28,"pl-c1"],[28,29,"pl-s"]],[[37,38,"pl-s"],[38,42,"pl-c1"],[42,43,"pl-s"],[48,49,"pl-s"],[49,54,"pl-c1"],[54,55,"pl-s"]],[[54,55,"pl-s"],[55,70,"pl-c1"],[70,71,"pl-s"]],[[0,1,"pl-s"],[1,14,"pl-c1"],[14,15,"pl-s"]],[[89,90,"pl-s"],[90,103,"pl-c1"],[103,104,"pl-s"]],[[17,18,"pl-s"],[18,48,"pl-c1"],[48,49,"pl-s"],[70,71,"pl-s"],[71,86,"pl-c1"],[86,87,"pl-s"]],[[29,30,"pl-s"],[30,50,"pl-c1"],[50,51,"pl-s"]],[[0,1,"pl-s"],[1,31,"pl-c1"],[31,32,"pl-s"]],[[0,1,"pl-s"],[1,3,"pl-c1"],[3,4,"pl-s"],[6,7,"pl-s"],[7,19,"pl-c1"],[19,20,"pl-s"],[22,23,"pl-s"],[23,32,"pl-c1"],[32,33,"pl-s"],[35,36,"pl-s"],[36,38,"pl-c1"],[38,39,"pl-s"],[41,42,"pl-s"],[42,49,"pl-c1"],[49,50,"pl-s"]],[[46,47,"pl-s"],[47,72,"pl-c1"],[72,73,"pl-s"]],[[88,89,"pl-s"],[89,106,"pl-c1"],[106,107,"pl-s"]],[[44,45,"pl-s"],[45,60,"pl-c1"],[60,61,"pl-s"]],[],[[0,1,"pl-s"],[1,129,"pl-c1"],[129,130,"pl-s"]],[[4,5,"pl-s"],[5,61,"pl-c1"],[61,62,"pl-s"]],[[61,62,"pl-s"],[62,66,"pl-c1"],[66,67,"pl-s"],[82,83,"pl-s"],[83,85,"pl-c1"],[85,86,"pl-s"]],[],[[0,1,"pl-s"],[1,130,"pl-c1"],[130,131,"pl-s"]],[],[[0,22,"pl-mh"],[3,22,"pl-en"]],[],[[23,24,"pl-s"],[24,42,"pl-c1"],[42,43,"pl-s"],[63,64,"pl-s"],[64,80,"pl-c1"],[80,81,"pl-s"]],[[14,15,"pl-s"],[15,31,"pl-c1"],[31,32,"pl-s"],[65,66,"pl-s"],[66,84,"pl-c1"],[84,85,"pl-s"]]],"colorizedLines":null}},"title":"cosmos-framework/docs/posttrain/guides/sft.md at main · NVIDIA/cosmos-framework","appPayload":{},"meta":{"title":"cosmos-framework/docs/posttrain/guides/sft.md at main · NVIDIA/cosmos-framework"}}</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="/NVIDIA/cosmos-framework" 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 SidePanel__RGvnRQ HiddenSidePanel__B93C-7" 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="sidebar__UTbGEu" tabindex="0"><div class="prc-PageLayout-PaneWrapper-pHPop Pane__nWEixw HideTree__atYFw- HidePane__uwpyMP" 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="content__cw9d2I" data-selector="repos-split-pane-content" id="repos-split-pane-content" tabindex="0"> <!-- --> <div class="container Box__Mgy-fH"><div class="StickyHeader__WXzXSk" id="StickyHeader"><div class="Box_1__lNQXUt"><div class="Box_2__2Iyod3"><div class="react-code-view-header-wrap--narrow Box_3__FRi-lt"><div class="treeToggleWrapper__9kKsad"><h2 class="Heading__GnjjJL 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 Button_1__F8O5Sv" 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 expandButton__x9VQso filesButtonBreakpoint__9AmeQg 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 RefSelectorOverlayBtn__KrS-QJ" 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="RefSelectorOverlayContainer__do_QsK"><div style="max-width:125px" class="ref-selector-button-text-container RefSelectorBtnTextContainer__U9K7hH"><span class="RefSelectorText__DKi677">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 Box_5__XARjQx"><div class="container__3CaSnu lg__W8GBuN"><nav data-testid="breadcrumbs" aria-labelledby="repos-header-breadcrumb-heading" id="repos-header-breadcrumb" class="nav__om3y2l"><h2 class="sr-only userSelectNone__I6NSfK prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading" id="repos-header-breadcrumb-heading">Breadcrumbs</h2><ol class="list__l5DBAB"><li class="listItem__z6CNRy"><a class="repoLink__Uax2bT prc-Link-Link-9ZwDx" data-component="Link" data-testid="breadcrumbs-repo-link" href="/NVIDIA/cosmos-framework/tree/main" data-discover="true">cosmos-framework</a></li><li class="listItem__z6CNRy"><span class="separator__FWRrWr lg__W8GBuN" aria-hidden="true">/</span><a class="directoryLink__pFe5bB prc-Link-Link-9ZwDx" data-component="Link" href="/NVIDIA/cosmos-framework/tree/main/docs" data-discover="true">docs</a></li><li class="listItem__z6CNRy"><span class="separator__FWRrWr lg__W8GBuN" aria-hidden="true">/</span><a class="directoryLink__pFe5bB prc-Link-Link-9ZwDx" data-component="Link" href="/NVIDIA/cosmos-framework/tree/main/docs/posttrain" data-discover="true">posttrain</a></li><li class="listItem__z6CNRy"><span class="separator__FWRrWr lg__W8GBuN" aria-hidden="true">/</span><a class="directoryLink__pFe5bB prc-Link-Link-9ZwDx" data-component="Link" href="/NVIDIA/cosmos-framework/tree/main/docs/posttrain/guides" data-discover="true">guides</a></li></ol></nav><div data-testid="breadcrumbs-filename" class="filename__e-5cWV"><span class="separator__FWRrWr lg__W8GBuN" aria-hidden="true">/</span><h1 class="filenameHeading__MTKryR lg__W8GBuN prc-Heading-Heading-MtWFE" data-component="Heading" tabindex="-1" id="file-name-id">sft.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="tooltip__XwO6MO 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="Box_7__UInhGV"><div class="d-flex gap-2"><div><div class="FileResultsList__Sho6qi"><span class="d-flex FilesSearchBox__bU3lGO 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 Button__iESaGa" 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 IconButton__TllxCn 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="Box_7__UInhGV"><div class="d-flex gap-2"><button data-component="Button" type="button" style="display:none" class="prc-Button-ButtonBase-9n-Xk Button__iESaGa" 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 IconButton__TllxCn 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="contentWrapper__h3vMmh"><div class="react-code-view-bottom-padding"><div class="Box__nP_d2G"></div></div> <div class="d-none"></div><div class="d-flex flex-column border rounded-2 tmp-mb-3 pl-1"><div class="Box__B2eZet"><h2 class="sr-only userSelectNone__I6NSfK 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 userSelectNone__I6NSfK prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading">History</h2><a data-component="LinkButton" href="/NVIDIA/cosmos-framework/commits/main/docs/posttrain/guides/sft.md" class="prc-Button-ButtonBase-9n-Xk d-none d-lg-flex linkButton__rBg5F1 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="/NVIDIA/cosmos-framework/commits/main/docs/posttrain/guides/sft.md" class="prc-Button-ButtonBase-9n-Xk linkButton__rBg5F1 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 blobContainer__ds2DJS"><div class="react-code-size-details-banner codeSizeDetails__TwyI5R"><div class="react-code-size-details-banner Box__wO1jqt"><div class="text-mono Box_1__NgV1zw"><div data-testid="blob-size" class="Truncate_1__fzkDk_ prc-Truncate-Truncate-2G1eo" data-inline="true" title="48.4 KB" style="--truncate-max-width:100%"><span>555 lines (524 loc) · 48.4 KB</span></div></div></div></div><div class="react-blob-view-header-sticky stickyHeader__iOrrW6" id="repos-sticky-header"><div class="Box__pIkMkv"><div class="react-blob-sticky-header"><div class="outerWrapper__jQuXcV outerWrapperHidden__yN223M"><div class="Box_1__Lq7d9C"><div class="Box_2__LXYgfX"><div class="Box_3__1P_GZT"><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 RefSelectorOverlayBtn__KrS-QJ" 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="RefSelectorOverlayContainer__do_QsK"><div style="max-width:125px" class="ref-selector-button-text-container RefSelectorBtnTextContainer__U9K7hH"><span class="RefSelectorText__DKi677">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="Box_4__gQ9URQ"><div class="container__3CaSnu md__EChwKv"><nav data-testid="breadcrumbs" aria-labelledby="sticky-breadcrumb-heading" id="sticky-breadcrumb" class="nav__om3y2l"><h2 class="sr-only userSelectNone__I6NSfK prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading" id="sticky-breadcrumb-heading">Breadcrumbs</h2><ol class="list__l5DBAB"><li class="listItem__z6CNRy"><a class="repoLink__Uax2bT prc-Link-Link-9ZwDx" data-component="Link" data-testid="breadcrumbs-repo-link" href="/NVIDIA/cosmos-framework/tree/main" data-discover="true">cosmos-framework</a></li><li class="listItem__z6CNRy"><span class="separator__FWRrWr md__EChwKv" aria-hidden="true">/</span><a class="directoryLink__pFe5bB prc-Link-Link-9ZwDx" data-component="Link" href="/NVIDIA/cosmos-framework/tree/main/docs" data-discover="true">docs</a></li><li class="listItem__z6CNRy"><span class="separator__FWRrWr md__EChwKv" aria-hidden="true">/</span><a class="directoryLink__pFe5bB prc-Link-Link-9ZwDx" data-component="Link" href="/NVIDIA/cosmos-framework/tree/main/docs/posttrain" data-discover="true">posttrain</a></li><li class="listItem__z6CNRy"><span class="separator__FWRrWr md__EChwKv" aria-hidden="true">/</span><a class="directoryLink__pFe5bB prc-Link-Link-9ZwDx" data-component="Link" href="/NVIDIA/cosmos-framework/tree/main/docs/posttrain/guides" data-discover="true">guides</a></li></ol></nav><div data-testid="breadcrumbs-filename" class="filename__e-5cWV"><span class="separator__FWRrWr md__EChwKv" aria-hidden="true">/</span><h1 class="filenameHeading__MTKryR md__EChwKv prc-Heading-Heading-MtWFE" data-component="Heading" tabindex="-1" id="sticky-file-name-id">sft.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="tooltip__XwO6MO 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 Button__x4ALLb GoToTopButton__NTXwOZ" 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="Box_1__1bJV7g"><h2 class="sr-only userSelectNone__I6NSfK prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading">File metadata and controls</h2><div class="Box_2__Is-e-Y"><ul aria-label="File view" class="prc-SegmentedControl-SegmentedControl-lqIXp SegmentedControl__GioqBZ" 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 Box__wO1jqt"><div class="text-mono Box_1__NgV1zw"><div data-testid="blob-size" class="Truncate_1__fzkDk_ prc-Truncate-Truncate-2G1eo" data-inline="true" title="48.4 KB" style="--truncate-max-width:100%"><span>555 lines (524 loc) · 48.4 KB</span></div></div></div></div><div class="Box_3__OE5Y7F"><div class="d-none"></div><div class="react-blob-header-edit-and-raw-actions Box_4__C-NqPq"><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/NVIDIA/cosmos-framework/raw/refs/heads/main/docs/posttrain/guides/sft.md" data-testid="raw-button" class="prc-Button-ButtonBase-9n-Xk linkButton__rBg5F1 LinkButton___5BTHO" 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 downloadButton__gSQP8w 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 IconButton__fFTwBu 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 IconButton__0qsoRg 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="blobContentWrapper__Nr-ksB"><section aria-labelledby="file-name-id-wide file-name-id-mobile" class="blobContentSection__g1-z7P blobContentSectionMarkdown__5cydiO" style="margin-top:46px"><div class="js-snippet-clipboard-copy-unpositioned markdownBlob__6s-Qd9" 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">SFT</h1><a id="user-content-sft" class="anchor" aria-label="Permalink: SFT" href="#sft"><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="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">1. When to choose it</h2><a id="user-content-1-when-to-choose-it" class="anchor" aria-label="Permalink: 1. When to choose it" href="#1-when-to-choose-it"><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">Full-parameter supervised fine-tuning of Qwen conversations through the existing <code>LLMTrainer</code>.
The <a href="/NVIDIA/cosmos-framework/blob/main/cosmos_framework/posttrain/configs/sft_qwen3p8_27b_multimodal.py">multimodal recipe</a> targets <code>Qwen/Qwen3.8-27B</code>
(the dense <code>qwen3_5</code> architecture), with text, images, videos and multiple assistant turns.
Local/torchrun FSDP is supported; Ray execution, LoRA, sequence packing and MTP training are not.
There is no rollout engine, reference model or reward function.</p>
<p dir="auto">SFT opts into Transformers 5.8.1; existing RL/GR00T defaults stay on 4.57.6. The SFT builder
supports Qwen text models, dense Qwen3.5/3.8 multimodal models and the Qwen3-VL / Qwen3-VL-MoE
families (all three ship <code>Qwen3VLProcessor</code>). A "seat" is the model construction path the SFT
objective sits on. Qwen3.5/3.8 sits on the HF backend (<code>model_backend='hf'</code>,
<code>model/hf.py::HFModel</code>). Qwen3-VL and Qwen3-VL-MoE sit on the i4-native policy builder
(<code>model_backend='i4'</code> with <code>config.model = NativePolicyBuildSpec(builder=model/qwen3_vl.py:: build_qwen3_vl_native_policy, ...)</code>, see <a href="/NVIDIA/cosmos-framework/blob/main/cosmos_framework/posttrain/configs/sft_qwen3_vl_moe_native.py">the native recipe</a>):
the HF backend refuses MoE VLMs because the general weight loader has no fused-expert handling and
Transformers 5 stores the MoE expert tensors transposed relative to a Transformers 4 checkpoint.
On the native seat the parameters are stored in bfloat16 (the MoE expert kernel requires it), so the
recipe uses <code>attn_impl='sdpa'</code> and <code>OptimizerConfig(name='fusedadam')</code> (apex fp32 master weights and
moments inside the optimizer); <code>validate_config</code> refuses <code>adamw</code> there because its bfloat16 moments
round most updates to zero. The seat's masking contract is pinned against the official Qwen3-VL
processor template in <code>tests/test_data_packer_sft.py</code> (the collated <code>attention_mask</code> is <code>torch.int64</code>
0/1, the contract <code>main</code> pins in <code>test_model_qwen3_vl.py</code>; the native eager mask casts it to bool); its
GPU training path reuses the online adapters.</p>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">2. Quick start</h2><a id="user-content-2-quick-start" class="anchor" aria-label="Permalink: 2. Quick start" href="#2-quick-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>
<p dir="auto">Start the container and install uv 0.11.29 as in
<a href="/NVIDIA/cosmos-framework/blob/main/docs/posttrain/howto/run-posttrain.md#1-start-the-container">sections 1 and 2 of the run guide</a>, then run
from the repository root. SFT uses its own venv with the <code>sft</code> group
(<a href="/NVIDIA/cosmos-framework/blob/main/docker/posttrain/environment/pyproject.toml">locked environment project</a>):</p>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="# `python3 -m uv` runs the pip-installed uv 0.11.29: a bare `uv` can resolve to an older release
# that ships with the container, which the environment project refuses.
# cu130-runtime matches the run guide's CUDA 13.0 image; use cu128-runtime on a CUDA 12.8 stack.
UV_PROJECT_ENVIRONMENT=&quot;$PWD/docker/posttrain/environment/.venv-sft&quot; \
  python3 -m uv sync --project docker/posttrain/environment --frozen \
  --no-group transformers4 --group sft --group cu130-runtime
export SFT_PYTHON=&quot;$PWD/docker/posttrain/environment/.venv-sft/bin/python&quot;
export PYTHONPATH=.

# The reviewed Qwen3.8-27B snapshot (about 56 GB).
uvx hf@latest download Qwen/Qwen3.8-27B \
  --revision 1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0 \
  --local-dir artifacts/models/Qwen3.8-27B
export SFT_MODEL_PATH=&quot;$PWD/artifacts/models/Qwen3.8-27B&quot;
export SFT_DATA_ROOT=&quot;$PWD/.ene/scratch/sft-example&quot;
&quot;$SFT_PYTHON&quot; -m cosmos_framework.posttrain.scripts.prepare_sft_example --output &quot;$SFT_DATA_ROOT&quot;
&quot;$SFT_PYTHON&quot; -m cosmos_framework.posttrain.entrypoints.sft --validate-manifest
&quot;$SFT_PYTHON&quot; -m cosmos_framework.posttrain.entrypoints.sft --validate-rows

# N is the allocated GPU count; this command does not allocate resources.
&quot;$SFT_PYTHON&quot; -m torch.distributed.run --standalone --nproc_per_node=&quot;$N&quot; \
  -m cosmos_framework.posttrain.entrypoints.sft"><pre><span class="pl-c"><span class="pl-c">#</span> `python3 -m uv` runs the pip-installed uv 0.11.29: a bare `uv` can resolve to an older release</span>
<span class="pl-c"><span class="pl-c">#</span> that ships with the container, which the environment project refuses.</span>
<span class="pl-c"><span class="pl-c">#</span> cu130-runtime matches the run guide's CUDA 13.0 image; use cu128-runtime on a CUDA 12.8 stack.</span>
UV_PROJECT_ENVIRONMENT=<span class="pl-s"><span class="pl-pds">"</span><span class="pl-smi">$PWD</span>/docker/posttrain/environment/.venv-sft<span class="pl-pds">"</span></span> \
  python3 -m uv sync --project docker/posttrain/environment --frozen \
  --no-group transformers4 --group sft --group cu130-runtime
<span class="pl-k">export</span> SFT_PYTHON=<span class="pl-s"><span class="pl-pds">"</span><span class="pl-smi">$PWD</span>/docker/posttrain/environment/.venv-sft/bin/python<span class="pl-pds">"</span></span>
<span class="pl-k">export</span> PYTHONPATH=.

<span class="pl-c"><span class="pl-c">#</span> The reviewed Qwen3.8-27B snapshot (about 56 GB).</span>
uvx hf@latest download Qwen/Qwen3.8-27B \
  --revision 1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0 \
  --local-dir artifacts/models/Qwen3.8-27B
<span class="pl-k">export</span> SFT_MODEL_PATH=<span class="pl-s"><span class="pl-pds">"</span><span class="pl-smi">$PWD</span>/artifacts/models/Qwen3.8-27B<span class="pl-pds">"</span></span>
<span class="pl-k">export</span> SFT_DATA_ROOT=<span class="pl-s"><span class="pl-pds">"</span><span class="pl-smi">$PWD</span>/.ene/scratch/sft-example<span class="pl-pds">"</span></span>
<span class="pl-s"><span class="pl-pds">"</span><span class="pl-smi">$SFT_PYTHON</span><span class="pl-pds">"</span></span> -m cosmos_framework.posttrain.scripts.prepare_sft_example --output <span class="pl-s"><span class="pl-pds">"</span><span class="pl-smi">$SFT_DATA_ROOT</span><span class="pl-pds">"</span></span>
<span class="pl-s"><span class="pl-pds">"</span><span class="pl-smi">$SFT_PYTHON</span><span class="pl-pds">"</span></span> -m cosmos_framework.posttrain.entrypoints.sft --validate-manifest
<span class="pl-s"><span class="pl-pds">"</span><span class="pl-smi">$SFT_PYTHON</span><span class="pl-pds">"</span></span> -m cosmos_framework.posttrain.entrypoints.sft --validate-rows

<span class="pl-c"><span class="pl-c">#</span> N is the allocated GPU count; this command does not allocate resources.</span>
<span class="pl-s"><span class="pl-pds">"</span><span class="pl-smi">$SFT_PYTHON</span><span class="pl-pds">"</span></span> -m torch.distributed.run --standalone --nproc_per_node=<span class="pl-s"><span class="pl-pds">"</span><span class="pl-smi">$N</span><span class="pl-pds">"</span></span> \
  -m cosmos_framework.posttrain.entrypoints.sft</pre></div>
<p dir="auto">The generator creates 32 training and 8 validation conversations with local PNG/MP4 media;
it refuses to overwrite a nonempty directory. Video decoding requires TorchCodec 0.11.0
and compatible FFmpeg shared libraries. This is a functional example, not a quality benchmark.
Preflight checks configuration, local file availability and role wiring, not GPU memory or
remote access. <code>--validate-rows</code> then runs every row through the real packer on CPU and refuses
over-long rows, masks that disagree with the assistant turns, and mislabelled tool turns before any
trainer is built (<a href="/NVIDIA/cosmos-framework/blob/main/cosmos_framework/posttrain/scripts/README.md#pre-launch-sft-row-validator">scripts/README.md</a>). Use torchrun even for one GPU; 27B FP32 training does not fit a single ordinary GPU.</p>
<p dir="auto">Use a complete immutable snapshot, not a mutable Hub branch or metadata-only test fixture.
The reviewed Qwen3.8 revision is <code>1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0</code>; its config selects
<code>Qwen3_5ForConditionalGeneration</code> and its processor is <code>Qwen3VLProcessor</code>. Preserve the
processor/tokenizer/template sidecars. The loader requires every dense model parameter and
ignores extra <code>mtp.*</code> weights; SFT does not train MTP.</p>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">3. Data contract</h2><a id="user-content-3-data-contract" class="anchor" aria-label="Permalink: 3. Data contract" href="#3-data-contract"><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 complete conversation per JSONL record:</p>
<div class="highlight highlight-source-json notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="{&quot;messages&quot;:[{&quot;role&quot;:&quot;user&quot;,&quot;content&quot;:[{&quot;type&quot;:&quot;image&quot;,&quot;image&quot;:&quot;media/frame.png&quot;},{&quot;type&quot;:&quot;text&quot;,&quot;text&quot;:&quot;What color is the object?&quot;}]},{&quot;role&quot;:&quot;assistant&quot;,&quot;content&quot;:&quot;Red.&quot;},{&quot;role&quot;:&quot;user&quot;,&quot;content&quot;:&quot;Repeat in uppercase.&quot;},{&quot;role&quot;:&quot;assistant&quot;,&quot;content&quot;:&quot;RED.&quot;}]}"><pre>{<span class="pl-ent">"messages"</span>:[{<span class="pl-ent">"role"</span>:<span class="pl-s"><span class="pl-pds">"</span>user<span class="pl-pds">"</span></span>,<span class="pl-ent">"content"</span>:[{<span class="pl-ent">"type"</span>:<span class="pl-s"><span class="pl-pds">"</span>image<span class="pl-pds">"</span></span>,<span class="pl-ent">"image"</span>:<span class="pl-s"><span class="pl-pds">"</span>media/frame.png<span class="pl-pds">"</span></span>},{<span class="pl-ent">"type"</span>:<span class="pl-s"><span class="pl-pds">"</span>text<span class="pl-pds">"</span></span>,<span class="pl-ent">"text"</span>:<span class="pl-s"><span class="pl-pds">"</span>What color is the object?<span class="pl-pds">"</span></span>}]},{<span class="pl-ent">"role"</span>:<span class="pl-s"><span class="pl-pds">"</span>assistant<span class="pl-pds">"</span></span>,<span class="pl-ent">"content"</span>:<span class="pl-s"><span class="pl-pds">"</span>Red.<span class="pl-pds">"</span></span>},{<span class="pl-ent">"role"</span>:<span class="pl-s"><span class="pl-pds">"</span>user<span class="pl-pds">"</span></span>,<span class="pl-ent">"content"</span>:<span class="pl-s"><span class="pl-pds">"</span>Repeat in uppercase.<span class="pl-pds">"</span></span>},{<span class="pl-ent">"role"</span>:<span class="pl-s"><span class="pl-pds">"</span>assistant<span class="pl-pds">"</span></span>,<span class="pl-ent">"content"</span>:<span class="pl-s"><span class="pl-pds">"</span>RED.<span class="pl-pds">"</span></span>}]}</pre></div>
<ul dir="auto">
<li>Roles: <code>system</code> (first only), <code>user</code>, <code>assistant</code>, and <code>tool</code>. Text is a string or a
<code>{"type":"text","text":"..."}</code> part. Videos use <code>{"type":"video","video":"..."}</code>.</li>
<li>Optional <code>tools</code>, assistant <code>tool_calls</code>, and <code>reasoning_content</code> are retained. Tool-only
assistant content may be absent/null; it normalizes to empty text.</li>
<li>Optional <code>supervise</code>, a string: <code>all_assistant</code> (the rule when the key is absent) or <code>last_assistant</code>
(section 4). Any other value, <code>null</code> included, is refused at load with the row's label. The key is
never added to a row that lacks it, so the fingerprint of an existing file does not change.</li>
<li>Optional <code>opener</code>, a string: <code>self</code> (the rule when the key is absent) or <code>prefilled</code> (section 4);
validated and never added the same way. A <code>meta.opener</code> (the exporter's record of its prefilled slice)
must agree with the <code>opener</code> field, which is what the packer reads.</li>
<li><code>rl.data.path</code> and <code>rl.validation.data.path</code> accept local JSONL or <code>s3://bucket/key.jsonl</code>.
Remote reads use each source's <code>credentials</code> path and the existing S3/GCS client.</li>
<li>JSONL is read once per rank into memory. Fingerprints cover normalized content and local
media bytes. Text-only identity excludes URI/credentials and survives cross-cluster moves.</li>
<li>Local media resolves relative to the JSONL file unless <code>media_root</code> is set. S3 JSONL with
media requires an explicit local <code>media_root</code>; automatic remote media fetching is not supported.</li>
<li>Alternatively, <code>rl.data.factory</code> plus <code>factory_kwargs</code> selects a map-style source returning
this schema with an immutable <code>cursor_fingerprint()</code> covering rows and media. Additional
dataset cursor hooks must be supplied as a save/load pair.</li>
<li>Training row count must divide DP world size. Rows shuffle and repeat by epoch; no training
records are silently dropped or padded. Validation requires a separate source.</li>
</ul>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">4. Objective and masking</h2><a id="user-content-4-objective-and-masking" class="anchor" aria-label="Permalink: 4. Objective and masking" href="#4-objective-and-masking"><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 packer renders with the checkpoint's own chat template and passes <code>preserve_thinking=True</code>
only to a template that declares that variable (the toy test template does). The official
Qwen3-VL template has no such variable: it renders <code>reasoning_content</code> for every assistant turn
and passes inline <code>&lt;think&gt;</code> text through as content, so nothing is passed to it; a kwarg the
template does not declare is one Transformers 5 reclassifies as a processor kwarg and warns about
on every render. Every assistant body and turn-ending token is supervised; headers,
user/system/tool content, media tokens, generated video timestamps and padding are ignored.</p>
<p dir="auto"><strong>Row-level supervision (<code>supervise</code>).</strong> A row's <code>supervise</code> field selects the assistant
turns that carry loss: <code>all_assistant</code> (the default and the behaviour before the field existed: every
assistant body and its <code>&lt;|im_end|&gt;</code>) or <code>last_assistant</code> (the LAST assistant turn's body through its
<code>&lt;|im_end|&gt;</code> only; every earlier assistant turn stays in the sequence as context at -100, like the tool
results and user turns around it). The packer records the row's contract string on
<code>SFTPolicyInput.masking</code> (<code>qwen_chatml_all_assistant_bodies_and_end_v2</code> or
<code>qwen_chatml_last_assistant_body_and_end_v1</code>); the packer-level resume identity keeps the all-assistant
string because the field is part of the row and therefore of the source fingerprint.
<code>rl.mask_think_opener</code> applies to the supervised turn only (the per-row <code>opener</code> field below applies the
same rule to one row). The rule exists for <strong>prefix rows</strong> (a term
defined here): one row per model call of an agent-harness episode, whose prompt is the served prefix of
that call -- the tokenizer template's rendering of the history, every earlier assistant turn
reasoning-free, exactly what the default serve renders when the request carries a tools array (measured
equal to the serving deployment's tokenize endpoint on 146 of 146 calls of one agent-harness episode) --
and whose completion is the student's own turn at that call, reasoning included.
A prefix row therefore matches the <strong>default serve</strong> of a default export token for token; a
whole-episode row with reasoning in every assistant turn does not (it is exact only under a serve that
renders the processor template with tools: a <strong>unified export</strong>, defined in section 7 as an export built
with the materializer's <code>--unified-chat-template</code>, whose two template files carry the canonical processor
template). Fixtures:
<code>tests/test_data_packer_sft.py::test_supervise_last_assistant_three_turn_row_exact_loss_counts</code>
(a three-turn row through the toy tokenizer: 96 = [91, 5] loss tokens under the default, 5 = [5] under
<code>last_assistant</code>, the ids identical) and
<code>test_supervise_last_assistant_official_template_keeps_history_at_minus_100</code> (the official template
with an image and a tool call; the opener mask then touches the last turn's opener only). Under
<code>last_assistant</code> the history turns must carry no reasoning: the packer refuses a history assistant turn
with a non-empty <code>reasoning_content</code> or a content opening with <code>&lt;think&gt;</code> (the processor template renders
a history <code>reasoning_content</code> as a think block, 250 vs 236 ids on one probe, while the default serve's
prefix has none, and it strips an exact <code>&lt;think&gt;&lt;/think&gt;</code> content prefix the tokenizer template keeps).
Fixture:
<code>test_last_assistant_row_prefix_is_the_served_prefix_under_both_templates_and_history_reasoning_is_refused</code>
(the base's two templates as repo fixtures: the row's text and ids begin with the tokenizer template's
served prefix, the two templates agree byte for byte when no turn carries reasoning, a history
<code>reasoning_content</code> or <code>&lt;think&gt;&lt;/think&gt;</code> prefix diverges inside the history and is refused, an
<code>all_assistant</code> row with the same history still packs).</p>
<p dir="auto"><strong>Row-level opener (<code>opener</code>).</strong> A row's <code>opener</code> field says whose token the
<code>&lt;think&gt;</code> opener of a supervised assistant turn is: <code>self</code> (the default and the behaviour before the
field: the opener is the student's first supervised token, as the agent harness's serve prefills nothing)
or <code>prefilled</code> (the serve prefills the opener token itself, <code>&lt;|im_start|&gt;assistant\n&lt;think&gt;</code>, id 151667, no
newline after it, as a thinking-on client without tools does: the packer masks the first <code>&lt;think&gt;</code> token
of every supervised assistant block of that row, exactly the rule the run-level <code>rl.mask_think_opener=True</code>
applies to every row, and the supervised target begins with the newline that opens the reasoning text;
under <code>last_assistant</code> that is the last block only). One rule: a row with <code>opener: prefilled</code> in a run
with <code>mask_think_opener=True</code> is masked once, the count unchanged. Why per row: the exporter writes the
prefilled slice (20 percent of the supervised reasoning turns, a fixed seed) into the same row files
as the self rows, so the mask must be the row's, not the run's; the exporter records its choice as
<code>meta.opener</code> and must write the same value in the row's <code>opener</code> field, which is what the packer reads
(the loader refuses a <code>meta.opener</code> that disagrees with the field, a <code>prefilled</code> in <code>meta</code> without the
field included). The per-row contract string gains <code>_opener_prefilled_v1</code>
(<code>qwen_chatml_all_assistant_bodies_and_end_v2_opener_prefilled_v1</code>,
<code>qwen_chatml_last_assistant_body_and_end_v1_opener_prefilled_v1</code>); the packer-level identity keeps
recording the run-level knob. A <code>prefilled</code> row on a tokenizer without <code>&lt;think&gt;</code> is refused. A <code>prefilled</code>
row needs a reasoning block in every supervised assistant turn: the packer
refuses the row unless its mask removed exactly one <code>&lt;think&gt;</code> id in every supervised block (the refusal
names the bare blocks and the per-block counts), and the loader refuses a <code>prefilled</code> row whose supervised
turns (all of them under <code>all_assistant</code>, the last under <code>last_assistant</code>) lack a non-empty
<code>reasoning_content.strip()</code>, so the string <code>_opener_prefilled_v1</code> is only ever recorded when the masking
happened; the run-level knob on a bare turn masks nothing and refuses nothing (it is the run's variant,
recorded in the packer identity, not the row's contract). The loader also refuses a <code>meta.supervise</code> that
disagrees with the row's <code>supervise</code> field, as it does for <code>meta.opener</code>. Fixtures:
<code>tests/test_data_packer_sft.py::test_opener_prefilled_three_turn_row_exact_loss_counts_under_the_four_combinations</code>
(a three-turn row through the toy tokenizer: with reasoning in both assistant turns under <code>all_assistant</code>,
<code>self</code> 118 = [102, 16] and <code>prefilled</code> 116 = [101, 15]; under <code>last_assistant</code>, with the history turn
reasoning-free as that mode requires, 16 and 15; the difference exactly the opener token of each
supervised block), <code>test_opener_prefilled_and_the_global_mask_are_one_rule</code>,
<code>test_opener_refuses_unknown_values_and_a_tokenizer_without_think</code>,
<code>test_opener_prefilled_refuses_a_supervised_block_without_an_opener</code> (B1 / B2 / B3 refused, self rows and the
run-level knob unchanged),
<code>tests/test_roles_env_sft.py::test_opener_field_is_validated_by_the_loader_and_reaches_the_target</code> and
<code>::test_opener_prefilled_rows_require_reasoning_on_every_supervised_turn_and_meta_supervise_must_agree</code>. A row
validator that counts assistant tokens independently of the labels must count over
<code>data/packer/sft.py::supervised_assistant_blocks(n_assistant_blocks, supervise)</code>, the indices the packer
paints, or it reports every <code>last_assistant</code> row as a mask mismatch.
<code>rl.mask_think_opener=True</code> additionally unsupervises the <code>&lt;think&gt;</code> token that opens an assistant
body, and only that token. Keep the default <code>False</code>: on the serving path of record (Codex
<code>--thinking high</code> sends <code>reasoning.effort</code> and the harness's tools array on every call) vLLM 0.24
prefills no opener -- with tools present the served prefix is <code>&lt;|im_start|&gt;assistant\n</code> and nothing
more (the effort field adds 0 input tokens; <code>/tokenize</code> with tools and <code>enable_thinking</code> ends in
<code>assistant\n</code>; measured live; the ids are the fixture
<code>tests/fixtures/served_prefix_with_tools.json</code>), so the student must emit <code>&lt;think&gt;</code> itself as the
first token of every turn and then the reasoning, or the closer <code>\n\n&lt;/think&gt;\n\n</code> of the empty
block a turn without reasoning (a no-think turn) is rendered with; all of it is the student's and
the opener's loss is the only training signal for that token. <code>True</code> would leave it unsupervised;
what a <code>True</code>-trained student would emit there is UNMEASURED with tools present (no such student
exists, and the first token after <code>assistant\n</code> with tools present was never sampled), so the
consequence is a RISK, not a measurement. The failure it could reopen has a measured trigger: the
qwen3 parser treats an output that carries no <code>&lt;/think&gt;</code> as reasoning in full, so a no-think TEXT
turn of the student never reaches Codex as an agent message, while a no-think TOOL-CALL turn is
unaffected (vLLM 0.24 <code>reasoning/basic_parsers.py</code> 173-181: without <code>&lt;/think&gt;</code> the whole output is
reasoning; with <code>&lt;/think&gt;</code> it is split even without <code>&lt;think&gt;</code>); under the exporter's rendering the
closer stays supervised under <code>True</code>, so a turn that dropped only the opener would still carry
<code>&lt;/think&gt;</code>. The decision does not rest on the risk: <code>False</code> stays the default because the opener's
loss is the only training signal for a token the student must emit on the path of record. Selecting
the <code>prefilled_opener</code> variant sets the typed field <code>rl.serve_contract=prefills_opener</code> beside the
mask: the declaration that the student will be served by a path that prefills <code>&lt;think&gt;</code> for it,
recorded in the resolved config and, being non-default, in the objective identity. <code>SFTConfig</code>
refuses the VALUE <code>rl.mask_think_opener=True</code> under the default contract <code>tools_no_prefill</code> from any
source, a <code>--</code> override on the <code>default</code> variant included, and the resolved variant name is stamped
into the attempt's provenance as <code>recipe_variant</code>. The prefill exists only for requests without
tools: there a present effort sets <code>enable_thinking</code> and the template appends <code>&lt;think&gt;</code> (10 input
tokens instead of 9) -- not a path of record; under such a serve the supervised opener costs one
deterministic token per turn and the student continues after it, so <code>False</code> is right under both
conditions. (The Nemo-Chat processor rule also unsupervises an empty block, because its serve
supplies the whole block; that rule, applied here, would remove the closer's loss under a single-newline
rendering.) The native recipe's table (its <code>&lt;think&gt;</code> opener row) records the decision with its
measurements. Templates that drop supplied reasoning or reorder messages are rejected, as are
reserved chat/media delimiters in source text.</p>
<p dir="auto">Masks use the <strong>final processor-expanded token stream</strong>, requiring an exact tokenizer round
trip; no prefix-length approximation or pre-expansion assistant mask is used. Labels are
unshifted at collation; the objective shifts exactly once. With <code>rl.ce_exponent=0</code> (the framework
default) the loss is the global supervised-token mean across ranks and accumulation; with
<code>ce_exponent=e</code> every row contributes its token sum divided by <code>n^e</code> over the DP-mean of
<code>sum_rows n^(1-e)</code> (<code>0.5</code> = the Cosmos post-training recipe's square-root weighting, <code>1</code> = every row
weighs the same). <code>rl.moe_lbl_coeff&gt;0</code> adds the MoE load-balancing term
<code>coeff * E * mean_layers(sum_e f_e * P_e)</code> from the sparse blocks' routing statistics of the same
forward (<code>f_e</code> the share of routed tokens, summed over the DP ranks under <code>moe_lbl_method='global'</code>;
<code>P_e</code> the mean router probability); <code>train/lbl_loss</code>, <code>train/moe_load_max_rel</code> (the largest
expert's share relative to uniform, 1.0 = balanced) and <code>train/objective</code> (the value descended)
then appear beside <code>train/loss_avg</code>, which stays the plain token-mean CE. Overlength conversations
fail rather than truncating targets.</p>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">5. Main knobs</h2><a id="user-content-5-main-knobs" class="anchor" aria-label="Permalink: 5. Main knobs" href="#5-main-knobs"><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">Global conversations/update are <code>rl.micro_batch_size × rl.grad_accum × DP world size</code>.
<code>rl.max_steps</code> counts optimizer updates; <code>rl.max_length</code> limits the full expanded sequence.
<code>rl.optimizer.*</code> controls the optimizer, clipping and warmup (<code>warmup_steps</code> must be <code>&gt;= 0</code>);
<code>rl.lr_schedule.kind</code> selects what follows the warmup: <code>constant</code> (the pre-existing path) or
<code>cosine</code> (the Cosmos post-training recipe's <code>LambdaWarmUpCosineScheduler</code>: lr × <code>f_start</code> at the
first update, linear to lr at <code>warmup_steps</code>, cosine down to lr × <code>f_min</code> at <code>cycle_steps</code> or
<code>max_steps</code>). <code>rl.optimizer.lr_multipliers</code> scales the learning rate of the parameters whose name
contains a key (<code>{"model.visual": 0.1}</code> = the vision tower at a tenth). Precision differs by seat.
The dense HF recipe keeps FP32 parameters and optimizer state (<code>master_dtype='float32'</code>) under BF16
autocast. The native Qwen3-VL-MoE recipe stores the parameters in bfloat16
(<code>master_dtype='bfloat16'</code>, <code>param_dtype='bfloat16'</code>); its fp32 master weights and fp32 moments
live inside the apex fused Adam (<code>OptimizerConfig(name='fusedadam')</code>), which refreshes the bf16
parameters from the master on every step, and the saved artifact is that bf16 copy, never the
master: an update below half a bf16 ulp of a weight is carried in the master during the run and
reaches neither the artifact nor the training forward, which reads the same bf16 copy. Known limit,
measured over 1,401 training steps at lr 1e-5: <code>model.language_model.norm.weight</code>
(median |w| 3.08, bf16 ulp 0.0156 &gt; 1,401 × 1e-5 = 0.014) changed in 0 of 2,048 elements while
<code>layers.0.input_layernorm.weight</code> (median 0.0036) changed in 1,985 of 2,048; 36 of the 882 tensors
(34 vision norms, <code>layers.47.input_layernorm.weight</code>, the final norm) were bitwise the base's, i.e.
those 36 norm scales did not train. Trade-off: the served model is bf16 either way, and storing the
1-D parameters (the 426 norm scales and biases, a few MB in fp32) in fp32 would un-freeze them at
negligible memory cost, the export rounding each once (at most half an ulp lost). The materializer
records per export how many tensors equal the base (<code>tensors_equal_to_base</code> in <code>.materialized</code>).
<code>tests/test_config_sft.py::test_bf16_storage_freezes_large_scales_below_half_an_ulp</code> is a pin of the
mechanism on a tiny fixture (it records pure bf16 arithmetic, which the framework does not change), as
is <code>test_deterministic_knob_reaches_setup</code> (pre-existing setup behaviour); neither tests a change to
the framework. Both recipes use activation checkpointing and SDPA. Weight decay is decoupled;
<code>decay_groups=''</code> builds one parameter group (every trainable parameter decays, norms, biases,
embeddings and routers included -- the Cosmos post-training recipe's own grouping:
<code>cosmos3/utils/optimizer.py::_build_params_with_metadata</code> decays all 882 tensors of the backbone),
<code>decay_groups='hf'</code> reproduces the Transformers Trainer's [decay, no-decay] split (LayerNorm modules,
biases and <code>*norm*</code> names undecayed; the embedding, the head and the router gates decay), and
<code>decay_groups='qwen_moe'</code> (the native recipe) leaves every 1-D parameter (norm scales, biases) AND
the token embedding, the output head and the MoE router gates undecayed -- the seat's own choice,
whose protection and cost the recipe's table states in its weight-decay row. The native recipe's
docstring carries the per-knob decision table (Cosmos post-training recipe vs the A1 arms vs its
defaults).</p>
<p dir="auto"><code>rl.processor_kwargs</code> accepts HF <code>images_kwargs</code> and <code>videos_kwargs</code>. Pixel budgets use
<code>size.shortest_edge</code>/<code>longest_edge</code> (pixel area), not legacy <code>min_pixels</code>/<code>max_pixels</code>.
The example samples 8 video frames with <code>fps=None</code>; do not also request FPS-based sampling.
The processor's media tensors and <code>mm_token_type_ids</code> reach the model unchanged. The Qwen3.5
forward adapter orders image/video vision calls and backward graphs on every rank, including
dummy work for absent modalities; dummy grids never enter token positions or M-RoPE.</p>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">6. Metrics and validation</h2><a id="user-content-6-metrics-and-validation" class="anchor" aria-label="Permalink: 6. Metrics and validation" href="#6-metrics-and-validation"><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>train/loss_avg</code> and <code>val/loss_avg</code> are token-weighted means; valid token/sequence counts
are sums. Every committed frame is written to <code>&lt;run dir&gt;/metrics.jsonl</code> (one JSON line per step:
<code>train/grad_norm</code> = the pre-clip global norm, <code>train/learning_rate</code>, <code>train/valid_token_count</code>,
<code>timer/e2e_step_s</code>, <code>train/grad_clip_coef</code> = the factor <code>clip_grad_norm_</code> applied,
<code>min(1, grad_clip_norm / (norm + 1e-6))</code>, and <code>train/grad_clipped</code> = 1.0 exactly when that factor is
below 1 (one rule; both recorded by <code>LLMTrainer</code> from the norm it clipped),
<code>train/grad_clip_fraction</code> = the share of the run's updates clipped so far (the loop's running count),
plus the validation keys of that step) and the console line carries the headline subset. The file
holds one row per step across relaunches: an attempt that resumes at step <code>s</code> keeps the rows with
<code>step &lt;= s</code> and drops the later ones, which it re-emits (a crash past the last save leaves committed
rows the resumed attempt recomputes), and the clip counters continue from the kept rows, so the
fraction is the run's, not the attempt's; a fresh attempt starts the file empty. Held-out validation
uses finite batches with zero-weight tail padding and restores module modes, source cursor and RNGs.
Final validation is mandatory when enabled. The validation source must be held out row by row: setup
refuses it when any validation row has the content hash (messages + tools, media by file bytes so a
copy of the training media under another root is the same row) of a training row or the item id
(<code>meta.item</code>) of one, and when validation rows carry no item id while the training rows do (a row
without an item has only its content hash as identity, which one changed character defeats); a
whole-source fingerprint check is not enough, since it passes a strict subset of the training file.</p>
<p dir="auto">On the native Qwen3-VL-MoE seat, <code>train/grad_norm</code> varies from run to run because routing in the bf16
MoE forward is not deterministic. Read it as a per-run diagnostic, not as a quantity to compare
between two runs.</p>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">7. Checkpoints, resume and export</h2><a id="user-content-7-checkpoints-resume-and-export" class="anchor" aria-label="Permalink: 7. Checkpoints, resume and export" href="#7-checkpoints-resume-and-export"><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 generic example saves DCP every 10 updates and at its final step. Obj1k instead selects
consolidated <code>model.pt</code> for HF export. <code>rl.resume=auto</code> resumes the latest checkpoint for the
same job identity; an explicit iteration directory also works. Exact resume binds every rank's
data cursor, tokenizer/processor/masking semantics, precision and batching. Preemption saves
only at complete optimizer boundaries.</p>
<p dir="auto">For storage and retention see <a href="/NVIDIA/cosmos-framework/blob/main/docs/posttrain/reference/checkpoint.md">checkpointing</a>. The
<a href="/NVIDIA/cosmos-framework/blob/main/docs/posttrain/howto/checkpoint-artifacts.md#materialize-an-opd-teacher">HF materializer</a> consumes consolidated
<code>model.pt</code>, not DCP; it preserves tokenizer/processor sidecars, writes the base's <code>config.json</code> into the
export (the transformers-written one is kept unpublished as <code>config.json.trainer.bak</code>, the export's own file
before the base overlay), and verifies every tensor of <code>model.pt</code> bitwise against the shards before it
returns, keeping a sha256 per tensor and the list of tensors bitwise equal to the base in <code>.materialized</code>. A
<code>processor_config.json</code> in the export is the base's own file or none (the reference base carries none);
<code>conversion.hf.service_processor_config</code> composes one from the base's sidecars but has no production caller,
and the file served beside one deployed export (placed by hand) differs from it in the image processor class
and 17 explicit defaults, so connecting the helper is a separate change: a contract bump, <code>verify_sidecars</code>
accepting the composed file and a re-anchored serve. Select <code>rl.checkpoint_format=consolidated</code> if export is
required and budget rank-0 host memory. <code>rl.export_*</code> is not wired and is rejected.</p>
<p dir="auto"><strong>Unified chat template (<code>--unified-chat-template</code>).</strong> The base ships two chat templates: <code>chat_template.json</code>
(the <strong>processor template</strong>, 5,614 chars, text sha256 <code>97de86bf6ddb765a...</code>) and <code>tokenizer_config.json</code>'s
<code>chat_template</code> (the <strong>tokenizer template</strong>, 5,292 chars, <code>3636d0f0bd6bef02...</code>). They differ in what they
render for an assistant turn in the HISTORY: the processor template renders <code>reasoning_content</code>
(<code>&lt;think&gt;...&lt;/think&gt;</code>) in every assistant turn, the tokenizer template renders none. vLLM 0.24 renders a
request that carries a tools array with the tokenizer template (measured: a captured agent-harness request,
req_012, tokenizes to 8,946 ids on the default serve and to 8,969 with the processor template forced, the 23
extra ids an earlier turn's think block; the first differing id sits at position 7,247, <code>&lt;think&gt;</code> vs
<code>&lt;tool_call&gt;</code>). The materializer option writes BOTH template files of the export, <code>tokenizer_config.json</code>'s
<code>chat_template</code> and <code>chat_template.json</code>'s <code>chat_template</code>, as the processor template in its CANONICAL form,
every other key of each file unchanged (every other line byte-equal when the base's file is a plain
<code>json.dumps</code> rendering, which both of the reference base's are). The <strong>canonical form</strong>
(<code>template_mode: processor-canonical</code>) is the processor template with ONE change in its reasoning branch,
<code>'&lt;think&gt;\n' ~ (message.reasoning_content | trim) ~ '\n&lt;/think&gt;\n'</code> instead of the untrimmed rendering: a
replayed reasoning string that arrives with a newline at both ends (the agent harness's form) then renders the
canonical block <code>&lt;think&gt;\n&lt;text&gt;\n&lt;/think&gt;\n</code>, the student's own emission form, instead of the padded
<code>&lt;think&gt;\n\n&lt;text&gt;\n\n&lt;/think&gt;\n</code> (<code>conversion.hf.canonicalize_processor_template</code>; a base whose processor
template lacks the exact line is refused). The marker records the processor template's sha, the shipped sha of
each file (<code>shipped</code>) and the one-hunk diff under <code>chat_template</code> (<code>template_mode</code>, <code>files</code>, <code>canonical_diff</code>;
also <code>options.unified_chat_template</code> and <code>sidecars.chat_template</code>), makes the option part of the output's
identity (a request without it on such an output is refused until <code>--force</code>, and the reverse) and verifies
both files by rule instead of byte identity (<code>verify_sidecars</code>: each file's mapping equals the base's on every
key but <code>chat_template</code>, whose value is the canonical text; <code>verify_with_torch</code>: the loaded tokenizer's and
the loaded processor's templates are that text). Default off: the default export stays byte-identical to the
base's sidecars. The rows for this template write <code>reasoning_content</code> as the model's TRIMMED reasoning text
(the <code>str.strip()</code> of the model's reasoning bytes; the packer renders the base's own processor template, which
yields the same canonical block for a stripped string, so training bytes are canonical with or without the
option), and no-reasoning turns stay BARE, no think block (matching the student's measured emission and the
serve's history form). Serving condition: <strong>unified rows</strong> (a term defined here: whole-episode rows in which
every assistant turn is supervised and the history turns carry their reasoning, the row shape of a unified
export's training set) are exact under ANY serve of a unified export and without a serve-side template flag:
both template files of a unified export carry the canonical text, so a request with or without tools renders
the same reasoning form (a tokenizer-only loader reads <code>tokenizer_config.json</code>, a processor loader reads
<code>chat_template.json</code>). Two row conditions carry this claim, both measured on the captured request req_012: (a)
tool-call <code>arguments</code> travel in the row as the PARSED OBJECT, which the template renders through <code>tojson</code>
(<code>{"query": "value"}</code>, with <code>": "</code> and <code>", "</code>), exactly as the serve re-serialises the parsed arguments; a row
that keeps the model's compact JSON string (<code>{"query":"value"}</code>) renders it verbatim and differs from the
served prefix at the first argument (3 of 3 argument strings of req_012 differ from their re-serialised form);
the packer also accepts <code>arguments</code> as a string and renders it verbatim, and such a string matches only when
it equals <code>json.dumps(obj, ensure_ascii=False)</code> of its parsed object (the <code>tojson</code> form the serve emits): the
model's compact string and <code>json.dumps(obj)</code> with the default <code>ensure_ascii=True</code> (non-ASCII escaped as
<code>\uXXXX</code>) both differ; (b) <code>reasoning_content</code> is the <code>str.strip()</code> of the model's reasoning bytes (Jinja's
<code>trim</code>), not the text with one newline removed at each end: a trailing space or a second newline survives the
latter and breaks the match. Pins: the string-vs-object and whitespace cases of
<code>tests/test_data_packer_sft.py::test_processor_canonical_template_trims_the_replayed_reasoning_where_the_verbatim_template_pads_it</code>
(the <code>ensure_ascii=True</code> case included). Supported-base contract under the option: a base ships its templates
in the two JSON files, <code>chat_template.json</code> and <code>tokenizer_config.json</code>'s <code>chat_template</code>, as the evidenced
Cosmos base does, and carries NO template sidecar a loader prefers over them; the materializer's preflight
enforces it. The materializer's preflight is the torch-free set of checks in
<code>checkpoint/tools/materialize_hf.py</code> that read the base alone before anything is removed or written (not the
trainer's preflight of section 2, which checks the training configuration). Read on transformers 4.57.6 and
5.8.1, the two pinned versions, those are <code>chat_template.jinja</code> (the tokenizer loader takes it over
<code>tokenizer_config.json</code>'s key; the processor loader reads it only when <code>chat_template.json</code> is absent), the
<code>additional_chat_templates/</code> directory (named templates the tokenizer loader prefers over the key; beside
<code>chat_template.json</code> the processor loader refuses the combination; the directory is refused whatever it holds,
empty or with nested directories only included, by the one helper the materializer's preflight and
<code>verify_sidecars</code> share: both loaders discover named templates with <code>glob("*.jinja")</code> and ignore an empty
directory, and the rule still refuses it, fail closed) and a <code>chat_template</code> key in <code>processor_config.json</code>
(the processor loader prefers it on 5.8.1). With such a sidecar the export would ship both canonical JSON
files while <code>AutoTokenizer</code> renders the sidecar, so the materializer REFUSES the base in unified mode before
anything is published, with or without <code>--no-verify</code>, naming the file. That refusal is part of the
materializer's preflight, which runs before any destructive step: under <code>--force</code> the existing output is
removed, <code>&lt;out&gt;.tmp</code> created and the overlay run only after it has passed, so a refused request leaves the
existing output byte-identical. The same preflight also parses every JSON sidecar of the base
(<code>tokenizer_config.json</code> and <code>chat_template.json</code> as objects; the overlay and the template record read them
after the overlay), refuses in the default path an <code>additional_chat_templates/</code> whose entries are not all
regular files (the default path copies the directory verbatim and its verifier refuses a sub-directory), and
turns an unreadable base into a named refusal instead of a traceback (fixtures
<code>tests/test_checkpoint_materialize_hf.py::test_force_rebuild_keeps_the_existing_output_when_a_base_json_sidecar_does_not_parse</code>,
<code>::test_default_preflight_refuses_a_named_template_directory_with_entries_that_are_not_regular_files</code> and
<code>::test_preflight_refuses_an_unreadable_base_with_a_named_reason_instead_of_a_traceback</code>). The same preflight
also runs on every base shard the index lists the safetensors header check the output gets
(<code>conversion.hf.shard_status</code>: present, readable, header parsed, size = 8 + header + data, header keys = the
tensors the index maps to it), because the overlay's <code>from_pretrained</code> opens every shard in the staged build
and a shard truncated by one byte, with a garbage header or unreadable would otherwise pass (the identity
records sizes only); requires every JSON sidecar of the base to be a JSON object and <code>chat_template.json</code>,
when present, to carry a non-empty <code>chat_template</code> string (the loaders index these after the overlay: a <code>[]</code>
sidecar fails <code>AutoProcessor</code> / <code>GenerationConfig</code> and a <code>{}</code> template file is the processor loader's
KeyError, read on the container's transformers 5.13.0); validates the index's <code>weight_map</code> (a non-empty object
of tensor name -&gt; shard name, so no index shape escapes as AttributeError / TypeError); and raises every
refusal in the one message family
<code>REFUSED before anything is published: &lt;what was found; what the staged build would have done with it&gt;</code>
(fixtures
<code>::test_preflight_refuses_a_base_shard_the_safetensors_header_check_rejects_before_anything_is_removed</code>,
<code>::test_preflight_refuses_a_json_sidecar_the_loaders_reject_although_it_parses</code>,
<code>::test_preflight_refuses_an_index_whose_weight_map_is_not_tensor_to_shard_names_without_a_traceback</code> and
<code>::test_every_preflight_refusal_is_in_the_one_message_family_and_names_what_it_found</code>). ONE JSON decoder
serves the whole preflight and the materializer's own readers (<code>conversion.hf.decode_json_bytes</code>: strict UTF-8
text, what <code>model_identity</code>, <code>_read_json_file</code> and transformers' loaders decode in the staged build), so a
UTF-8 byte-order mark in front of valid JSON (config.json, any JSON sidecar, the index) is refused by name
instead of passing through <code>json.loads(bytes)</code>, which strips it (on the reference base's files a leading mark
fails AutoConfig, AutoProcessor, AutoTokenizer and GenerationConfig: <code>Unexpected UTF-8 BOM</code> /
<code>not a valid JSON file</code>); and <code>shard_status</code> validates the safetensors header's shape (a JSON object of tensor
entries with a dtype string, a shape list and <code>data_offsets</code> of two non-negative integers begin &lt;= end, an
optional <code>__metadata__</code> object), so a malformed header is a named refusal in the preflight and a named failure
of the output verifier, never a traceback (fixtures
<code>::test_preflight_refuses_a_utf8_byte_order_mark_in_front_of_valid_json_as_the_loaders_do</code> and
<code>::test_shard_status_refuses_a_header_without_the_safetensors_shape_and_the_preflight_names_it</code>). The
construction is STAGED. The whole build happens in <code>&lt;out&gt;.tmp</code> beside an existing output: the overlay (the
base read by its real readers: the pinned safetensors reader on every shard, transformers on the sidecars),
the sidecar sync, <code>config.json &lt;- base</code>, the verification (index, sidecars and, unless <code>--no-verify</code>, the
torch probe, all on the staged copy) and the <code>.materialized</code> marker, the last file written there (its
semantics unchanged); only then the swap replaces the existing output by renames (<code>&lt;out&gt;</code> -&gt; <code>&lt;out&gt;.previous</code>,
<code>&lt;out&gt;.tmp</code> -&gt; <code>&lt;out&gt;</code>, <code>&lt;out&gt;.previous</code> removed; <code>materialize_hf.publish_staging</code>). On any failure before the
swap the staging directory is removed, the error names its stage and the existing output is byte-identical,
under <code>--force --no-verify</code> too. Transient disk: two exports side by side from the overlay to the swap (the
staged shards are written by <code>save_pretrained</code>, not linked). A leftover <code>&lt;out&gt;.previous</code> is refused before the
build unless <code>--force</code>, which discards it. Before the staging, the same preflight asks the pinned safetensors
reader itself (<code>conversion.hf.safetensors_reader_error</code>: <code>safe_open</code> on the header of every base shard the
index lists; dtype names, string metadata values, contiguous offsets, byte count per tensor, file length: a
BF16 <code>[3]</code> tensor over four bytes, an unknown dtype, a non-string metadata value and an offset gap all passed
the shape check) and decodes, strictly as UTF-8, every Jinja template the tokenizer and processor loaders read
(<code>chat_template.jinja</code> and each <code>additional_chat_templates/*.jinja</code> named template;
<code>conversion.hf.loader_template_files</code> cites the loader lines), refusing by file and reader message / decode
position in the one family (fixtures
<code>::test_preflight_refuses_a_base_shard_the_pinned_safetensors_reader_rejects_and_keeps_the_export</code>,
<code>::test_preflight_decodes_the_jinja_templates_the_loaders_read_as_strict_utf8_and_keeps_the_export</code>,
<code>::test_a_failure_after_the_preflight_keeps_the_existing_export_and_removes_the_staging_directory</code>,
<code>::test_the_swap_publishes_by_rename_and_a_leftover_previous_output_is_refused_without_force</code> and
<code>::test_preflight_refuses_when_the_pinned_safetensors_reader_cannot_be_imported</code>). Under <code>--force</code> no complete
marked tree is discarded while it is the only one: in the crash state between the swap's two renames
(<code>&lt;out&gt;.previous</code> = the old export, <code>&lt;out&gt;.tmp</code> = the new one complete and marked, no <code>&lt;out&gt;</code>)
<code>&lt;out&gt;.previous</code> is renamed back to <code>&lt;out&gt;</code> first and the build happens beside it; a leftover <code>&lt;out&gt;.previous</code>
beside an existing <code>&lt;out&gt;</code> is removed at the swap, after the new tree is verified. <code>--force</code> rebuilds from the
source; a death-left <code>&lt;out&gt;.tmp</code> is discarded once <code>&lt;out&gt;</code> is complete again whatever its marker says (a
marker match covers the identity, the shard sizes and tensor counts, not the shard bytes, and the base digest
excludes the base shards' bytes), a complete marked <code>&lt;out&gt;.tmp</code> that is the only complete tree is refused by
name rather than discarded, and a kept staged copy is published only by a request without <code>--force</code>, after the
same verification as a fresh build (index, sidecars, the torch probe unless <code>--no-verify</code>, which trusts the
kept copy's bytes on size and tensor count). One materializer per output: <code>&lt;out&gt;.lock</code> beside the output, held
with <code>fcntl.flock</code> from before the staging to after the swap; a second materializer on the same <code>--out</code> is
refused by name (pid, host, start time of the holder) without touching anything; the lock file stays beside
the output (it is not part of the export) and the file system must support flock (Lustre: the <code>flock</code> mount
option; a mount that refuses it is a named refusal). Fixtures
<code>::test_force_after_a_death_between_the_swap_renames_restores_the_old_export_before_building</code>,
<code>::test_two_materializers_on_one_output_exclude_each_other_through_the_per_output_lock</code>,
<code>::test_the_per_output_lock_refuses_by_name_in_process_and_fails_closed_without_flock</code>,
<code>::test_force_rebuilds_from_the_source_instead_of_publishing_a_death_left_copy</code> and
<code>::test_a_death_left_copy_is_published_only_by_a_request_without_force_after_verification</code>. An inherited sole
complete marked <code>&lt;out&gt;.tmp</code> (a first publication that died after <code>.materialized</code> and before the rename) is
never deleted: the unforced recovery checks its marker against the request (else refused by name), repairs a
missing staged <code>config.json</code> from the base through a temporary file and a rename, re-syncs the sidecars the
same way (never a shard), then verifies, re-marks and swaps; a failed recovery check refuses by name and KEEPS
the tree (its shards and its marker untouched, its sidecars possibly repaired from the base before the check:
config.json rewritten, a differing one kept as <code>config.json.trainer.bak</code>, a stray sidecar removed, a
<code>.copying</code> or <code>.writing</code> temporary left by an interrupted copy or unified-template rewrite, and under
<code>--unified-chat-template</code> the two template files back in the base's form when that rewrite did not reach its
rename; the refusal says so and names the state at <code>&lt;out&gt;</code>: absent, standing but not a complete marked export,
or a complete marked export), and the overlay is never run while the copy is the sole complete tree. The
marker / skip / mismatch decision is taken under the per-output lock, so a materializer that paused before the
lock while another published a different source is refused on that export's marker instead of overwriting it;
a held lock is waited for up to 120 s (<code>--lock-wait-seconds</code>, polling), so two simultaneous identical requests
of a published source both end with 0 (the second skips once the holder has finished), a differing request is
refused on the marker, and a holder still there after the bound is refused by name with the bound stated.
Fixtures: <code>::test_a_failed_recovery_check_leaves_the_inherited_sole_marked_copy_as_found</code>,
<code>::test_the_marker_decision_is_taken_under_the_output_lock_so_a_paused_materializer_cannot_overwrite_a_newer_export</code>,
<code>::test_a_repair_then_failed_recovery_check_keeps_the_shards_and_the_marker_and_says_what_it_changed</code>,
<code>::test_an_identical_request_waits_for_the_lock_holder_and_skips_with_0</code>,
<code>::test_the_lock_wait_is_bounded_and_the_refusal_names_the_bound</code> and
<code>::test_a_failed_unified_rewrite_during_recovery_leaves_the_writing_temporary_and_the_refusal_names_it</code>; the
lock bound must be a finite number &gt;= 0 (<code>inf</code> and <code>nan</code> are refused by name:
<code>::test_lock_wait_seconds_refuses_non_finite_values</code>). The source's identity of record (sha256 + bytes of
<code>model.pt</code>) is read UNDER the output lock, not before the wait, through a file object opened once there, and
the overlay memory-maps that SAME open file (through <code>/proc/self/fd</code>; where that reference does not exist the
loader reads the payload whole through the file object, no mmap, with the whole payload in RAM), so by
construction the skip / mismatch decision, the source record and the marker name the bytes the overlay
consumed, and the default verification (the torch probe) compares the staged shards against that same open
file (a path replaced during the overlay can neither fail a correct build nor pass a wrong one), whatever the
path names meanwhile: the merge tool (tmp + os.replace over <code>model.pt</code>) is not excluded by the lock and may
replace the path while the request waits (adopted with a WARNING naming both hashes) or while the overlay runs
(logged; nothing of what was built changes). The opened inode is fstat'd before the hash and after the
overlay: a change of its size or mtime refuses the build by name, with no "same bytes" acceptance, since the
digest of the file after the fact does not say what a reader consumed; that check is best effort against a
writer into the opened inode (a client may report an open inode's attributes late), which the merge tool never
is: the guarantee of record is against a replaced path, by construction (fixtures
<code>::test_the_marker_records_the_source_the_overlay_read_when_the_source_changes_during_the_lock_wait</code>,
<code>::test_a_source_replaced_during_the_overlay_does_not_change_what_was_built_or_recorded</code>,
<code>::test_the_marker_names_the_bytes_the_overlay_consumed_when_forced_merges_race_the_overlay</code> with the real
merge tool, <code>::test_the_default_verification_receives_the_held_payload</code>, the verification suite's
<code>test_checkpoint_hf_verification.py::test_default_verification_consumes_the_held_payload_when_the_path_is_replaced</code>
with the real merge tool and the real torch verifier, and the loader's
<code>test_checkpoint_hf_overlay.py::test_load_consolidated_state_dict_reads_the_open_file_not_the_path</code>). The
weights-free loader calls themselves (<code>AutoProcessor</code> / <code>AutoTokenizer</code> / <code>GenerationConfig</code> <code>from_pretrained</code>
on the base) are NOT part of the preflight, by design: they are not torch-free (the processor instantiates the
image and video processors, which import torch), their verdicts depend on the installed transformers rather
than on the files, and the synthetic bases of the tests are not loadable by them; a base that passes every
file check but fails a loader on a schema fact the files do not state (<code>tokenizer.json</code> = <code>{}</code>, a
<code>preprocessor_config.json</code> without <code>image_processor_type</code>) is still refused by the overlay, in the staged
build, with the existing output kept. A <code>chat_template.jinja</code> (or a <code>processor_config.json</code> key) whose text
equals the canonical text is allowed, synced verbatim and recorded under <code>chat_template.preferred_sidecars</code>;
<code>verify_sidecars</code> applies the same rule to the export. Fixtures:
<code>tests/test_checkpoint_materialize_hf.py::test_unified_chat_template_refuses_a_base_whose_preferred_template_sidecar_diverges</code>
and <code>tests/test_data_packer_sft.py::test_unified_export_tokenizer_loads_the_canonical_text_and_a_divergent_jinja_sidecar_is_refused</code>
(a real tokenizer load from a unified export of a toy base: canonical; with the Jinja beside it: the Jinja);
the directory rule and the preflight order:
<code>tests/test_checkpoint_materialize_hf.py::test_unified_template_directory_rule_is_one_helper_for_preflight_and_verifier</code>
and <code>tests/test_checkpoint_materialize_hf.py::test_force_rebuild_keeps_the_existing_output_when_a_torch_free_preflight_refuses</code>.
Prefix rows (section 4) are exact under the default serve of a default export. Offline proof on the real
base's sidecars: the tokenizer loaded from a unified scratch export renders req_012 (messages normalised as
vLLM does: <code>developer</code> to <code>system</code>, <code>content: null</code> to <code>""</code>, <code>reasoning</code> as <code>reasoning_content</code>, argument
strings parsed, the image placeholder expanded to its 209 tokens; its two replayed reasoning strings begin and
end with a newline) to 8,969 ids with positions 7248, 7254, 8016, 8025 reading 198, 624, 198, 624 (the
stripped form: <code>\n</code> and <code>.\n</code>); the verbatim processor template renders 8,969 ids with 271, 382, 271, 382 at
the same positions (the padded form: <code>\n\n</code> and <code>.\n\n</code>), pinned beside it; the base's tokenizer renders
8,946. Consequence: the shared-vocabulary identity of <code>config/build.py</code> hashes the tokenizer's
<code>chat_template</code>, so a unified export is not an OPD teacher for a student loaded from the default sidecars (and
the reverse); pair teacher and student on the same choice. Serve assumption, recorded in <code>.materialized</code>
beside the shas (<code>chat_template.serve_assumption</code>): the serve sets no <code>enable_thinking</code>. Under the unified
template a request that sets <code>enable_thinking=true</code> is prefilled with the opener token itself,
<code>&lt;|im_start|&gt;assistant\n&lt;think&gt;</code> (id 151667, no newline after it: 251 vs 250 ids; the same tail without tools,
<code>\n</code>, <code>&lt;|im_start|&gt;</code>, <code>assistant</code>, <code>\n</code>, <code>&lt;think&gt;</code>, 10 ids against 9), while the rows supervise the opener as
the student's first token; under such a serve <code>rl.mask_think_opener=True</code> masks exactly that one token and the
supervised target begins with the newline that opens the reasoning text (the rule of an <code>opener: prefilled</code>
row, section 4). The agent harness sends no <code>enable_thinking</code>, and the student's serve recipe must not set it.
Fixtures:
<code>tests/test_checkpoint_materialize_hf.py::test_unified_chat_template_rewrites_the_tokenizer_template_only_and_is_verified_by_rule</code>
and <code>test_main_unified_chat_template_option_identity_and_skip</code>; the padded and stripped forms side by side on
the official template through the toy tokenizer (same count, <code>\n\n</code> tokens become <code>\n</code> tokens; a trimmed
string renders identically under both):
<code>tests/test_data_packer_sft.py::test_processor_canonical_template_trims_the_replayed_reasoning_where_the_verbatim_template_pads_it</code>.</p>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">8. Extension points</h2><a id="user-content-8-extension-points" class="anchor" aria-label="Permalink: 8. Extension points" href="#8-extension-points"><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">Keep tensor shaping in <code>data/packer/sft.py</code>, objective math in <code>algorithm/sft.py</code>, model
adaptation in <code>model/qwen3_5.py</code>, and lifecycle orchestration in <code>entrypoints/sft.py</code>.</p>
</article></div><div class="d-none"></div></section></div></div></div> </div> <!-- --> </div></div></div></div></div></div><div class="scrollMarksContainer__STmjRv" 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>

