diff --git a/.github/instructions/content.instructions.md b/.github/instructions/content.instructions.md index a4606d6d0487..d6a1443502d2 100644 --- a/.github/instructions/content.instructions.md +++ b/.github/instructions/content.instructions.md @@ -92,3 +92,61 @@ Examples: * ❌ Incorrect: "The cat – which sat on a branch – smiled with a broad grin." (en dash with spaces) * ❌ Incorrect: "The cat-which sat on a branch-smiled with a broad grin." (hyphen without spaces) * ❌ Incorrect: "The cat - which sat on a branch - smiled with a broad grin." (hyphen with spaces) + +## Versioning + +Avoid `{% ifversion fpt %}`, `{% ifversion ghec %}`, and `{% ifversion fpt or ghec %}` in content files whenever possible. Instead of suggesting or adding version-gating within an article: + +* Write content that applies to all versions the article is versioned for +* If content is truly version-specific, consider whether it is low-harm to show it to all readers (e.g., an enterprise-only row in a reference table) +* Only use `{% ifversion %}` as a last resort when content would be actively misleading for readers on a different version + +**FPT and GHEC content**: When dotcom content applies to both products, version the page for `fpt` and `ghec` in the frontmatter. Do NOT use in-article Liquid versioning. Do NOT suggest adding `{% ifversion fpt or ghec %}` blocks as a fix for content that mentions a dotcom-only feature. Instead, suggest rewriting the content using the alternatives to inline versioning options listed below. + +**GHES content**: If versioning is necessary for GitHub Enterprise Server content, use feature-based versioning (FBV). GHES content should rely on feature flags defined in `data/features/` rather than inline `{% ifversion ghes %}` blocks. Feature flags allow centralized control of when content appears for specific GHES releases. + +### Alternatives to inline versioning + +Before resorting to in-article versioning, first consider whether the content is actually different across versions. Often procedures can be simplified to work at both levels. + +Use these strategies instead of `{% ifversion %}`, depending on the level of content: + +**At the article level:** + +* When the feature is only available in certain products, use the "Who can use this feature?" box to convey that the content of the article applies only to specific products +* When an article only exists because the functionality is only available in older GHES releases (and not on {% data variables.product.prodname_dotcom_the_website %} or newer GHES releases), just remove that article + +**At the heading level:** + +* Use prose similar to "Who can use this feature?" to convey that the content of a section applies only to specific products + +**At the paragraph or sentence level:** + +* If you're briefly introducing a feature and then linking to an article, there's no need to specify versioning. Let readers learn availability when they follow the link, via the "Who can use this feature?" box +* When necessary, start sentences with "With {% data variables.product.prodname_ghe_cloud %}...", "On {% data variables.product.prodname_dotcom_the_website %}...", etc. +* End list items with "({% data variables.product.prodname_ghe_cloud %} only)", "({% data variables.product.prodname_dotcom_the_website %} only)", etc. +* Specify if the feature is not available for GHES with "NAME-OF-FEATURE is not available for {% data variables.product.prodname_ghe_server %}", "... (not available in {% data variables.product.prodname_ghe_server %})", etc. + +### Example + +When documenting a feature that only applies to dotcom (not GHES): + +❌ Don't wrap content in version blocks: + +```markdown +{% ifversion fpt or ghec %} + +## Immutable subject claims + +Repositories created after July 15, 2026 now use an immutable default subject format. + +{% endif %} +``` + +✅ Do use prose to indicate availability: + +```markdown +## Immutable subject claims + +Repositories created after July 15, 2026 now use an immutable default subject format. This rollout does not include {% data variables.product.prodname_ghe_server %}. +``` diff --git a/.github/workflows/changelog-agent.yml b/.github/workflows/changelog-agent.yml index b7a25cd66bb6..de8637dacef1 100644 --- a/.github/workflows/changelog-agent.yml +++ b/.github/workflows/changelog-agent.yml @@ -404,6 +404,16 @@ jobs: fs.writeFileSync('prompt.txt', userPrompt); core.setOutput('date_str', dateStr); + - name: Set up Node.js for Copilot CLI + if: steps.check_parent.outputs.has_parent == 'true' && steps.check_existing.outputs.exists == 'false' + uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 + with: + node-version: 24 + + - name: Install GitHub Copilot CLI + if: steps.check_parent.outputs.has_parent == 'true' && steps.check_existing.outputs.exists == 'false' + run: npm install -g @github/copilot + - name: Generate changelog draft via Copilot if: steps.check_parent.outputs.has_parent == 'true' && steps.check_existing.outputs.exists == 'false' id: generate_draft diff --git a/.github/workflows/copy-api-issue-to-internal.yml b/.github/workflows/copy-api-issue-to-internal.yml index a76c18026330..4e1c6243e471 100644 --- a/.github/workflows/copy-api-issue-to-internal.yml +++ b/.github/workflows/copy-api-issue-to-internal.yml @@ -45,7 +45,9 @@ jobs: - name: Create an issue in the docs-content repo run: | - new_issue_url="$(gh issue create --title "$ISSUE_TITLE" --body "$ISSUE_BODY" --repo github/docs-content --label "workflow-generated")" + new_issue_url="$(gh issue create --title "$ISSUE_TITLE" --body "$ISSUE_BODY + + Copied to this repo by the [$GITHUB_WORKFLOW workflow run]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID)." --repo github/docs-content --label "workflow-generated")" echo 'NEW_ISSUE='$new_issue_url >> $GITHUB_ENV env: GITHUB_TOKEN: ${{secrets.DOCS_BOT_PAT_BASE}} diff --git a/.github/workflows/delete-orphan-translation-files.yml b/.github/workflows/delete-orphan-translation-files.yml index aa1757f1c51d..ba45c5c63897 100644 --- a/.github/workflows/delete-orphan-translation-files.yml +++ b/.github/workflows/delete-orphan-translation-files.yml @@ -127,7 +127,7 @@ jobs: echo "Creating pull request..." gh pr create \ --title "Delete orphan files ($current_daystamp)" \ - --body '👋 humans. This PR was generated from docs-internal/.github/workflows/delete-orphan-translation-files.yml. + --body '👋 humans. This PR was generated by the [Delete orphan translation files](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) workflow run. ' \ --repo "${{ matrix.language_repo }}" \ --label "workflow-generated" \ diff --git a/.github/workflows/generate-code-scanning-query-lists.yml b/.github/workflows/generate-code-scanning-query-lists.yml index da3e7f726a7b..e3fd557f6014 100644 --- a/.github/workflows/generate-code-scanning-query-lists.yml +++ b/.github/workflows/generate-code-scanning-query-lists.yml @@ -259,4 +259,6 @@ jobs: No action is required from the first responder for the Docs content team. This PR is automatically added to the Docs content review board. Any writer can review this by checking that the PR looks sensible. If CI does not pass or other problems arise, contact #docs-engineering on slack. - When the DRI for the CodeQL CLI release is ready to publish, they will ask us to merge this PR in #docs-content.' + When the DRI for the CodeQL CLI release is ready to publish, they will ask us to merge this PR in #docs-content. + + _Generated by the [Generate code scanning query lists](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) workflow run._' diff --git a/.github/workflows/moda-allowed-ips.yml b/.github/workflows/moda-allowed-ips.yml index eefba673bca2..5d134793c418 100644 --- a/.github/workflows/moda-allowed-ips.yml +++ b/.github/workflows/moda-allowed-ips.yml @@ -48,7 +48,9 @@ jobs: git push gh pr create \ --title "Update list of allowed IPs" \ - --body 'This PR updates the list of allowed IPs in Moda. It is automatically generated.' \ + --body "This PR updates the list of allowed IPs in Moda. It is automatically generated. + + _Generated by the [Update Moda allowed IPs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) workflow run._" \ --label "workflow-generated" \ --head=$branchname echo "Pull request created" diff --git a/.github/workflows/orphaned-features-check.yml b/.github/workflows/orphaned-features-check.yml index 5689a95f764a..21f39d8cf2a4 100644 --- a/.github/workflows/orphaned-features-check.yml +++ b/.github/workflows/orphaned-features-check.yml @@ -90,6 +90,8 @@ jobs: to make sure they aren't referenced anywhere and then approve and merge the pull request. For more information, see [Doc: Orphaned Features](https://github.com/github/docs-engineering/blob/main/docs/orphaned-features.md). + + Generated by the [orphaned features workflow run]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID). EOM ) diff --git a/.github/workflows/orphaned-files-check.yml b/.github/workflows/orphaned-files-check.yml index 09b604711ab6..600efa06c2ca 100644 --- a/.github/workflows/orphaned-files-check.yml +++ b/.github/workflows/orphaned-files-check.yml @@ -98,6 +98,8 @@ jobs: If you are the first responder, please spot check some of the unused assets to make sure they aren't referenced anywhere. Then, approve and merge the pull request. For more information, see [Doc: Orphaned Assets](https://github.com/github/docs-engineering/blob/main/docs/orphaned-assets.md) and [Doc: Reusables CLI](https://github.com/github/docs-internal/tree/main/src/content-render/scripts/reusables-cli). + + Generated by the [orphaned files workflow run]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID). EOM ) diff --git a/.github/workflows/purge-fastly-all.yml b/.github/workflows/purge-fastly-all.yml new file mode 100644 index 000000000000..4aa2745ce409 --- /dev/null +++ b/.github/workflows/purge-fastly-all.yml @@ -0,0 +1,44 @@ +name: Purge Fastly (all) + +# **What it does**: Purges the ENTIRE Fastly cache for docs (every URL) on demand. +# **Why we have it**: So docs engineering can clear a bad cache state without asking core engineering to run a purge-all in the Fastly UI. +# **Who does it impact**: All readers. Origin sees a traffic spike while the cache refills, so only run this when a targeted purge will not do. + +on: + workflow_dispatch: + inputs: + confirm: + description: "Type 'purge everything' to confirm a full hard purge of the Fastly cache." + required: true + +permissions: + contents: read + +# Only one purge-all may run at a time. Do not cancel an in-flight purge: +# a half-finished purge leaves the cache in an unknown state. +concurrency: + group: purge-fastly-all + cancel-in-progress: false + +env: + FASTLY_TOKEN: ${{ secrets.FASTLY_TOKEN }} + FASTLY_SERVICE_ID: ${{ secrets.FASTLY_SERVICE_ID }} + +jobs: + purge-all: + if: github.repository == 'github/docs-internal' + runs-on: ubuntu-latest + steps: + - name: Validate confirmation input + if: ${{ inputs.confirm != 'purge everything' }} + run: | + echo "::error::Confirmation text did not match. Re-run and type exactly: purge everything" + exit 1 + + - name: Check out repo + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + + - uses: ./.github/actions/node-npm-setup + + - name: Purge entire Fastly cache + run: npm run purge-fastly-all diff --git a/.github/workflows/sme-review-tracking-issue.yml b/.github/workflows/sme-review-tracking-issue.yml index c8725ca73d52..b8fa0a50289c 100644 --- a/.github/workflows/sme-review-tracking-issue.yml +++ b/.github/workflows/sme-review-tracking-issue.yml @@ -53,6 +53,9 @@ jobs: - Routed to another channel / team - Reviewer stating they'll need to get back to us at a later time - Review provided was unclear or missing key information, and a follow-up is necessary + + --- + _Generated by the [${context.workflow}](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}) workflow run._ `, labels: ['on track','open source', 'sme-review', 'workflow-generated'], }); diff --git a/.github/workflows/sync-openapi.yml b/.github/workflows/sync-openapi.yml index 4c1221cf36df..a8e596864ee3 100644 --- a/.github/workflows/sync-openapi.yml +++ b/.github/workflows/sync-openapi.yml @@ -113,7 +113,9 @@ jobs: Docs First Responders should follow [the acting-as-the-first-responder instructions](https://github.com/github/docs-team/blob/main/contributing-to-docs/first-responder/acting-as-the-first-responder.md?plain=1#L156). - If CI does not pass or other problems arise, contact #docs-engineering on slack.' \ + If CI does not pass or other problems arise, contact #docs-engineering on slack. + + _Generated by the [Sync OpenAPI schema](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) workflow run._' \ --repo github/docs-internal \ --label github-openapi-bot,workflow-generated \ --head=$branchname \ diff --git a/.github/workflows/sync-sdk-docs.yml b/.github/workflows/sync-sdk-docs.yml index 789da315dcea..df0fb34b4537 100644 --- a/.github/workflows/sync-sdk-docs.yml +++ b/.github/workflows/sync-sdk-docs.yml @@ -216,7 +216,7 @@ jobs: > This PR is auto-generated. Do not edit it directly — make changes in the [copilot-sdk docs](https://github.com/github/copilot-sdk/tree/main/docs) instead. --- - _Generated by the [sync-sdk-docs](https://github.com/github/docs-internal/actions/workflows/sync-sdk-docs.yml) workflow._" + _Generated by the [sync-sdk-docs workflow run]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID)._" EXISTING_PR=$(gh pr list --head "$SYNC_BRANCH" --json number --jq '.[0].number' 2>/dev/null || true) diff --git a/content/code-security/reference/security-incident-response/investigation-areas.md b/content/code-security/reference/security-incident-response/investigation-areas.md index 311503c2a219..d241b9365de7 100644 --- a/content/code-security/reference/security-incident-response/investigation-areas.md +++ b/content/code-security/reference/security-incident-response/investigation-areas.md @@ -109,6 +109,8 @@ You found suspicious code in your repository, a security researcher reported an * Review the **Actions** tab for unexpected workflow runs, especially those triggered by unfamiliar users or at unusual times. * Inspect workflow run logs for suspicious output. +* Review the credentials accessible to suspicious workflow runs, including the default `GITHUB_TOKEN`, any {% data variables.product.pat_generic_plural %}, {% data variables.product.prodname_github_app %} tokens, or other credentials stored as secrets. The `GITHUB_TOKEN` is scoped to the job and expires when the job completes, but other credentials have their own lifecycle and do not expire with the job. Any credential that may have been exposed should be treated as compromised and rotated or replaced immediately. +* Be aware that workflow run logs only capture standard output from workflow steps. Activity that does not write to standard output (such as network calls, file system modifications, or background processes) will not appear in the logs. For a more comprehensive investigation, correlate with audit log events. * Use {% data variables.product.github %} code search to find suspicious files or code additions, particularly in workflow files (`.github/workflows/`), shell scripts, or configuration files. * Use the Activity view to check for pushes to unusual branch names, force pushes, pushes from unexpected actors. * Check the audit logs for changes to security settings or disablement actions (look for events like `repository_ruleset.destroy`, `repository_secret_scanning_push_protection.disable`, or other `.delete`, `.disable`, `.destroy` events). @@ -127,6 +129,8 @@ You found suspicious code in your repository, a security researcher reported an ### Key resources * [Containment actions](/code-security/tutorials/secure-your-organization/responding-to-security-incidents#step-2-contain-the-threat) +* [AUTOTITLE](/actions/concepts/security/github_token) +* [AUTOTITLE](/actions/reference/security/secure-use) {% ifversion fpt or ghec %} diff --git a/content/code-security/reference/security-incident-response/investigation-tools.md b/content/code-security/reference/security-incident-response/investigation-tools.md index a9534d1c1acd..1db03e9b72d7 100644 --- a/content/code-security/reference/security-incident-response/investigation-tools.md +++ b/content/code-security/reference/security-incident-response/investigation-tools.md @@ -156,7 +156,8 @@ Read access to the repository. * Confirm what executed in CI/CD at a given time (such as the commands executed, or the dependency installed). * Investigate suspicious workflow runs, such as those triggered by an unfamiliar user or at an unusual time, to see what actions were performed, which secrets were accessed, and what code was executed. -* Determine whether a workflow had access to any secrets. +* Review what credentials a workflow job had access to, including the default `GITHUB_TOKEN`, any {% data variables.product.pat_generic_plural %}, {% data variables.product.prodname_github_app %} tokens, other credentials stored as secrets, and access tokens obtained during the workflow run. +* Retrieve logs programmatically via the REST API for archival, forensic, or automation purposes. #### Permissions required @@ -166,8 +167,22 @@ Read access to the repository. * [AUTOTITLE](/actions/how-tos/monitor-workflows/view-workflow-run-history) * [AUTOTITLE](/actions/how-tos/monitor-workflows/use-workflow-run-logs) +* [AUTOTITLE](/actions/how-tos/manage-workflow-runs/download-workflow-artifacts) +* [AUTOTITLE](/actions/concepts/security/github_token) +* [AUTOTITLE](/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets) +* [AUTOTITLE](/actions/reference/security/secure-use) +* [AUTOTITLE](/rest/actions/workflow-runs) +* [AUTOTITLE](/rest/actions/workflow-jobs) +* [AUTOTITLE](/code-security/tutorials/implement-supply-chain-best-practices/securing-builds) ### Notes and limitations * {% data variables.product.github %} automatically redacts secrets from workflow logs. -* By default, workflow logs are retained by {% data variables.product.github %} for 90 days, but you can configure this retention period to be longer (up to 400 days for private repositories). +* By default, workflow logs are retained by {% data variables.product.github %} for 90 days, but you can configure this retention period. {% ifversion fpt or ghec %}For public repositories, the maximum retention is 90 days. For private{% ifversion ghec %} and internal{% endif %} repositories, the maximum is 400 days.{% else %}The maximum retention is 400 days.{% endif %} Retention can be configured at the enterprise, organization, or repository level. If a workflow run occurred outside of your configured retention window, the logs may no longer be available. For more information, see [AUTOTITLE](/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository), [AUTOTITLE](/organizations/managing-organization-settings/configuring-the-retention-period-for-github-actions-artifacts-and-logs-in-your-organization), or [AUTOTITLE](/admin/enforcing-policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-github-actions-in-your-enterprise). +* Workflow runs (including their logs) can also be deleted via the REST API. To check whether a run was deleted, query for `workflows.delete_workflow_run` events in the audit log. +* The default `GITHUB_TOKEN` issued to each job is scoped to that job and expires when the job finishes or after its effective maximum lifetime (up to 24 hours on self-hosted runners). Even if a step captured the token, it cannot be reused after the job finishes. For more information, see [AUTOTITLE](/actions/concepts/security/github_token). +* Other credentials referenced in workflows, such as {% data variables.product.pat_generic_plural %}, {% data variables.product.prodname_github_app %} installation tokens, or third-party API keys stored as secrets, have their own lifecycle and do not expire when the job ends. If a workflow step exposed one of these credentials, the token remains valid until it is revoked or expires according to its own policy. Any credential that may have been exposed should be treated as compromised and rotated or replaced immediately. Review the workflow file and the repository, organization, and environment secrets to determine which credentials were accessible. For more information, see [AUTOTITLE](/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets). +* You can download logs for an entire workflow run or for a specific job programmatically using the REST API. Both endpoints return a redirect URL that is valid for one minute. For more information, see [AUTOTITLE](/rest/actions/workflow-runs) and [AUTOTITLE](/rest/actions/workflow-jobs). +* Workflow run logs only capture standard output from workflow steps. Activity that does not write to standard output, such as network calls, file system modifications, or background processes, does not appear in the logs. +* For {% data variables.product.github %}-hosted runners, the runner environment is ephemeral and destroyed after the job completes. {% data variables.product.github %} does not retain any data beyond the workflow run logs for these runners. For self-hosted runners, additional host-level or network telemetry may be available from your own infrastructure. +* For a more comprehensive investigation, correlate workflow run logs with audit log events. Events such as `git.clone`, `git.fetch`, `git.push`, `protected_branch.create`, and `protected_branch.policy_override` can provide additional context. Because Git events in {% data variables.product.github %}-hosted audit logs are currently retained for only 7 days for enterprises, setting up streamed enterprise audit logs ahead of time is important for this type of investigation. For more information, see [AUTOTITLE](/code-security/tutorials/secure-your-organization/preparing-for-security-incidents). diff --git a/content/copilot/concepts/billing/budgets-for-usage-based-billing.md b/content/copilot/concepts/billing/budgets-for-usage-based-billing.md index 6439cf068cf7..16e3c878e129 100644 --- a/content/copilot/concepts/billing/budgets-for-usage-based-billing.md +++ b/content/copilot/concepts/billing/budgets-for-usage-based-billing.md @@ -1,10 +1,10 @@ --- title: Budgets for usage-based billing shortTitle: Budgets -intro: 'Under usage-based billing, budget controls at the user, cost center, and enterprise levels determine how {% data variables.product.prodname_copilot_short %} usage is served, metered, or blocked.' +intro: 'Under usage-based billing, budget controls at the user, organization, cost center, and enterprise levels determine how {% data variables.product.prodname_copilot_short %} usage is served, metered, or blocked.' versions: feature: copilot -permissions: 'Enterprise owners and billing managers can set all budget controls. Organization owners can set organization-level and cost center budgets.' +permissions: 'Enterprise owners and billing managers can set all budget controls. Organization owners can set organization-level budgets.' product: '{% data variables.copilot.copilot_enterprise_short %} or {% data variables.copilot.copilot_business_short %}' contentType: concepts category: @@ -13,9 +13,9 @@ category: Every {% data variables.product.prodname_copilot_short %} license includes {% data variables.product.prodname_ai_credits_short %} that are pooled across your enterprise. Budget controls let you govern how individual users draw from that pool, and cap any additional spending once it's exhausted. This article explains what each budget control does, how the system evaluates them, and what happens when a limit is reached. -## Understanding the four budget controls +## Understanding budget controls -You have four budget controls, each serving a different purpose. They work together, not as alternatives. +You have budget controls at the user, organization, cost center, and enterprise levels, each serving a different purpose. They work together, not as alternatives. ### User-level budget @@ -38,6 +38,14 @@ A cost center budget caps metered charges for a defined group of users or an org When a cost center's budget is exhausted, only users in that cost center are blocked. Other users and cost centers are unaffected. +### Organization budget + +An organization budget caps metered charges for users who receive their {% data variables.product.prodname_copilot_short %} license through that organization. Like cost center budgets, it is only active after the shared pool is exhausted. + +Organization budgets are the only budget option available to organization owners. They can only further restrict usage below any budget set by an enterprise admin, and they cannot override a higher-level budget. + +If a user receives {% data variables.product.prodname_copilot_short %} licenses from multiple organizations, {% data variables.product.github %} picks one organization at random each billing cycle to bill the seat. This means the user's spend could count against a different organization's budget from month to month, making enforcement unpredictable. To avoid this, ensure each user has a single license through one organization, or use cost center budgets with direct user assignment. + ### Enterprise budget The enterprise budget caps total metered charges across your entire enterprise. Like cost center budgets, it is only active after the shared pool is exhausted. @@ -52,6 +60,7 @@ The enterprise budget caps total metered charges across your entire enterprise. | Universal user-level budget | Each user's total {% data variables.product.prodname_ai_credit_singular %} consumption | Always (pool + metered) | Per user | Always | | Individual user-level budget | A specific user's total consumption (overrides universal) | Always (pool + metered) | Per user | Always | | Cost center budget | A team's metered charges after pool exhaustion | Metered phase only | Per cost center | Only if "Stop usage when budget limit is reached" is enabled | +| Organization budget | An organization's metered charges after pool exhaustion | Metered phase only | Per organization | Only if "Stop usage when budget limit is reached" is enabled | | Enterprise budget | Total enterprise metered charges after pool exhaustion | Metered phase only | Enterprise-wide | Only if "Stop usage when budget limit is reached" is enabled | Any budget set to $0 USD stops usage immediately for the users it applies to. @@ -67,15 +76,16 @@ Each request for an {% data variables.product.prodname_ai_credit_singular %}-con 1. **User-level budget check.** The system first checks whether the user has exceeded their user-level budget. If yes, the request is blocked immediately—user-level budgets are always a hard stop. If no (or no ULB is set), the request continues. 1. **Shared pool check.** Next, the system checks whether the shared pool has {% data variables.product.prodname_ai_credits_short %} remaining. If yes, the request is served from the pool at no extra cost. If the pool is empty, the request moves to metered usage at {% data variables.product.prodname_ai_credits_value %} per {% data variables.product.prodname_ai_credit_singular %}. -1. **Cost center or enterprise check.** For metered usage, the system checks whether the user is assigned to a cost center. +1. **Cost center, organization, or enterprise check.** For metered usage, the system checks budgets in the following order: * **If the user is in a cost center:** The cost center's budget is checked. If budget remains, the cost center pays. If the budget is exhausted, the system checks whether "Stop usage when budget limit is reached" is enabled. - * **If the user is not in a cost center:** The enterprise spending limit is checked. If the limit has not been reached, the enterprise pays. If the limit has been reached, the system checks whether "Stop usage when budget limit is reached" is enabled. + * **If the user is not in a cost center but their license is billed to an organization with a budget:** The organization's budget is checked. If budget remains, the organization pays. If the budget is exhausted, the system checks whether "Stop usage when budget limit is reached" is enabled. + * **If no cost center or organization budget applies:** The enterprise spending limit is checked. If the limit has not been reached, the enterprise pays. If the limit has been reached, the system checks whether "Stop usage when budget limit is reached" is enabled. - In both cases, if "Stop usage when budget limit is reached" is on, the user is blocked. If it is off, charges continue to accrue without a cap. + In all cases, if "Stop usage when budget limit is reached" is on, the user is blocked. If it is off, charges continue to accrue without a cap. > [!IMPORTANT] -> "Stop usage when budget limit is reached" applies to enterprise spending limits and cost center budgets only, and is off by default. Without it, charges continue to accrue past the limit. Always enable it when creating a spending limit. User-level budgets always enforce a hard stop and do not have this setting. +> "Stop usage when budget limit is reached" applies to enterprise spending limits, cost center budgets, and organization budgets only, and is off by default. Without it, charges continue to accrue past the limit. Always enable it when creating a budget. User-level budgets always enforce a hard stop and do not have this setting. ## How user-level budgets and spending limits interact diff --git a/content/copilot/concepts/billing/usage-based-billing-for-organizations-and-enterprises.md b/content/copilot/concepts/billing/usage-based-billing-for-organizations-and-enterprises.md index bdd283caffc0..f158267ed7f8 100644 --- a/content/copilot/concepts/billing/usage-based-billing-for-organizations-and-enterprises.md +++ b/content/copilot/concepts/billing/usage-based-billing-for-organizations-and-enterprises.md @@ -68,12 +68,12 @@ Additional usage budgets are set in US dollars, and usage is shown in {% data va ## How can I control costs with budgets? -Budget controls let you govern how individual users draw from the shared pool and cap any additional spending once it's exhausted. You can set budgets at four levels: +Budget controls let you govern how individual users draw from the shared pool and cap any additional spending once it's exhausted. You can set budgets at multiple levels: * **User-level budgets** cap how much an individual user can consume per billing cycle, from both the shared pool and additional usage. A $0 USD user-level budget blocks the user immediately. * **Cost-center budgets** cap metered charges for a defined group of users after the pool is exhausted. * **Enterprise spending limits** cap total metered charges across your entire enterprise after the pool is exhausted. -* **Organization-level budgets** track spending for all repositories in the organization. +* **Organization-level budgets** cap metered charges for users whose {% data variables.product.prodname_copilot_short %} seats are billed to the organization, after the pool is exhausted. For a full explanation of how these controls work together and when usage gets blocked, see [AUTOTITLE](/copilot/concepts/billing/budgets-for-usage-based-billing). diff --git a/content/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers.md b/content/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers.md index b2807e1c71f9..ac9bf01024c8 100644 --- a/content/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers.md +++ b/content/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers.md @@ -22,10 +22,15 @@ The Model Context Protocol (MCP) is an open standard that defines how applicatio If your organization or enterprise has configured a registry URL and allowlist policy, those settings apply to {% data variables.copilot.copilot_cli_short %}. The configured registry URL will appear as a discovery source, and only servers permitted by the allowlist policy can run. -You can add MCP servers using the interactive `/mcp add` command within the CLI, or by editing the configuration file directly. +You can add MCP servers in the following ways: +* [Using the `/mcp add` command](#using-the-mcp-add-command) +* [Using the `copilot mcp add` subcommand](#using-the-copilot-mcp-add-subcommand) +* [Editing the configuration file](#editing-the-configuration-file) +* [Searching and installing from the registry (experimental)](#searching-and-installing-from-the-registry) For installation instructions, available tools, and URLs for specific MCP servers, see the [{% data variables.product.github %} MCP Registry](https://github.com/mcp). + ### Using the `/mcp add` command 1. In interactive mode, enter `/mcp add`. A configuration form is displayed. Use Tab to navigate between fields. @@ -50,6 +55,59 @@ For installation instructions, available tools, and URLs for specific MCP server 1. Next to **Tools**, specify which tools from the server should be available. Enter `*` to include all tools, or provide a comma-separated list of tool names (no quotes needed). The default is `*`. 1. Press Ctrl+S to save the configuration. The MCP server is added and available immediately without restarting the CLI. +### Using the `copilot mcp add` subcommand + +You can add MCP servers from the terminal using the `copilot mcp add` subcommand, without entering interactive mode. The server is added to the user configuration at `~/.copilot/mcp-config.json`. + +For local (stdio) servers, provide the command after `--`: + +```shell copy +copilot mcp add SERVER-NAME -- COMMAND [ARGS...] +``` + +For remote (HTTP/SSE) servers, specify the transport and provide the URL: + +```shell copy +copilot mcp add --transport http SERVER-NAME URL +``` + +You can also pass additional options: + +* `--env KEY=VALUE`: Set environment variables for the server. Repeat for multiple variables. +* `--header "HEADER: VALUE"`: Set HTTP headers for remote servers. Repeat for multiple headers. +* `--transport TRANSPORT`: Set the transport type (`stdio`, `http`, or `sse`). The default is `stdio`. +* `--tools TOOLS`: Specify which tools to enable. Use `*` for all tools (default), a comma-separated list, or `""` for none. +* `--timeout MS`: Set a timeout in milliseconds. + +#### Examples + +Add a local stdio server: + +```shell copy +copilot mcp add context7 -- npx -y @upstash/context7-mcp +``` + +Add a local server with environment variables: + +```shell copy +copilot mcp add github -e GITHUB_PERSONAL_ACCESS_TOKEN=YOUR_GITHUB_PAT -- docker run -i --rm -e GITHUB_PERSONAL_ACCESS_TOKEN ghcr.io/github/github-mcp-server +``` + +Add a remote HTTP server: + +```shell copy +copilot mcp add --transport http notion \ + https://mcp.notion.com/mcp +``` + +Add a remote server with an authorization header: + +```shell copy +copilot mcp add --transport http \ + --header "Authorization: Bearer YOUR-TOKEN" \ + stripe https://mcp.stripe.com +``` + ### Editing the configuration file You can also add MCP servers by editing the configuration file at `~/.copilot/mcp-config.json`. This is useful if you want to share configurations or add multiple servers at once. @@ -80,9 +138,31 @@ The following example shows a configuration file with a local server and a remot For more information on MCP server configuration, see [AUTOTITLE](/copilot/how-tos/use-copilot-agents/cloud-agent/extend-cloud-agent-with-mcp#writing-a-json-configuration-for-mcp-servers). +### Searching and installing from the registry + +> [!NOTE] +> The `/mcp search` command is currently an experimental feature. To use it, start {% data variables.copilot.copilot_cli_short %} with the `--experimental` command line option, or enter `/experimental on` during a session. + +You can discover and install MCP servers directly from the [{% data variables.product.github %} MCP Registry](https://github.com/mcp) using the `/mcp search` command in interactive mode. This lets you browse available servers, view their details, and install them without manually filling out the configuration form. + +If your organization has configured a custom MCP registry URL, `/mcp search` connects to that registry instead of the default {% data variables.product.github %} registry. + +1. In interactive mode, enter `/mcp search` to browse top servers by stars, or `/mcp search QUERY` to search for a specific server. For example: + + ```text + /mcp search context7 + ``` + +1. A keyboard-navigable list of matching servers is displayed. Use the arrow keys to browse the results. +1. Select a server to open its configuration form. The form is pre-populated with the server's configuration from the registry. Fill in any required fields, such as API keys or tokens. +1. Press Ctrl+S to save. The server is added to your `mcp-config.json` and started immediately. + + ## Managing MCP servers -You can manage your configured MCP servers using the following `/mcp` commands in {% data variables.copilot.copilot_cli_short %}. +You can manage your configured MCP servers using the `/mcp` commands in interactive mode or the `copilot mcp` subcommands from the terminal. + +### Using `/mcp` commands in interactive mode * **List configured MCP servers:** Use the command `/mcp show`. This displays all configured MCP servers and their current status. @@ -96,6 +176,34 @@ You can manage your configured MCP servers using the following `/mcp` commands i * **Enable a previously disabled server:** Use the command `/mcp enable SERVER-NAME`. +### Using `copilot mcp` subcommands from the terminal + +You can also manage MCP servers from the terminal without entering interactive mode. + +* **List all configured servers:** + + ```shell copy + copilot mcp list + ``` + + Lists servers from all configuration sources (user, workspace, and plugin). Add `--json` for JSON output. + +* **View server details:** + + ```shell copy + copilot mcp get SERVER-NAME + ``` + + Shows a server's type, status, and available tools. Add `--json` for JSON output. + +* **Remove a server:** + + ```shell copy + copilot mcp remove SERVER-NAME + ``` + + Removes the server from the user configuration. + ## Using MCP servers Once you have added an MCP server, {% data variables.product.prodname_copilot_short %} can automatically use the tools it provides when relevant to your prompt. You can also directly reference an MCP server and specific tools in a prompt to ensure they are used. diff --git a/content/copilot/how-tos/troubleshoot-copilot/index.md b/content/copilot/how-tos/troubleshoot-copilot/index.md index 99f43f2f4857..0db17c1bcf70 100644 --- a/content/copilot/how-tos/troubleshoot-copilot/index.md +++ b/content/copilot/how-tos/troubleshoot-copilot/index.md @@ -11,6 +11,7 @@ children: - /troubleshoot-firewall-settings - /troubleshoot-network-errors - /troubleshoot-spark + - /troubleshoot-copilot-slowness redirect_from: - /copilot/troubleshooting-github-copilot - /copilot/how-tos/troubleshoot diff --git a/content/copilot/how-tos/troubleshoot-copilot/troubleshoot-copilot-slowness.md b/content/copilot/how-tos/troubleshoot-copilot/troubleshoot-copilot-slowness.md new file mode 100644 index 000000000000..61a8fcde9213 --- /dev/null +++ b/content/copilot/how-tos/troubleshoot-copilot/troubleshoot-copilot-slowness.md @@ -0,0 +1,74 @@ +--- +title: Troubleshooting slow responses from GitHub Copilot +intro: Troubleshooting help for slow responses from {% data variables.product.prodname_copilot %}. +allowTitleToDifferFromFilename: true +versions: + feature: copilot +shortTitle: Troubleshoot slow responses +redirect_from: + - /copilot/troubleshooting-github-copilot/troubleshooting-copilot-slowness + - /copilot/how-tos/troubleshoot/troubleshooting-copilot-slowness + - /copilot/how-tos/troubleshoot/troubleshoot-copilot-slowness +contentType: how-tos +category: + - Troubleshooting Copilot +--- + +## About the problem + +If {% data variables.product.prodname_copilot %} is responding more slowly than expected, the problem may be related to network conditions, local system performance, editor configuration, or connectivity restrictions such as proxies or firewalls. Because {% data variables.product.prodname_copilot_short %} relies on remote services to generate responses, issues that affect communication with {% data variables.product.github %} services can reduce responsiveness or cause delays. The troubleshooting steps below can help you determine whether the problem is caused by your environment or by a broader service issue. + +If {% data variables.product.prodname_copilot_short %} is responding slowly, work through the following troubleshooting steps. + +## Check your internet connection + +Make sure you have a stable, high-speed internet connection. Slow or inconsistent connectivity can increase latency and affect how quickly {% data variables.product.prodname_copilot_short %} returns responses. + +## Check the GitHub status page + +Visit the [GitHub status page](https://www.githubstatus.com/) to confirm whether there is an ongoing incident affecting {% data variables.product.prodname_copilot_short %} or related GitHub services. + +## Update your editor and {% data variables.product.prodname_copilot_short %} extension + +Make sure your editor and the {% data variables.product.prodname_copilot_short %} extension or plugin are up to date. After updating, restart your editor. + +## Check for extension conflicts + +Temporarily disable other extensions or plugins, especially ones related to AI coding assistants, linting, formatting, or code analysis. Conflicts between extensions can sometimes affect editor responsiveness and make {% data variables.product.prodname_copilot_short %} appear slow. + +## Try a smaller or simpler file + +{% data variables.product.prodname_copilot_short %} may respond more slowly in very large files or in projects with high complexity. Test whether performance improves in a smaller file or after splitting large files into smaller units. + +## Test in a new project or workspace + +Open a new minimal project or workspace and test {% data variables.product.prodname_copilot_short %} there. If response times improve, the issue may be related to the size, dependencies, or configuration of your main project. + +## Review system resource usage + +Check CPU and memory usage on your machine. High system load or limited available resources can slow down your editor and affect how quickly {% data variables.product.prodname_copilot_short %} responds. + +## Check proxy, VPN, and firewall settings + +If you use a proxy, VPN, firewall, or security software that inspects web traffic, verify that it is not blocking or interfering with connections required by {% data variables.product.prodname_copilot_short %}. If you work behind a corporate proxy or firewall, you may need to review your organization's network configuration and make sure to follow [AUTOTITLE](/copilot/how-tos/troubleshoot-copilot/troubleshoot-firewall-settings). + +## Review logs for errors or timeouts + +Check your editor logs for errors, timeouts, or connectivity problems. + + * In **Visual Studio Code**, open the **Output** panel and select **GitHub Copilot** from the dropdown. + * In **JetBrains IDEs**, open the logs from the **Help** menu. + +For more information, see [AUTOTITLE](/copilot/how-tos/troubleshoot-copilot/view-logs?tool=vscode#viewing-and-collecting-log-files). Save any relevant logs if you need to report the problem. + +## Try a different network or device + +If possible, test {% data variables.product.prodname_copilot_short %} on a different network or another device. This can help determine whether the issue is specific to your current environment. + +## Check GitHub Docs and known issues + +Review [AUTOTITLE](/copilot/how-tos/troubleshoot-copilot/troubleshoot-common-issues), similar reports, or environment-specific guidance. + +## Contact GitHub Support with diagnostic details + +If the problem persists, collect relevant diagnostic information before contacting GitHub Support. Include your editor and {% data variables.product.prodname_copilot_short %} extension or plugin versions, steps to reproduce the problem, example files if available, and any related log messages or errors. diff --git a/content/copilot/reference/copilot-billing/models-and-pricing.md b/content/copilot/reference/copilot-billing/models-and-pricing.md index 79393e32e839..87b5c0f23e7b 100644 --- a/content/copilot/reference/copilot-billing/models-and-pricing.md +++ b/content/copilot/reference/copilot-billing/models-and-pricing.md @@ -43,6 +43,8 @@ All prices are **per 1 million tokens**. Anthropic models include a cache write cost in addition to cached input. +{% data reusables.copilot.model-fable-disabled %} + | Model | Release status | Category | Input | Cached input | Cache write | Output | | --- | --- | --- | ---: | ---: | ---: | ---: | | {% for entry in tables.copilot.models-and-pricing %}{% if entry.provider == "anthropic" %} | diff --git a/content/copilot/reference/copilot-cli-reference/cli-command-reference.md b/content/copilot/reference/copilot-cli-reference/cli-command-reference.md index 10f3257a8f8a..78cecac225e3 100644 --- a/content/copilot/reference/copilot-cli-reference/cli-command-reference.md +++ b/content/copilot/reference/copilot-cli-reference/cli-command-reference.md @@ -196,6 +196,7 @@ Holding or accelerates scrolling after the first 1 | Command | Purpose | |-----------------------------------------------------|---------| | `/add-dir PATH` | Add a directory to the allowed list for file access. | +| `/after [DELAY PROMPT]`, `/after` | Schedule a non-recurring prompt, skill, or schedulable slash command for the current session (for example, `/after 30m remind me the time` or `/after 1h /chronicle standup`). With no arguments the schedule manager is displayed. {% data reusables.copilot.experimental %} | | `/agent` | Browse and select from available agents (if any). See [AUTOTITLE](/copilot/concepts/agents/copilot-cli/about-custom-agents). | | `/ask QUESTION` | Ask a quick side question without adding to the conversation history. {% data reusables.copilot.experimental %} | | `/allow-all [on\|off\|show]`, `/yolo [on\|off\|show]` | Enable all permissions (tools, paths, and URLs). | @@ -209,8 +210,9 @@ Holding or accelerates scrolling after the first 1 | `/cwd`, `/cd [PATH]` | Change the working directory or display the current directory. | | `/delegate [PROMPT]` | Delegate changes to a remote repository with an AI-generated pull request. See [AUTOTITLE](/copilot/how-tos/copilot-cli/use-copilot-cli/delegate-tasks-to-cca). | | `/diff` | Review changes in the current directory; auto-switches to branch diff when the working tree is clean (experimental). | -| `/downgrade ` | Download and restart into a specific CLI version. Available for team accounts. | +| `/downgrade VERSION` | Download and restart into a specific CLI version. Available for team accounts. | | `/env` | Show loaded environment details (instructions, MCP servers, skills, agents, plugins, LSPs, hooks, extensions). | +| `/every [INTERVAL PROMPT]`, `/every` | Schedule a recurring prompt, skill, or schedulable slash command for the current session (for example, `/every 1h run tests` or `/every 1d /chronicle standup`). With no arguments the schedule manager is displayed. {% data reusables.copilot.experimental %} | | `/exit`, `/quit` | Exit the CLI. | | `/extensions [manage\|mode]`, `/extension` | Manage CLI extensions. | | `/experimental [on\|off\|show]` | Toggle, set, or show experimental features. | @@ -255,7 +257,7 @@ Holding or accelerates scrolling after the first 1 | `/usage` | Display session usage metrics and statistics. | | `/user [show\|list\|switch]` | Manage the current {% data variables.product.github %} user. | | `/version` | Display version information and check for updates. | -| `/worktree [branch]`, `/move [branch]` | Create a new git worktree and switch to it, moving any uncommitted changes along. If you omit the branch name, a name is auto-generated from the conversation. Requires a git repository. {% data reusables.copilot.experimental %} | +| `/worktree [branch]`, `/move [branch]` | Create a new Git worktree and switch to it, moving any uncommitted changes along. If you omit the branch name, a name is auto-generated from the conversation. Requires a Git repository. {% data reusables.copilot.experimental %} | For a complete list of available slash commands enter `/help` in the CLI's interactive interface. @@ -311,7 +313,7 @@ For a complete list of available slash commands enter `/help` in the CLI's inter | `--output-format=FORMAT` | FORMAT can be `text` (default) or `json` (outputs JSONL: one JSON object per line). | | `-p PROMPT`, `--prompt=PROMPT` | Execute a prompt programmatically (exits after completion). See [AUTOTITLE](/copilot/how-tos/copilot-cli/automate-copilot-cli/run-cli-programmatically). | | `--plan` | Start in plan mode. Shorthand for `--mode plan`. Cannot be combined with `--mode` or `--autopilot`. | -| `--plain-diff` | Disable rich diff rendering (syntax highlighting via the diff tool specified by your git config). | +| `--plain-diff` | Disable rich diff rendering (syntax highlighting via the diff tool specified by your Git config). | | `--plugin-dir=DIRECTORY` | Load a plugin from a local directory (can be used multiple times). | | `--remote` | Enable remote access to this session from {% data variables.product.prodname_dotcom_the_website %} and {% data variables.product.prodname_mobile %}. See [AUTOTITLE](/copilot/how-tos/copilot-cli/use-copilot-cli/steer-remotely). | | `-r`, `--resume[=VALUE]` | Resume a previous interactive session by choosing from a list. Optionally specify a session ID, ID prefix, or session name. Name matching is exact and case-insensitive; falls back to the auto-generated summary when no explicit name matches. | @@ -426,6 +428,7 @@ copilot --allow-tool='MyMCP' | `COPILOT_ALLOW_ALL` | Set to `true` to allow all permissions automatically (equivalent to `--allow-all`). | | `COPILOT_AUTO_UPDATE` | Set to `false` to disable automatic updates. | | `COPILOT_CACHE_HOME` | Override the cache directory (used for marketplace caches, auto-update packages, and other ephemeral data). See [AUTOTITLE](/copilot/reference/copilot-cli-reference/cli-config-dir-reference#changing-the-location-of-the-configuration-directory) for platform defaults. | +| `COPILOT_COMPUTER_USE_LINUX` | Set to opt in to the `computer-use` MCP server on Linux distributions that support it. The `computer-use` server is not available on Alpine Linux (musl libc). | | `COPILOT_CUSTOM_INSTRUCTIONS_DIRS` | Comma-separated list of additional directories for custom instructions. | | `COPILOT_EDITOR` | Editor command for interactive editing (checked after `$VISUAL` and `$EDITOR`). Defaults to `vi` if none are set. | | `COPILOT_ENABLE_HTTP2` | Set to `1` or `true` to opt into HTTP/2 transport. HTTP/1.1 is the default. | @@ -615,6 +618,7 @@ The CLI includes built-in MCP servers that are available without additional setu | `playwright` | Browser automation: navigate, click, type, screenshot, and form handling. | | `fetch` | HTTP requests via the `fetch` tool. | | `time` | Time utilities: `get_current_time` and `convert_time`. | +| `computer-use` | Screen capture and mouse/keyboard automation. Not available on Alpine Linux (musl libc). Set `COPILOT_COMPUTER_USE_LINUX` to opt in on other Linux distributions where it is available. | Use `--disable-builtin-mcps` to disable all built-in servers, or `--disable-mcp-server SERVER-NAME` to disable a specific one. @@ -764,7 +768,7 @@ Custom agents are specialized AI agents defined in Markdown files. The filename | User | `~/.copilot/agents/` | | Plugin | `/agents/` | -Project-level agents take precedence over user-level agents. Plugin agents have the lowest priority. +For project-scoped agents, the CLI walks upward from your current working directory to the Git root, loading `.github/agents/` and `.claude/agents/` directories at each ancestor level. This means each package or subdirectory in a monorepo can contribute its own agents. When multiple `.github/agents/` directories exist in the path, all are loaded, with the deepest directory taking highest priority. The `.github/agents/` convention takes precedence over `.claude/agents/` at the same level. User-level agents have lower priority than project-level agents. Plugin agents have the lowest priority. ### Subagent limits @@ -797,7 +801,7 @@ When the full dialog is shown, you can also choose from these options: | This location | Until manually cleared | Saved to disk per location | | Always | Permanent | Config file | -The **This location** option appears when the CLI can determine a location key (git root or current directory). It persists the approval to disk so the same permission is automatically granted the next time you work in that directory without prompting again. +The **This location** option appears when the CLI can determine a location key (Git root or current directory). It persists the approval to disk so the same permission is automatically granted the next time you work in that directory without prompting again. Use `/permissions reset` to clear in-memory approvals for the current session. diff --git a/content/copilot/reference/copilot-usage-metrics/copilot-usage-metrics.md b/content/copilot/reference/copilot-usage-metrics/copilot-usage-metrics.md index df7f243e639f..32c5fb359d98 100644 --- a/content/copilot/reference/copilot-usage-metrics/copilot-usage-metrics.md +++ b/content/copilot/reference/copilot-usage-metrics/copilot-usage-metrics.md @@ -17,7 +17,7 @@ contentType: reference The {% data variables.product.prodname_copilot_short %} usage metrics dashboard and APIs display and export data using a consistent set of fields. This reference lists all available metrics and describes how to interpret their values in both dashboard visuals and NDJSON or API exports. * The {% data variables.product.prodname_copilot_short %} usage metrics dashboards are available at the **enterprise** and **organization** level. -* The {% data variables.product.prodname_copilot_short %} usage metrics APIs support **enterprise-, organization-, and user-level** records. +* The {% data variables.product.prodname_copilot_short %} usage metrics APIs return reports scoped to the **enterprise**, **organization**, or **individual user** level, in different shapes depending on scope and granularity. * Team-level metrics are not pre-aggregated; you construct them by joining the user-teams report with the per-user usage metrics report. See [AUTOTITLE](/copilot/reference/copilot-usage-metrics/team-level-metrics). For guidance on how to read and interpret these metrics, see [AUTOTITLE](/copilot/concepts/copilot-metrics). @@ -63,100 +63,248 @@ These metrics appear in the code generation dashboard and provide a breakdown of ## API and export fields -These fields appear in the exported NDJSON reports and in the {% data variables.product.prodname_copilot_short %} usage metrics APIs. They provide daily records at the enterprise, organization, or user scope, depending on the metric. +These fields appear in the exported NDJSON reports and in the {% data variables.product.prodname_copilot_short %} usage metrics APIs. Most tables below list the field name, its JSON type, whether the value can be null, and a description. -For example schemas of the data returned by the APIs, see [AUTOTITLE](/copilot/reference/copilot-usage-metrics/example-schema). +Reports come in different shapes depending on their scope and granularity, so the fields available in a record depend on which report it comes from: -| Field | Description | -|:--|:--| -| `agent_edit` | Captures lines added and deleted when {% data variables.product.prodname_copilot_short %} (in agent and edit mode) writes changes directly into your files in the IDE. `agent_edit` is not included in suggestion-based metrics and may not populate suggestion-style fields (for example, `user_initiated_interaction_count`). Counts edits from custom agents as well. | -| `report_start_day` / `report_end_day` | Start and end dates for the 28-day reporting period. | -| `day` | Calendar day this record represents. | -| `enterprise_id` | Unique ID of the enterprise. | -| `organization_id` (API only) | Unique ID of the organization. | -| `user_id` / `user_login` | Unique identifier and {% data variables.product.github %} username for the user. | -| `user_initiated_interaction_count` | Number of explicit prompts sent to {% data variables.product.prodname_copilot_short %}.

Only counts messages or prompts actively sent to the model. Does **not** include opening the chat panel, switching modes (for example, ask, edit, plan, or agent), using keyboard shortcuts to open the inline UI, or making configuration changes. | -| `chat_panel_agent_mode` | Captures user-initiated interactions in the chat panel with agent mode selected. | -| `chat_panel_ask_mode` | Captures user-initiated interactions in the chat panel with ask mode selected. | -| `chat_panel_custom_mode` | Captures user-initiated interactions in the chat panel with a custom agent selected. | -| `chat_panel_edit_mode` | Captures user-initiated interactions in the chat panel with edit mode selected. | -| `chat_panel_plan_mode` | Captures user-initiated interactions in the chat panel with plan mode selected. | -| `chat_panel_unknown_mode` | Captures user-initiated interactions in the chat panel where the mode is unknown. | -| `code_generation_activity_count` | Number of distinct {% data variables.product.prodname_copilot_short %} output events generated.

**Includes:** All generated content, including comments and docstrings.
**Multiple blocks:** Each distinct code block from a single user prompt counts as a separate generation.
**Note:** This metric is not directly comparable to `user_initiated_interaction_count`, since one prompt can produce multiple generations. | -| `code_acceptance_activity_count` | Number of suggestions or code blocks accepted by users.

**Counts:** All built-in accept actions, such as “apply to file,” “insert at cursor,” “insert into terminal,” and use of the **Copy** button.
**Does not count:** Manual OS clipboard actions (for example, Ctrl+C).
**Granularity:** Each acceptance action increments the count once, regardless of how many code blocks were generated by the initial prompt. | -| `loc_suggested_to_add_sum` | Lines of code {% data variables.product.prodname_copilot_short %} suggested to add (completions, inline chat, chat panel, etc.; **excludes** agent edits). | -| `loc_suggested_to_delete_sum` | Lines of code {% data variables.product.prodname_copilot_short %} suggested to delete (future support planned). | -| `loc_added_sum` | Lines of code actually added to the editor (accepted completions, applied code blocks, agent/edit mode). | -| `loc_deleted_sum` | Lines of code deleted from the editor (currently from agent edits). | -| `totals_by_ide` | Breakdown of metrics by IDE used. | -| `totals_by_feature` | Breakdown of metrics by {% data variables.product.prodname_copilot_short %} feature (e.g., inline chat, chat panel). | -| `totals_by_language_feature` | Breakdown combining language and feature dimensions. | -| `totals_by_model_feature` / `totals_by_language_model` | Model-specific breakdowns for chat activity (not completions). When {% data variables.copilot.copilot_auto_model_selection_short %} is enabled, activity is attributed to the actual model used rather than appearing as `Auto`. | -| `last_known_ide_version` / `last_known_plugin_version` | The most recent IDE and {% data variables.copilot.copilot_chat_short %} extension version detected for each user. | -| `daily_active_cli_users` | Number of unique users in the enterprise or organization who used {% data variables.product.prodname_copilot_short %} via the CLI on a given day. This field is **independent** of IDE active user counts and is **not** included in IDE-based active user definitions. Omitted for enterprises or organizations with no CLI usage on that day. | -| `daily_active_copilot_code_review_users` | Number of unique users who actively used {% data variables.copilot.copilot_code-review_short %} on a given day. Active usage means manually requesting a review or applying a suggestion. When a user has both active and passive signals in the same period, they are counted as active only. | -| `daily_passive_copilot_code_review_users` | Number of unique users who had {% data variables.copilot.copilot_code-review_short %} automatically assigned to review their pull request on a given day, with no active engagement. | -| `weekly_active_copilot_code_review_users` | Number of unique users who actively used {% data variables.copilot.copilot_code-review_short %} during a trailing seven-day window. When a user has both active and passive signals in the same period, they are counted as active only. | -| `weekly_passive_copilot_code_review_users` | Number of unique users who had {% data variables.copilot.copilot_code-review_short %} automatically assigned to review their pull request during a trailing seven-day window, with no active engagement. | -| `monthly_active_copilot_code_review_users` | Number of unique users who actively used {% data variables.copilot.copilot_code-review_short %} during a trailing 28-day window. When a user has both active and passive signals in the same period, they are counted as active only. | -| `monthly_passive_copilot_code_review_users` | Number of unique users who had {% data variables.copilot.copilot_code-review_short %} automatically assigned to review their pull request during a trailing 28-day window, with no active engagement. | -| `totals_by_cli` | Breakdown of CLI-specific metrics for the enterprise, organization, or user on a given day. Independent of IDE metrics—CLI usage is **not** reflected in other fields such as `totals_by_ide` or `totals_by_feature`. Omitted when there's no CLI usage on that day. See [{% data variables.copilot.copilot_cli_short %} metrics fields](#copilot-cli-metrics-fields-api-only) below. | -| `used_cli` | Captures whether the user has used {% data variables.copilot.copilot_cli_short %} that day. | -| `used_agent` | Captures whether the user has used agent mode in the IDE that day. Does not include {% data variables.copilot.copilot_code-review_short %} activity, which is captured separately in `used_copilot_code_review_active` and `used_copilot_code_review_passive`. | -| `used_chat` | Captures whether the user has used IDE chat that day. | -| `used_copilot_code_review_active` | Captures whether the user actively engaged with {% data variables.copilot.copilot_code-review_short %} that day. A user is considered active if they manually requested a {% data variables.product.prodname_copilot_short %} review, or applied a {% data variables.product.prodname_copilot_short %} review suggestion. | -| `used_copilot_code_review_passive` | Captures whether the user had {% data variables.product.prodname_copilot_short %} automatically assigned to review their pull request that day, without actively engaging with the review. | - -### {% data variables.copilot.copilot_cli_short %} metrics fields (API only) - -The `totals_by_cli` object contains the following nested fields when CLI usage is present. - -| Field | Description | -|:--|:--| -| `totals_by_cli.session_count` | Number of distinct CLI sessions initiated on this day. | -| `totals_by_cli.request_count` | Total number of requests made to {% data variables.product.prodname_copilot_short %} via the CLI on this day, including both user-initiated prompts and automated agentic follow-up calls. | -| `totals_by_cli.token_usage.output_tokens_sum` | Total number of output tokens generated across all CLI requests on this day. | -| `totals_by_cli.token_usage.prompt_tokens_sum` | Total number of prompt tokens sent across all CLI requests on this day. | -| `totals_by_cli.token_usage.avg_tokens_per_request` | Average number of **output** and **prompt** tokens per CLI request, computed as `(output_tokens_sum + prompt_tokens_sum) ÷ request_count`.| -| `totals_by_cli.prompt_count` | Total number of user prompts, commands, or queries executed within a session. | -| `totals_by_cli.last_known_cli_version` | Most recent {% data variables.copilot.copilot_cli_short %} version detected for the user that day. | +* **Per-user reports** (`*-users-1-day` and `*-users-28-day`) contain one record per user, including `user_id`, `user_login`, the `used_*` indicators, and `ai_adoption_phase`. They do not contain active-user counts, `pull_requests`, or `totals_by_ai_adoption_phase`. +* **Aggregated reports** (`enterprise-1-day` and `org-1-day`) contain one aggregated record per enterprise or organization, including active-user counts, `pull_requests`, and `totals_by_ai_adoption_phase`. They do not contain `user_id`, `user_login`, or the `used_*` indicators. +* **28-day reports** (`enterprise-28-day` and `org-28-day`) wrap an array of daily aggregated records in a `day_totals` field, with the reporting window at the top level. +* **User-teams reports** (`*-user-teams-1-day`) map users to the teams they belong to, so you can construct team-level metrics. -### Pull request activity fields (API only) +Organization-scope reports also include `organization_id` alongside `enterprise_id`. For example schemas of the data returned by the APIs, see [AUTOTITLE](/copilot/reference/copilot-usage-metrics/example-schema). -> [!IMPORTANT] -> Organization- and enterprise-level reports may show different totals due to differences in user deduplication and attribution timing. For guidance on interpreting pull request metrics across scopes, see [AUTOTITLE](/copilot/concepts/copilot-usage-metrics/copilot-metrics#interpreting-pull-request-lifecycle-metrics-across-scopes). +The **Type** column uses JSON Schema types: `string`, `integer`, `number`, `boolean`, `array`, and `object`. The **Nullable** column indicates whether a field's value can be `null` or absent from a record where it would otherwise apply. Arrays are always present but can be empty (`[]`), so they are not nullable. -These fields capture daily pull request creation, review, merge, and suggestion activity at the enterprise or organization scope, including activity performed by {% data variables.product.prodname_copilot_short %}. +### Report identification and partition fields -| Field | Description | -|:--|:--| -| `pull_requests.total_created` | Total number of pull requests created on this specific day.

Creation is a one-time event. Each pull request is counted only on the day it is created. | -| `pull_requests.total_reviewed` | Total number of pull requests reviewed on this specific day.

The same pull request may be counted on multiple days if it receives reviews on multiple days. Within a single day, each pull request is counted once, even if multiple review actions occur. | -| `pull_requests.total_merged` | Total number of pull requests merged on this specific day.

Merging is a one-time event. Each pull request is counted only on the day it is merged. | -| `pull_requests.median_minutes_to_merge` | Median time, in minutes, between pull request creation and merge for pull requests merged on this specific day.

Median is used to reduce the impact of outliers from unusually long-running pull requests. | -| `pull_requests.total_suggestions` | Total number of pull request review suggestions generated on this specific day, regardless of author. | -| `pull_requests.total_applied_suggestions` | Total number of pull request review suggestions that were applied on this specific day, regardless of author. | -| `pull_requests.total_created_by_copilot` | Number of pull requests created by {% data variables.product.prodname_copilot_short %} on this specific day. | -| `pull_requests.total_reviewed_by_copilot` | Number of pull requests reviewed by {% data variables.product.prodname_copilot_short %} on this specific day.

A pull request may be counted on multiple days if {% data variables.product.prodname_copilot_short %} reviews it on multiple days. | -| `pull_requests.total_merged_created_by_copilot` | Number of pull requests created by {% data variables.product.prodname_copilot_short %} that were merged on this specific day. Each pull request is counted only on the day it is merged. | -| `pull_requests.total_merged_reviewed_by_copilot` | Number of pull requests that were both merged and reviewed by {% data variables.copilot.copilot_code-review_short %} during the reporting period. | -| `pull_requests.median_minutes_to_merge_copilot_authored` | Median time, in minutes, between pull request creation and merge for pull requests created by {% data variables.product.prodname_copilot_short %} and merged on this specific day. | -| `pull_requests.median_minutes_to_merge_copilot_reviewed` | Median time, in minutes, between pull request creation and merge, calculated only for pull requests reviewed by {% data variables.copilot.copilot_code-review_short %}. | -| `pull_requests.total_copilot_suggestions` | Number of pull request review suggestions generated by {% data variables.product.prodname_copilot_short %} on this specific day. | -| `pull_requests.total_copilot_applied_suggestions` | Number of pull request review suggestions generated by {% data variables.product.prodname_copilot_short %} that were applied on this specific day. | -| `pull_requests.copilot_suggestions_by_comment_type` | Aggregated counts of {% data variables.product.prodname_copilot_short %} code review suggestions, broken down by the comment type {% data variables.product.prodname_copilot_short %} assigned (for example, `security` or `bug_risk`). Each entry includes `comment_type`, `total_copilot_suggestions`, and `total_copilot_applied_suggestions`. Not available at the repository level. | - -### User-teams fields (API only) +These fields identify the scope, date, and (for exports) partition of each record. The exact set present depends on the report shape. + +| Field | Type | Nullable | Description | +|:--|:--|:--|:--| +| `day` | `string` | No | Calendar day this record represents, in `YYYY-MM-DD` format. In 28-day reports, `day` appears within each `day_totals` entry rather than at the top level. | +| `enterprise_id` | `string` | No | Unique ID of the enterprise. Included in both enterprise- and organization-scope reports. | +| `organization_id` | `string` | Yes | Unique ID of the organization. Included in organization-scope reports only; omitted from enterprise-scope reports. | +| `etl_id` / `day_partition` | `string` | No | Partition fields used for housekeeping. Included in exported NDJSON files and returned by the usage metrics APIs. | +| `entity_id_partition` | `integer` | No | Entity partition used for housekeeping. Included in exported NDJSON files and returned by the usage metrics APIs. | + +### Per-user report fields + +Per-user reports contain one record per user for the reporting period. The 28-day per-user report also includes `report_start_day` and `report_end_day` to mark the reporting window. + +| Field | Type | Nullable | Description | +|:--|:--|:--|:--| +| `user_id` | `integer` | No | Unique identifier for the user. | +| `user_login` | `string` | No | {% data variables.product.github %} username for the user. | +| `user_initiated_interaction_count` | `integer` | No | Number of explicit prompts sent to {% data variables.product.prodname_copilot_short %}.

Only counts messages or prompts actively sent to the model. Does **not** include opening the chat panel, switching modes (for example, ask, edit, plan, or agent), using keyboard shortcuts to open the inline UI, or making configuration changes. | +| `code_generation_activity_count` | `integer` | No | Number of distinct {% data variables.product.prodname_copilot_short %} output events generated.

**Includes:** All generated content, including comments and docstrings.
**Multiple blocks:** Each distinct code block from a single user prompt counts as a separate generation.
**Note:** This metric is not directly comparable to `user_initiated_interaction_count`, since one prompt can produce multiple generations. | +| `code_acceptance_activity_count` | `integer` | No | Number of suggestions or code blocks accepted by users.

**Counts:** All built-in accept actions, such as “apply to file,” “insert at cursor,” “insert into terminal,” and use of the **Copy** button.
**Does not count:** Manual OS clipboard actions (for example, Ctrl+C).
**Granularity:** Each acceptance action increments the count once, regardless of how many code blocks were generated by the initial prompt. | +| `loc_suggested_to_add_sum` | `integer` | No | Lines of code {% data variables.product.prodname_copilot_short %} suggested to add (completions, inline chat, chat panel, and so on; **excludes** agent edits). | +| `loc_suggested_to_delete_sum` | `integer` | No | Lines of code {% data variables.product.prodname_copilot_short %} suggested to delete (future support planned). | +| `loc_added_sum` | `integer` | No | Lines of code actually added to the editor (accepted completions, applied code blocks, agent and edit mode). | +| `loc_deleted_sum` | `integer` | No | Lines of code deleted from the editor (currently from agent edits). | +| `used_agent` | `boolean` | No | Whether the user used agent mode in the IDE that day. Does not include {% data variables.copilot.copilot_code-review_short %} activity, which is captured separately in `used_copilot_code_review_active` and `used_copilot_code_review_passive`. | +| `used_chat` | `boolean` | No | Whether the user used IDE chat that day. | +| `used_cli` | `boolean` | No | Whether the user used {% data variables.copilot.copilot_cli_short %} that day. | +| `used_copilot_coding_agent` | `boolean` | No | Whether the user used {% data variables.copilot.copilot_cloud_agent %} (previously Copilot coding agent) that day. | +| `used_copilot_cloud_agent` | `boolean` | No | Whether the user used {% data variables.copilot.copilot_cloud_agent %} that day. Carries the same value as `used_copilot_coding_agent`; both names are retained for backward compatibility. | +| `used_copilot_code_review_active` | `boolean` | Yes | Whether the user actively engaged with {% data variables.copilot.copilot_code-review_short %} that day. A user is considered active if they manually requested a {% data variables.product.prodname_copilot_short %} review, or applied a {% data variables.product.prodname_copilot_short %} review suggestion. Null when there is no {% data variables.copilot.copilot_code-review_short %} signal for the user that day. | +| `used_copilot_code_review_passive` | `boolean` | Yes | Whether the user had {% data variables.product.prodname_copilot_short %} automatically assigned to review their pull request that day, without actively engaging with the review. Null when there is no {% data variables.copilot.copilot_code-review_short %} signal for the user that day. | +| `ai_adoption_phase` | `object` | No | The user's AI adoption phase for the day. Always present; defaults to the "No Cohort" phase. See [AI adoption phase fields](#ai-adoption-phase-fields). | +| `totals_by_cli` | `object` | Yes | CLI-specific metrics for the user. Omitted when the user had no {% data variables.copilot.copilot_cli_short %} usage that day. See [{% data variables.copilot.copilot_cli_short %} metrics fields](#copilot-cli-metrics-fields). | +| `totals_by_ide` | `array` | No | Per-IDE breakdown of the user's activity. See [Activity breakdown objects](#activity-breakdown-objects). | +| `totals_by_feature` | `array` | No | Per-feature breakdown of the user's activity. See [Activity breakdown objects](#activity-breakdown-objects). | +| `totals_by_language_feature` | `array` | No | Breakdown combining language and feature dimensions. See [Activity breakdown objects](#activity-breakdown-objects). | +| `totals_by_language_model` | `array` | No | Breakdown combining language and model dimensions, for chat activity. See [Activity breakdown objects](#activity-breakdown-objects). | +| `totals_by_model_feature` | `array` | No | Breakdown combining model and feature dimensions, for chat activity. See [Activity breakdown objects](#activity-breakdown-objects). | + +### Aggregated enterprise and organization report fields + +Aggregated reports contain one record per enterprise or organization, summarizing all users for the day. The following tables list the active-user counts, then the activity totals and breakdowns. + +Active-user counts: + +| Field | Type | Nullable | Description | +|:--|:--|:--|:--| +| `daily_active_users` | `integer` | No | Number of unique users who used {% data variables.product.prodname_copilot_short %} on a given day. | +| `weekly_active_users` | `integer` | No | Number of unique users who used {% data variables.product.prodname_copilot_short %} during a trailing seven-day window. | +| `monthly_active_users` | `integer` | No | Number of unique users who used {% data variables.product.prodname_copilot_short %} during a trailing 28-day window. | +| `monthly_active_chat_users` | `integer` | No | Number of unique users who used chat during a trailing 28-day window. | +| `monthly_active_agent_users` | `integer` | No | Number of unique users who used agent mode during a trailing 28-day window. | +| `daily_active_copilot_cloud_agent_users` | `integer` | No | Number of unique users who used {% data variables.copilot.copilot_cloud_agent %} on a given day. | +| `weekly_active_copilot_cloud_agent_users` | `integer` | No | Number of unique users who used {% data variables.copilot.copilot_cloud_agent %} during a trailing seven-day window. | +| `monthly_active_copilot_cloud_agent_users` | `integer` | No | Number of unique users who used {% data variables.copilot.copilot_cloud_agent %} during a trailing 28-day window. | +| `daily_active_copilot_code_review_users` | `integer` | No | Number of unique users who actively used {% data variables.copilot.copilot_code-review_short %} on a given day. Active usage means manually requesting a review or applying a suggestion. When a user has both active and passive signals in the same period, they are counted as active only. | +| `weekly_active_copilot_code_review_users` | `integer` | No | Number of unique users who actively used {% data variables.copilot.copilot_code-review_short %} during a trailing seven-day window. When a user has both active and passive signals in the same period, they are counted as active only. | +| `monthly_active_copilot_code_review_users` | `integer` | No | Number of unique users who actively used {% data variables.copilot.copilot_code-review_short %} during a trailing 28-day window. When a user has both active and passive signals in the same period, they are counted as active only. | +| `daily_passive_copilot_code_review_users` | `integer` | No | Number of unique users who had {% data variables.copilot.copilot_code-review_short %} automatically assigned to review their pull request on a given day, with no active engagement. | +| `weekly_passive_copilot_code_review_users` | `integer` | No | Number of unique users who had {% data variables.copilot.copilot_code-review_short %} automatically assigned to review their pull request during a trailing seven-day window, with no active engagement. | +| `monthly_passive_copilot_code_review_users` | `integer` | No | Number of unique users who had {% data variables.copilot.copilot_code-review_short %} automatically assigned to review their pull request during a trailing 28-day window, with no active engagement. | +| `daily_active_cli_users` | `integer` | Yes | Number of unique users who used {% data variables.copilot.copilot_cli_short %} on a given day. This count is **independent** of IDE active-user counts and is **not** included in IDE-based active-user definitions. Omitted for enterprises or organizations with no CLI usage that day. | + +Activity totals and breakdowns: + +| Field | Type | Nullable | Description | +|:--|:--|:--|:--| +| `user_initiated_interaction_count` | `integer` | No | Total number of explicit prompts sent to {% data variables.product.prodname_copilot_short %} across all users for the day. | +| `code_generation_activity_count` | `integer` | No | Total number of distinct {% data variables.product.prodname_copilot_short %} output events generated across all users for the day. | +| `code_acceptance_activity_count` | `integer` | No | Total number of suggestions or code blocks accepted across all users for the day. | +| `loc_suggested_to_add_sum` | `integer` | No | Aggregated lines of code suggested to add for the day. Same definition as the per-user field. | +| `loc_suggested_to_delete_sum` | `integer` | No | Aggregated lines of code suggested to delete for the day. Same definition as the per-user field. | +| `loc_added_sum` | `integer` | No | Aggregated lines of code added for the day. Same definition as the per-user field. | +| `loc_deleted_sum` | `integer` | No | Aggregated lines of code deleted for the day. Same definition as the per-user field. | +| `totals_by_ide` | `array` | No | Aggregated per-IDE activity breakdown. See [Activity breakdown objects](#activity-breakdown-objects). | +| `totals_by_feature` | `array` | No | Aggregated per-feature activity breakdown. See [Activity breakdown objects](#activity-breakdown-objects). | +| `totals_by_language_feature` | `array` | No | Aggregated language-and-feature activity breakdown. See [Activity breakdown objects](#activity-breakdown-objects). | +| `totals_by_language_model` | `array` | No | Aggregated language-and-model activity breakdown. See [Activity breakdown objects](#activity-breakdown-objects). | +| `totals_by_model_feature` | `array` | No | Aggregated model-and-feature activity breakdown. See [Activity breakdown objects](#activity-breakdown-objects). | +| `totals_by_cli` | `object` | Yes | Aggregated {% data variables.copilot.copilot_cli_short %} metrics for the day. Omitted when there is no CLI usage that day. Unlike the per-user form, it does not include `last_known_cli_version`. See [{% data variables.copilot.copilot_cli_short %} metrics fields](#copilot-cli-metrics-fields). | +| `totals_by_ai_adoption_phase` | `array` | Yes | Per-phase aggregates of users and their average activity. Omitted when no adoption-phase data is available. See [AI adoption phase fields](#ai-adoption-phase-fields). | +| `pull_requests` | `object` | No | Daily pull request activity for the enterprise or organization. See [Pull request activity fields](#pull-request-activity-fields). | + +### 28-day report fields + +The 28-day reports (`enterprise-28-day` and `org-28-day`) are wrappers: they carry the reporting window at the top level and an array of daily aggregated records. + +| Field | Type | Nullable | Description | +|:--|:--|:--|:--| +| `report_start_day` | `string` | No | First calendar day of the 28-day reporting window, in `YYYY-MM-DD` format. | +| `report_end_day` | `string` | No | Last calendar day of the 28-day reporting window, in `YYYY-MM-DD` format. | +| `created_at` | `string` | No | Timestamp (ISO 8601) when the report was generated. | +| `day_totals` | `array` | No | Array of daily aggregated records. Each entry has the same fields as an aggregated 1-day report. See [Aggregated enterprise and organization report fields](#aggregated-enterprise-and-organization-report-fields). | + +### User-teams fields These fields appear in the daily user-teams report (available via REST API at the organization and enterprise scopes) and are used to construct team-level metrics by joining with the per-user usage metrics report. For the full join recipe and the endpoint URLs, see [AUTOTITLE](/copilot/reference/copilot-usage-metrics/team-level-metrics). Teams with fewer than 5 seated {% data variables.product.prodname_copilot_short %} users on a given day are excluded from the user-teams report. -| Field | Description | +| Field | Type | Nullable | Description | +|:--|:--|:--|:--| +| `user_id` | `integer` | No | Unique identifier for the user. | +| `user_login` | `string` | No | {% data variables.product.github %} username for the user. | +| `day` | `string` | No | Calendar day this record represents. | +| `organization_id` | `string` | No | Unique ID of the organization the team belongs to. Organization scope only. | +| `enterprise_id` | `string` | No | Unique ID of the enterprise the team belongs to. Enterprise scope only. The enterprise-scoped report includes both enterprise teams and business teams. | +| `team_id` | `integer` | No | Unique ID of the team the user belongs to. | +| `slug` | `string` | No | URL-friendly identifier for the team. | + +### Activity breakdown objects + +The `totals_by_*` fields are arrays of breakdown objects. The array is always present but can be empty. Within each object, the metric fields (`*_count` and `loc_*_sum`) follow the same definitions as the top-level per-user fields, and the dimension fields carry the values documented in [Breakdown dimension values](#breakdown-dimension-values). + +| Object | Dimension fields | Description | +|:--|:--|:--| +| `totals_by_ide[]` | `ide` | Breakdown by IDE. In per-user reports, each entry also includes `last_known_ide_version` and `last_known_plugin_version`. | +| `totals_by_feature[]` | `feature` | Breakdown by {% data variables.product.prodname_copilot_short %} feature (for example, inline chat or chat panel). | +| `totals_by_language_feature[]` | `language`, `feature` | Breakdown combining language and feature. Does not include `user_initiated_interaction_count`. | +| `totals_by_language_model[]` | `language`, `model` | Breakdown combining language and model, for chat activity (not completions). | +| `totals_by_model_feature[]` | `model`, `feature` | Breakdown combining model and feature, for chat activity (not completions). | + +In per-user reports, each `totals_by_ide[]` entry also reports the most recently detected IDE and {% data variables.copilot.copilot_chat_short %} extension versions for the user. + +| Field | Type | Nullable | Description | +|:--|:--|:--|:--| +| `last_known_ide_version` | `object` | Yes | Most recent IDE version detected for the user, as `{ ide_version, sampled_at }`. Omitted for aggregated breakdown rows, such as the capped "others" IDE bucket. | +| `last_known_ide_version.ide_version` | `string` | No | IDE version string. Present when `last_known_ide_version` is present. | +| `last_known_ide_version.sampled_at` | `string` | Yes | Timestamp (ISO 8601) when the version was sampled. | +| `last_known_plugin_version` | `object` | Yes | Most recent {% data variables.product.prodname_copilot_short %} extension detected for the user, as `{ plugin, plugin_version, sampled_at }`. Omitted for aggregated breakdown rows. | +| `last_known_plugin_version.plugin` | `string` | No | Extension name (for example, `copilot` or `copilot-chat`). Present when `last_known_plugin_version` is present. | +| `last_known_plugin_version.plugin_version` | `string` | No | Extension version string. Present when `last_known_plugin_version` is present. | +| `last_known_plugin_version.sampled_at` | `string` | Yes | Timestamp (ISO 8601) when the version was sampled. | + +### {% data variables.copilot.copilot_cli_short %} metrics fields + +The `totals_by_cli` object contains the following nested fields when {% data variables.copilot.copilot_cli_short %} usage is present; the object is omitted when there is no CLI usage. CLI usage is independent of IDE metrics—it is **not** reflected in fields such as `totals_by_ide` or `totals_by_feature`. The `last_known_cli_version` object appears in per-user reports only. + +| Field | Type | Nullable | Description | +|:--|:--|:--|:--| +| `totals_by_cli.session_count` | `integer` | No | Number of distinct CLI sessions initiated on this day. | +| `totals_by_cli.request_count` | `integer` | No | Total number of requests made to {% data variables.product.prodname_copilot_short %} via the CLI on this day, including both user-initiated prompts and automated agentic follow-up calls. | +| `totals_by_cli.prompt_count` | `integer` | No | Total number of user prompts, commands, or queries executed within a session. | +| `totals_by_cli.token_usage.output_tokens_sum` | `integer` | No | Total number of output tokens generated across all CLI requests on this day. | +| `totals_by_cli.token_usage.prompt_tokens_sum` | `integer` | No | Total number of prompt tokens sent across all CLI requests on this day. | +| `totals_by_cli.token_usage.avg_tokens_per_request` | `number` | Yes | Average number of **output** and **prompt** tokens per CLI request, computed as `(output_tokens_sum + prompt_tokens_sum) ÷ request_count`. Null when there were no requests that day. | +| `totals_by_cli.last_known_cli_version` | `object` | No | Most recent {% data variables.copilot.copilot_cli_short %} version detected for the user that day, as `{ cli_version, sampled_at }`. Per-user reports only. | +| `totals_by_cli.last_known_cli_version.cli_version` | `string` | No | {% data variables.copilot.copilot_cli_short %} version string. Defaults to `unknown` if no version was detected. | +| `totals_by_cli.last_known_cli_version.sampled_at` | `string` | Yes | Timestamp (ISO 8601) when the version was sampled. | + +### Pull request activity fields + +> [!IMPORTANT] +> Organization- and enterprise-level reports may show different totals due to differences in user deduplication and attribution timing. For guidance on interpreting pull request metrics across scopes, see [AUTOTITLE](/copilot/concepts/copilot-usage-metrics/copilot-metrics#interpreting-pull-request-lifecycle-metrics-across-scopes). + +The `pull_requests` object appears in aggregated enterprise and organization reports only. It captures daily pull request creation, review, merge, and suggestion activity at the enterprise or organization scope, including activity performed by {% data variables.product.prodname_copilot_short %}. + +| Field | Type | Nullable | Description | +|:--|:--|:--|:--| +| `pull_requests.total_created` | `integer` | No | Total number of pull requests created on this specific day.

Creation is a one-time event. Each pull request is counted only on the day it is created. | +| `pull_requests.total_reviewed` | `integer` | No | Total number of pull requests reviewed on this specific day.

The same pull request may be counted on multiple days if it receives reviews on multiple days. Within a single day, each pull request is counted once, even if multiple review actions occur. | +| `pull_requests.total_merged` | `integer` | No | Total number of pull requests merged on this specific day.

Merging is a one-time event. Each pull request is counted only on the day it is merged. | +| `pull_requests.median_minutes_to_merge` | `number` | Yes | Median time, in minutes, between pull request creation and merge for pull requests merged on this specific day.

Median is used to reduce the impact of outliers from unusually long-running pull requests. Null when no pull requests were merged that day. | +| `pull_requests.total_suggestions` | `integer` | No | Total number of pull request review suggestions generated on this specific day, regardless of author. | +| `pull_requests.total_applied_suggestions` | `integer` | No | Total number of pull request review suggestions that were applied on this specific day, regardless of author. | +| `pull_requests.total_created_by_copilot` | `integer` | No | Number of pull requests created by {% data variables.product.prodname_copilot_short %} on this specific day. | +| `pull_requests.total_reviewed_by_copilot` | `integer` | No | Number of pull requests reviewed by {% data variables.product.prodname_copilot_short %} on this specific day.

A pull request may be counted on multiple days if {% data variables.product.prodname_copilot_short %} reviews it on multiple days. | +| `pull_requests.total_merged_created_by_copilot` | `integer` | No | Number of pull requests created by {% data variables.product.prodname_copilot_short %} that were merged on this specific day. Each pull request is counted only on the day it is merged. | +| `pull_requests.total_merged_reviewed_by_copilot` | `integer` | No | Number of pull requests that were both merged and reviewed by {% data variables.copilot.copilot_code-review_short %} during the reporting period. | +| `pull_requests.median_minutes_to_merge_copilot_authored` | `number` | Yes | Median time, in minutes, between pull request creation and merge for pull requests created by {% data variables.product.prodname_copilot_short %} and merged on this specific day. Null when no such pull requests were merged that day. | +| `pull_requests.median_minutes_to_merge_copilot_reviewed` | `number` | Yes | Median time, in minutes, between pull request creation and merge, calculated only for pull requests reviewed by {% data variables.copilot.copilot_code-review_short %}. Null when no such pull requests were merged that day. | +| `pull_requests.total_copilot_suggestions` | `integer` | No | Number of pull request review suggestions generated by {% data variables.product.prodname_copilot_short %} on this specific day. | +| `pull_requests.total_copilot_applied_suggestions` | `integer` | No | Number of pull request review suggestions generated by {% data variables.product.prodname_copilot_short %} that were applied on this specific day. | +| `pull_requests.copilot_suggestions_by_comment_type` | `array` | No | Aggregated counts of {% data variables.product.prodname_copilot_short %} code review suggestions, broken down by the comment type {% data variables.product.prodname_copilot_short %} assigned (for example, `security` or `bug_risk`). Each entry includes `comment_type`, `total_copilot_suggestions`, and `total_copilot_applied_suggestions`. Always present but can be empty. Not available at the repository level. | + +### AI adoption phase fields + +{% data variables.product.prodname_copilot_short %} groups users into AI adoption phases based on their activity. Phase information appears in two places: the per-user `ai_adoption_phase` object, and the aggregated `totals_by_ai_adoption_phase` array. For the phase values, see [Breakdown dimension values](#breakdown-dimension-values). + +The per-user `ai_adoption_phase` object contains: + +| Field | Type | Nullable | Description | +|:--|:--|:--|:--| +| `ai_adoption_phase.phase_number` | `integer` | No | Numeric phase identifier (for example, `0` for "No Cohort"). | +| `ai_adoption_phase.phase` | `string` | No | Human-readable phase name. | +| `ai_adoption_phase.version` | `string` | No | Version of the adoption-phase model used (for example, `v1`). | + +Each entry in the aggregated `totals_by_ai_adoption_phase` array contains: + +| Field | Type | Nullable | Description | +|:--|:--|:--|:--| +| `phase` | `string` | No | Human-readable phase name. | +| `phase_number` | `integer` | No | Numeric phase identifier. | +| `total_engaged_users` | `integer` | No | Number of users grouped into this phase for the period. | +| `avg_user_initiated_interactions` | `number` | No | Average user-initiated interactions per user in this phase. | +| `avg_code_generation_activities` | `number` | No | Average code generation activities per user in this phase. | +| `avg_code_acceptance_activities` | `number` | No | Average code acceptance activities per user in this phase. | +| `avg_loc_added` | `number` | No | Average lines of code added per user in this phase. | +| `avg_loc_deleted` | `number` | No | Average lines of code deleted per user in this phase. | +| `avg_pull_requests_reviewed` | `number` | No | Average pull requests reviewed per user in this phase. | +| `avg_pull_requests_created` | `number` | No | Average pull requests created per user in this phase. | +| `avg_pull_requests_merged` | `number` | No | Average pull requests merged per user in this phase. | +| `avg_pull_requests_median_minutes_to_merge` | `number` | No | Average of the per-user median minutes to merge for users in this phase. | + +### Breakdown dimension values + +The breakdown objects above use dimension fields whose values come from fixed sets. These are field **values**, not separate fields. For example, `agent_edit` and the `chat_panel_*_mode` values are values of the `feature` field, not top-level fields. + +The `feature` dimension identifies the {% data variables.product.prodname_copilot_short %} feature or mode an activity is attributed to: + +| Value | Description | |:--|:--| -| `user_id` / `user_login` | Unique identifier and {% data variables.product.github %} username for the user. | -| `day` | Calendar day this record represents. | -| `organization_id` (organization scope) | Unique ID of the organization the team belongs to. | -| `enterprise_id` (enterprise scope) | Unique ID of the enterprise the team belongs to. The enterprise-scoped report includes both enterprise teams and business teams. | -| `team_id` | Unique ID of the team the user belongs to. | -| `slug` | URL-friendly identifier for the team. | +| `code_completion` | Inline code completions. | +| `chat_inline` | Inline chat in the editor. | +| `chat_panel_ask_mode` | Chat panel interactions with ask mode selected. | +| `chat_panel_edit_mode` | Chat panel interactions with edit mode selected. | +| `chat_panel_agent_mode` | Chat panel interactions with agent mode selected. | +| `chat_panel_plan_mode` | Chat panel interactions with plan mode selected. | +| `chat_panel_custom_mode` | Chat panel interactions with a custom agent selected. | +| `chat_panel_unknown_mode` | Chat panel interactions where the mode is unknown. | +| `agent_edit` | Lines added and deleted when {% data variables.product.prodname_copilot_short %} (in agent and edit mode) writes changes directly into your files in the IDE. Counts edits from custom agents as well. `agent_edit` is not included in suggestion-based metrics and may not populate suggestion-style fields, such as `user_initiated_interaction_count`. | +| `copilot_cli` | Activity attributed to {% data variables.copilot.copilot_cli_short %}. | +| `others` | Any feature not covered by the values above. | + +The `ide` dimension identifies the IDE an activity occurred in. This is not an exhaustive list, but examples of observed values include `vscode`, `visualstudio`, `intellij`, `eclipse`, `xcode`, `neovim`, `vim`, `emacs`, and `zed`. + +The `model` dimension identifies the AI model used for chat activity. Values include specific model identifiers (for example, `gpt-5.4` or `claude-sonnet-4.6`), `auto`, `unknown`, and `others`. The `auto` value represents activity where {% data variables.copilot.copilot_auto_model_selection_short %} was used and the request was not attributed to a specific model. + +The `phase` dimension identifies the AI adoption phase a user is grouped into: `No Cohort`, `Phase 1`, `Phase 2`, or `Phase 3`. diff --git a/content/copilot/reference/hooks-reference.md b/content/copilot/reference/hooks-reference.md index d8bde2b684fc..3b931dab5e87 100644 --- a/content/copilot/reference/hooks-reference.md +++ b/content/copilot/reference/hooks-reference.md @@ -115,6 +115,34 @@ Command hooks run shell scripts and are supported on all hook types. | `timeoutSec` | number | No | Timeout in seconds. Default: `30`. | | `type` | `"command"` | No | Hook type. Defaults to `"command"` when omitted. | +#### Progress messages + +Command hooks can emit progress status lines to the CLI timeline while executing. Write a `{"type": "progress", "message": "..."}` JSON object to stdout before writing the final output: + +```bash +echo '{"type": "progress", "message": "Checking policy..."}' +# ... perform work ... +echo '{"permissionDecision": "allow"}' +``` + +Set `"temporary": true` to emit a transient status line. A transient line replaces the previous transient line and is cleared when the assistant responds, instead of accumulating in the timeline: + +```bash +echo '{"type": "progress", "message": "Routing...", "temporary": true}' +echo '{"type": "progress", "message": "Thinking...", "temporary": true}' +# ... perform work ... +echo '{"permissionDecision": "allow"}' +``` + +Progress messages are display-only and do not affect hook output or decision logic. + +**How stdout is parsed when progress messages are mixed in.** — The CLI scans stdout line-by-line as the hook runs. Any line that, after trimming, is a single complete JSON object with `"type": "progress"` is consumed as a progress event and **removed from the hook's output stream**. Every other line—blank lines, plain text, and JSON objects that are not progress messages—is preserved verbatim. When the hook exits, the preserved lines are concatenated, trimmed, and parsed with a single `JSON.parse` call: that result is the hook's output (the "hook output JSON" referenced elsewhere in this article). This means: + +* Emitting progress lines alongside a final decision object (as in the examples above) is safe and is the intended pattern—the progress lines never reach the JSON parser. +* Each progress message must be on its own line and must be valid JSON on that single line. Multi-line / pretty-printed progress objects are not recognized as progress and will be left in the output stream, where they will likely cause the final `JSON.parse` to fail. +* The final decision object, by contrast, may span multiple lines—only progress *recognition* is line-oriented; what remains after progress stripping is parsed as one JSON document, not as line-delimited JSON. +* If the leftover output is empty, or fails to parse as JSON, the hook is treated as having produced no output and falls through to default behavior. Two or more non-progress JSON objects on stdout (for example, two `echo '{"permissionDecision": ...}'` calls) will therefore concatenate into invalid JSON and be ignored—emit exactly one final decision object. + ### HTTP hooks HTTP hooks send the input payload as a JSON `POST` to a URL. @@ -311,6 +339,30 @@ When configured with the PascalCase event name `PreToolUse`, the payload uses sn } ``` +**Claude-format matchers (PascalCase `PreToolUse`):** Hooks configured with the PascalCase event name `PreToolUse`—as used in Claude Code plugins and the Open Plugins format—apply Claude's matcher semantics instead of the native regex rule: + +* `*`, `**`, or an empty matcher fires for every tool. +* A literal name or `|`-separated alternation (for example, `Bash` or `Edit|Write`) fires when any token equals the runtime tool name or its Claude tool name from the table below. +* Any other value is treated as a case-sensitive regex anchored as `^(?:pattern)$` tested against the Claude tool name (or the runtime name for tools with no Claude equivalent). + +Payloads for PascalCase `PreToolUse` report `tool_name` as the Claude tool name (for example, `Bash`, not `bash`). + +| Runtime tool | Claude tool name | +|---|---| +| `bash`, `powershell` | `Bash` | +| `view` | `Read` | +| `create` | `Write` | +| `edit`, `str_replace_editor`, `apply_patch` | `Edit` | +| `grep`, `rg` | `Grep` | +| `glob` | `Glob` | +| `web_fetch` | `WebFetch` | +| `web_search` | `WebSearch` | +| `ask_user` | `AskUserQuestion` | +| `update_todo` | `TodoWrite` | +| `task` | `Agent` (the literal `Task` is also accepted) | + +Tools with no Claude equivalent keep their runtime names. + > [!IMPORTANT] > **Command vs HTTP fail behavior for `preToolUse`:** Command `preToolUse` hooks are **fail-closed**—a crash or non-zero exit denies the tool call. HTTP `preToolUse` hooks are **fail-open**—a network error, timeout, or non-2xx response falls through to the default permission flow. Choose the variant that matches your security requirements. @@ -573,6 +625,9 @@ All configured `permissionRequest` hooks run for each request (except `read` and **Matcher:** Optional regex tested against `toolName`. Anchored as `^(?:pattern)$`; must match the full tool name. When set, the hook fires only for matching tool names. +> [!NOTE] +> **Claude-format matchers (PascalCase `PermissionRequest`):** Hooks configured with the PascalCase event name `PermissionRequest` use the same Claude matcher semantics as `PreToolUse`. See [Claude-format matchers (PascalCase PreToolUse)](#claude-format-matchers-pascalcase-pretooluse) for the matcher rules and tool name table. + Output JSON to stdout to control the permission decision: | Field | Values | Description | diff --git a/content/copilot/tutorials/budgets/optimizing-your-budget-configuration.md b/content/copilot/tutorials/budgets/optimizing-your-budget-configuration.md index 295d576efc21..bd807048094f 100644 --- a/content/copilot/tutorials/budgets/optimizing-your-budget-configuration.md +++ b/content/copilot/tutorials/budgets/optimizing-your-budget-configuration.md @@ -18,7 +18,7 @@ category: - Manage Copilot for a team --- -Before optimizing your budget configuration, make sure you understand how the four budget controls work and how the system evaluates them. See [AUTOTITLE](/copilot/concepts/billing/budgets-for-usage-based-billing). +Before optimizing your budget configuration, make sure you understand how budget controls work and how the system evaluates them. See [AUTOTITLE](/copilot/concepts/billing/budgets-for-usage-based-billing). If you haven't set up budgets yet, start with [AUTOTITLE](/copilot/tutorials/budgets/getting-started-with-budget-controls) to get the basics in place, then come back to this guide to optimize your configuration. @@ -37,9 +37,29 @@ If you also use cost center budgets, the sum of your cost center budgets and you > [!TIP] > Whenever you raise user-level budgets, re-check this calculation. Raising ULBs without raising the enterprise budget can cause the enterprise budget to block users before they reach their individual budgets. +## Choosing a scope + +For most enterprises, we recommend **cost center budgets with users directly assigned**. When users are assigned directly to a cost center, charges always follow the user, so enforcement is predictable regardless of how licenses are structured. + +| Scope | Use when | Who can set it | +| --- | --- | --- | +| Cost center budget | You want predictable organization-level spending control as an enterprise admin. | Enterprise owners, billing managers | +| Organization budget | Organization owners need to set their own spending limits without enterprise admin involvement. | Organization owners | +| Enterprise budget | You need a failsafe that caps total metered charges for all users not covered by a narrower budget. | Enterprise owners, billing managers | + +If users in your enterprise have {% data variables.product.prodname_copilot_short %} licenses from multiple organizations, both organization budgets and cost centers that only contain organizations (not users) will enforce unpredictably. The billing organization is chosen at random each cycle, so spend may count against a different budget from month to month. Assigning users directly to cost centers avoids this problem. + +### Migrating from organization budgets to cost centers + +If your enterprise already has organization budgets, they will continue to work. However, if you have users with {% data variables.product.prodname_copilot_short %} licenses assigned through multiple organizations, migrating to cost centers with direct user assignment gives more predictable enforcement. + +1. Create cost centers and assign users directly (not just organizations). +1. Set cost center budgets matching your desired spending caps. +1. Remove the organization budgets once cost center budgets are in place. + ## Common scenarios -The following scenarios show common budget configurations for different enterprise structures. Each one builds on the previous, adding more controls. Start with the simplest configuration that matches your needs. You can layer on additional controls later as your usage patterns become clearer. +The following scenarios show common budget configurations for different enterprise structures. ### Manage shared usage responsibly @@ -84,6 +104,20 @@ Consider enabling **cost center exclusion** if you want business units to operat This is the most granular configuration. It combines per-user controls (who can consume how much), per-team controls (how much metered spend each business unit can generate), and an enterprise-wide safety net. Use this when you have a mix of usage patterns across teams and need fine-grained governance. +### Delegating control to organization owners + +**Situation:** Organization owners need to set their own spending guardrails without involving an enterprise admin. + +**Configuration:** + +* Each organization owner sets an **organization budget** for their organization. +* The enterprise admin sets an **enterprise budget** as a safety net. +* Enable **"Stop usage when budget limit is reached"** on all budgets. + +Organization budgets are the only budget option available to organization owners. An organization budget can only further restrict usage below any budget set by an enterprise admin. It cannot override a higher-level budget. + +If users in your enterprise have {% data variables.product.prodname_copilot_short %} licenses assigned through multiple organizations, organization budgets may not enforce predictably for those users. In this case, {% data variables.product.github %} picks one organization at random each billing cycle to bill the seat. This means the user's spend could count against a different organization's budget from month to month, making enforcement unpredictable. To avoid this, ensure each user has a single license through one organization, or use cost center budgets with direct user assignment. + ## Using historical data to size budgets Your AI usage dashboard and the usage export CSV are the best tools for sizing budgets. Look at: diff --git a/data/reusables/copilot/code-review/custom-instructions-limit.md b/data/reusables/copilot/code-review/custom-instructions-limit.md index 86ec2eb08fc1..1596bc3065c0 100644 --- a/data/reusables/copilot/code-review/custom-instructions-limit.md +++ b/data/reusables/copilot/code-review/custom-instructions-limit.md @@ -1,3 +1,2 @@ > [!NOTE] -> * {% data variables.copilot.copilot_code-review_short %} only reads the first 4,000 characters of any custom instruction file. Any instructions beyond this limit will not affect the reviews generated by {% data variables.copilot.copilot_code-review_short %}. This limit does not apply to {% data variables.copilot.copilot_chat_short %} or {% data variables.copilot.copilot_cloud_agent %}. -> * {% data reusables.copilot.code-review.custom-instructions-branch %} +> {% data reusables.copilot.code-review.custom-instructions-branch %} diff --git a/data/reusables/copilot/model-fable-disabled.md b/data/reusables/copilot/model-fable-disabled.md new file mode 100644 index 000000000000..3fe3c546eba8 --- /dev/null +++ b/data/reusables/copilot/model-fable-disabled.md @@ -0,0 +1 @@ +> [!NOTE] Claude Fable 5 is currently unavailable. For more information, see [Anthropic's announcement](https://www.anthropic.com/news/fable-mythos-access). \ No newline at end of file diff --git a/package.json b/package.json index 543eb1028096..c4764c901218 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,7 @@ "prevent-pushes-to-main": "tsx src/workflows/prevent-pushes-to-main.ts", "purge-fastly-edge-cache": "tsx src/workflows/purge-fastly-edge-cache.ts", "purge-fastly-edge-cache-per-language": "tsx src/languages/scripts/purge-fastly-edge-cache-per-language.ts", + "purge-fastly-all": "tsx src/workflows/purge-fastly-all.ts", "readability-report": "tsx src/workflows/experimental/readability-report.ts", "ready-for-docs-review": "tsx src/workflows/ready-for-docs-review.ts", "release-banner": "tsx src/ghes-releases/scripts/release-banner.ts", diff --git a/src/content-pipelines/state/copilot-cli.sha b/src/content-pipelines/state/copilot-cli.sha index 473bb8c694a7..c1ece678dd0e 100644 --- a/src/content-pipelines/state/copilot-cli.sha +++ b/src/content-pipelines/state/copilot-cli.sha @@ -1 +1 @@ -c05adb990b05f7ab88981904a6f5e0d67ab1387c +005830f576fb7f53962c8080fdd86d7a382587c6 diff --git a/src/secret-scanning/data/pattern-docs/fpt/public-docs.yml b/src/secret-scanning/data/pattern-docs/fpt/public-docs.yml index 0027e5b73a70..47c64d42597b 100644 --- a/src/secret-scanning/data/pattern-docs/fpt/public-docs.yml +++ b/src/secret-scanning/data/pattern-docs/fpt/public-docs.yml @@ -1679,6 +1679,16 @@ hasValidityCheck: false hasExtendedMetadata: false base64Supported: false + isduplicate: true +- provider: Datadog + supportedSecret: Datadog Personal Access Token + secretType: datadog_pat + isPublic: true + isPrivateWithGhas: false + hasPushProtection: false + hasValidityCheck: false + hasExtendedMetadata: false + base64Supported: false isduplicate: false - provider: Datadog supportedSecret: Datadog RCM @@ -1690,6 +1700,16 @@ hasExtendedMetadata: false base64Supported: false isduplicate: false +- provider: Datadog + supportedSecret: Datadog Service Account Token + secretType: datadog_sat + isPublic: true + isPrivateWithGhas: false + hasPushProtection: false + hasValidityCheck: false + hasExtendedMetadata: false + base64Supported: false + isduplicate: false - provider: Datastax supportedSecret: Datastax AstraCS Tokens secretType: datastax_astracs_token @@ -3431,7 +3451,7 @@ isPrivateWithGhas: true hasPushProtection: true hasValidityCheck: true - hasExtendedMetadata: false + hasExtendedMetadata: '{% ifversion ghes %}false{% else %}true{% endif %}' base64Supported: false isduplicate: true - provider: NuGet diff --git a/src/secret-scanning/data/pattern-docs/ghec/public-docs.yml b/src/secret-scanning/data/pattern-docs/ghec/public-docs.yml index 0027e5b73a70..47c64d42597b 100644 --- a/src/secret-scanning/data/pattern-docs/ghec/public-docs.yml +++ b/src/secret-scanning/data/pattern-docs/ghec/public-docs.yml @@ -1679,6 +1679,16 @@ hasValidityCheck: false hasExtendedMetadata: false base64Supported: false + isduplicate: true +- provider: Datadog + supportedSecret: Datadog Personal Access Token + secretType: datadog_pat + isPublic: true + isPrivateWithGhas: false + hasPushProtection: false + hasValidityCheck: false + hasExtendedMetadata: false + base64Supported: false isduplicate: false - provider: Datadog supportedSecret: Datadog RCM @@ -1690,6 +1700,16 @@ hasExtendedMetadata: false base64Supported: false isduplicate: false +- provider: Datadog + supportedSecret: Datadog Service Account Token + secretType: datadog_sat + isPublic: true + isPrivateWithGhas: false + hasPushProtection: false + hasValidityCheck: false + hasExtendedMetadata: false + base64Supported: false + isduplicate: false - provider: Datastax supportedSecret: Datastax AstraCS Tokens secretType: datastax_astracs_token @@ -3431,7 +3451,7 @@ isPrivateWithGhas: true hasPushProtection: true hasValidityCheck: true - hasExtendedMetadata: false + hasExtendedMetadata: '{% ifversion ghes %}false{% else %}true{% endif %}' base64Supported: false isduplicate: true - provider: NuGet diff --git a/src/workflows/purge-fastly-all.ts b/src/workflows/purge-fastly-all.ts new file mode 100644 index 000000000000..2d94ec0b0694 --- /dev/null +++ b/src/workflows/purge-fastly-all.ts @@ -0,0 +1,59 @@ +import { fetchWithRetry } from '@/frame/lib/fetch-utils' + +// Purges the ENTIRE Fastly cache for the docs service via Fastly's purge_all +// endpoint. This is the workflow equivalent of the "Purge all" button in the +// Fastly UI. It is intentionally a separate, manually triggered entry point: +// routine post-deploy purging is handled by +// `purge-fastly-edge-cache-per-language.ts`, and a gentler "refresh everything" +// can be done by running the Purge Fastly workflow with an empty languages +// input (a soft surrogate-key purge of every language). +// +// NOTE: Fastly's purge_all is always a HARD purge. The `fastly-soft-purge` +// header has no effect on this endpoint, so every object is evicted immediately +// and origin sees a traffic spike while the cache refills. Only reach for this +// when a targeted purge will not do. +// https://www.fastly.com/documentation/reference/api/purging/ + +async function purgeFastlyAll({ apiToken, serviceId }: { apiToken: string; serviceId: string }) { + const safeServiceId = encodeURIComponent(serviceId) + const requestPath = `https://api.fastly.com/service/${safeServiceId}/purge_all` + const response = await fetchWithRetry( + requestPath, + { + method: 'POST', + headers: { + 'fastly-key': apiToken, + accept: 'application/json', + 'Content-Type': 'application/json', + }, + }, + { + retries: 0, + timeout: 30_000, + throwHttpErrors: false, + }, + ) + if (!response.ok) { + // Fastly puts permission/feature-disabled details in the response body, + // which is often the only actionable signal, so surface it best-effort. + let body = '' + try { + body = await response.text() + } catch { + body = '' + } + throw new Error( + `Fastly purge_all failed: HTTP ${response.status} ${response.statusText}${body ? `: ${body}` : ''}`, + ) + } + return response +} + +const { FASTLY_TOKEN, FASTLY_SERVICE_ID } = process.env +if (!FASTLY_TOKEN || !FASTLY_SERVICE_ID) { + throw new Error('Fastly env vars not detected; refusing to run purge_all') +} + +console.log('Attempting Fastly purge_all (hard purge of the entire cache)...') +const result = await purgeFastlyAll({ apiToken: FASTLY_TOKEN, serviceId: FASTLY_SERVICE_ID }) +console.log('Fastly purge_all result:', result.status)