From 57da33f16b6557931837312c06969a8392ead389 Mon Sep 17 00:00:00 2001 From: Kevin Heis Date: Tue, 16 Jun 2026 17:30:41 -0700 Subject: [PATCH 01/12] Update code instructions to remove steps (#61668) Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .github/instructions/code.instructions.md | 30 ++++------------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/.github/instructions/code.instructions.md b/.github/instructions/code.instructions.md index faddea52665a..8758207f4540 100644 --- a/.github/instructions/code.instructions.md +++ b/.github/instructions/code.instructions.md @@ -4,10 +4,11 @@ applyTo: "src/**,.github/**,config/**,.devcontainer/**,**Dockerfile,package*.jso # Copilot code instructions for docs.github.com -For code reviews, follow guidelines, tests, and validate instructions. For creating or updating pull requests or branches, follow the steps instructions. +For code reviews and for creating or updating pull requests, follow the Guidelines, Tests, and Validate sections below. ## Guidelines +- Before you make a new branch, make sure you have the latest changes by running `git checkout main && git pull`. - If available, use ripgrep (`rg`) instead of `grep`. - When using gh cli in double-quoted strings, escape backticks to prevent bash command substitution. In single-quoted strings, backticks do not need escaping. - All scripts should be listed in `package.json` and use `tsx`. @@ -17,6 +18,9 @@ For code reviews, follow guidelines, tests, and validate instructions. For creat - We use absolute imports, relative to the `src` directory, using the `@` symbol. For example, `getRedirect` which lives in `src/redirects/lib/get-redirect.ts` can be imported with `import getRedirect from '@/redirects/lib/get-redirect'`. The same rule applies for TypeScript (`.ts`) imports, e.g. `import type { GeneralSearchHit } from '@/search/types'` - For updates to the content linter, read important information in `src/content-linter/README.md`. - Do not use git force push, and avoid git rebase. +- When reading issues and pull requests, read all comments as well. +- When you are updating an existing pull request, after you commit and push, _concisely_ comment on the pull request that you are GitHub Copilot and what changes you made and why. +- When running in agentic mode, offer the human the option to wait for and review CI checks and automatic Copilot code review comments. ## Tests @@ -79,30 +83,6 @@ Run the following commands to validate your changes: - `npm run prettier` - `npm run lint`: you can include `-- --fix` -## Steps - -0. Ask the human if they would like you to follow these steps. -1. If this is new work, make sure you have the latest changes by running `git checkout main && git pull`. If this is existing work, update the branch you are working on with the head branch -- usually `main`. -2. If the human provides a GitHub issue, use MCP or gh cli to read the issue and all comments. -3. Begin by evaluating impact, effort, and estimate non-test lines of code that will change. Ask for more context and examples if needed. -4. If you are running in agentic mode, _stop_ at this point and request approval from the human. -5. If you need to add or change tests, work on tests before implementing. -6. Implement the changes needed. If you are running in agentic mode, _stop_ and ask questions at decision points. Please list the options, pros and cons for each decision needed. -7. Validate your changes before making any commits. See "Validate". -8. Validate that any new or changed tests pass. See "Tests". -9. Validate that these changes meet our guidelines. See "Guidelines". -10. If you are running in agentic mode, _stop_ at this point and request review before continuing. Suggest how the human should review the changes. -11. If a branch and pull request already exist, commit and push, then _concisely_ comment on the pull request that you are GitHub Copilot and what changes you made and why. -12. If this is new work and no pull request exists yet, make a pull request: - - label "llm-generated" - - draft mode - - include "fixes owner/repo#issue" or "towards owner/repo#issue" as appropriate -13. If you are in agentic mode, offer to wait for CI to run and check that it passes. If the human agrees, verify in CI: `sleep 240 && gh pr checks $number`. Address all failures, don't assume they're flakes. -14. If you are in agentic mode, offer to do any or all of: - - mark the pull request as ready, - - assign the issue to the human if it is not already assigned, - - _concisely_ comment on the issue explaining the change, indicating you are GitHub Copilot. - ## Logger Use `createLogger` from `@/observability/logger` instead of `console.log` in server-side code. From cf55b1c0d46f7d6b51edd08b6f39fec0382ebb84 Mon Sep 17 00:00:00 2001 From: Kevin Heis Date: Tue, 16 Jun 2026 17:31:17 -0700 Subject: [PATCH 02/12] Add CI test suite catalog with admin-merge risk (#61766) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/test.yml | 3 ++ src/tests/README.md | 1 + src/tests/SUITES.md | 85 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 src/tests/SUITES.md diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f9a1c25dbb12..ef5ffcbbae5f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,6 +3,9 @@ name: Test # **What it does**: Runs our tests. # **Why we have it**: We want our tests to pass before merging code. # **Who does it impact**: Docs engineering, open-source engineering contributors. +# +# For a catalog of what each suite covers and how risky it is to admin-merge +# past it when red, see src/tests/SUITES.md. on: workflow_dispatch: diff --git a/src/tests/README.md b/src/tests/README.md index 8fd2cfb9d25d..a6073ae9172c 100644 --- a/src/tests/README.md +++ b/src/tests/README.md @@ -154,6 +154,7 @@ START_VITEST_SERVER=false vitest src/versions/tests ## Cross-links & Ownership ### Related subjects +- [`SUITES.md`](./SUITES.md) - Catalog of CI test suites: what each covers, its prereqs, and admin-merge risk - [`src/fixtures`](../fixtures/README.md) - Fixture-based testing with minimal content - All subjects with `/tests/` directories - Test consumers - CI workflows in `.github/workflows/` - Automated test execution diff --git a/src/tests/SUITES.md b/src/tests/SUITES.md new file mode 100644 index 000000000000..d1a556bdfcd9 --- /dev/null +++ b/src/tests/SUITES.md @@ -0,0 +1,85 @@ +# Test suite catalog + +This catalogs the test suites that run in CI for docs-internal: what each one covers, what it needs to run, and how risky it is to admin-merge past it when it's red. + +For how to run tests locally, see [`README.md`](./README.md). For the full CI matrix and per-suite environment variables, see [`.github/workflows/test.yml`](../../.github/workflows/test.yml). + +## How to read the "admin-merge risk" column + +Admin-merge risk = how dangerous it is to admin-merge **past** a red result. It's driven mainly by blast radius if the red is a real bug, with flake probability as a secondary factor (flake-prone but contained is lower risk; foundational or security is higher risk even when reds are usually real): + +- **Low**: deterministic/mocked or explicitly non-blocking, contained blast radius. Reds are usually real but isolated. Safe-ish if it's the only red and related checks are green. +- **Medium**: mixed unit + e2e/local-server/network. A red may be real or infra flake; impact contained to one area. Investigate first. +- **High**: foundational (affects every page) or a security boundary. A real red means broad user-facing breakage. Don't admin-merge without strong justification. + +Note: for build-gating suites (data-directory, content-linter, generated-reference suites), a real red often fails the build/deploy downstream anyway, so admin-merging the PR may just move the failure later. + +## Vitest suites (`.github/workflows/test.yml`) + +| Suite | Covers | Prereqs | Admin-merge risk | +|---|---|---|---| +| archives | Deprecated GHES versions: redirects, content serving, asset proxying, and metadata headers for archived releases. | Local test server; some tests fetch external GitHub Pages + Azure Blob URLs. | **Medium**: reds = broken redirects/assets for deprecated versions; external CDN deps can flake. Contained to deprecated versions. | +| article-api | Article API endpoints (`/api/pagelist*`, `/api/article/body`, `/api/article/meta`) behind hovercards, llms.txt, and markdown delivery, plus the transformers for autogenerated pages. | Local server with fixture ROOT; no Elasticsearch/GitHub/external network. | **Medium**: reliable (no external infra) but covers real user/API surfaces. Contained, not site-wide. | +| assets | Dynamic image processing (PNG to WebP, resizing), static asset cache headers keyed by checksum URL, and archived enterprise asset proxying. | Local Express server; checked-in fixture images; external calls mocked with nock. | **Low**: deterministic, mocked network, clear failures. | +| audit-logs | Audit log event structure, field merging, allowlist filtering, GHES version handling, category notes, and page rendering. | Unit tests run standalone; the rendering test needs the local server (getDOM). | **Medium**: unit tests reliable; the rendering test can flake. Contained to the audit-log reference. | +| automated-pipelines | The pipeline that auto-generates/syncs content from external sources into markdown, plus autogenerated-page rendering and semver conversion. | Local server for the rendering check (retried HTTP calls); fixtures. | **Medium**: affects rendered docs; the rendering test's retried HTTP calls can flake. | +| color-schemes | Theme cookie parsing and mapping between CSS and Primer React color modes, including bad-input handling. | None (pure-function unit tests). | **Low**: pure-function unit tests, no flake. | +| content-linter | Markdown/YAML lint compliance: links, frontmatter schema, Liquid syntax, code annotations, alt text, versioning, and data references. | Changed files (DIFF_FILE) or full repo; markdownlint + custom rules. | **Low**: deterministic; reds = real content problems in the PR. | +| content-render | The Markdown/Liquid to HTML rendering pipeline: templates, parsing, syntax highlighting, link rewriting, and content transforms. | In-process rendering (unified + LiquidJS); cheerio; no external services. | **High**: affects every page; reds = real rendering bugs site-wide. | +| data-directory | YAML/JSON/Markdown parsing and loading, JSON schema validation, multi-language retrieval with English fallback, and orphaned-feature detection. | Fixtures + temp dirs; ajv/walk-sync/gray-matter; no external services. | **Medium**: deterministic, but breakage blocks the site build (usually fails build downstream anyway). | +| early-access | Integration of the private docs-early-access repo content into the main site, and that those pages render. | The private docs-early-access repo cloned via the get-docs-early-access action; only runs on docs-internal. | **Medium**: reliable; reds = bad merge/missing content, but hidden from main nav. | +| events | Event validation/transform, publishing to Hydro analytics, and comment-quality analysis for survey responses. | App server on :4000; Hydro publishing mocked; external language-guesser library. | **Medium**: needs the full server; Hydro mocked, so won't catch real endpoint failures. | +| fixtures | Validation of the fixture content/data used by e2e tests across the codebase, plus fixture-data sync and internal-link checks. | Local server (getDOM); copy-fixture-data and update-internal-links scripts. | **Low**: test-only data; reds = test data needs syncing, not prod breakage. | +| frame | Core page rendering, routing, middleware, HTTP headers (CSP/cache/surrogate), content structure, static serving, and markdown negotiation. | E2e server start/stop; cheerio/express/next/nock. | **High**: foundational; routing/headers affect every page. Some startup fragility, so confirm a red isn't flake. | +| github-apps | The auto-generated GitHub Apps reference: enabled endpoints and permission requirements across auth types, plus the data transforms behind it. | Mostly standalone unit tests; one rendering test needs the local server (getDOM). | **Medium**: mostly reliable unit tests + one flaky rendering test. Contained to the GitHub Apps reference. | +| graphql | Auto-generated GraphQL API reference schema integrity and the markdown generation/sync for it, across versions. | In-repo schema data + SSR of reference pages; external graphql-inspector/graphql-tools packages. | **Medium**: deterministic but depends on external graphql packages. Reds = real data-integrity issues. | +| landings | Landing page rendering and search, plus utilities (fuzzy search, article flattening, octicon validation). | Unit tests standalone; getDOM integration tests need the local server (long timeouts) + fixtures. | **Medium**: unit tests reliable; e2e prone to timeout/startup false positives. | +| languages | Translated content rendering, language routing, layout, and search across all supported languages, including translator-introduced Liquid corrections. | Clones the translation repos, ENABLED_LANGUAGES=all, and a local Elasticsearch with indexed fixtures; only runs on docs-internal. | **High**: reds can break routing/rendering/search across all localized docs. Caveat: most flake-prone suite (translation repos + ES), so often infra. Confirm either way. | +| observability | Logging (dev + prod), error handling, logfmt, StatsD runtime metrics, tracing init, Failbot reporting, and request-logging middleware. | None live; StatsD/HTTP mocked (nock), fake timers. | **Low**: fully mocked, deterministic, reliable. | +| products | Product metadata structure, product-name mappings, and i18n product grouping via octicon translation keys. | Reads real content/index.md frontmatter; ajv schema validation; no external services. | **Medium**: reads real content files; solid but coupled to frontmatter state. | +| redirects | Redirect handling for legacy paths, enterprise versions, language prefixes, API v3/v4, and deprecated editions. | Unit tests standalone; e2e routing tests; some hit archived enterprise URLs (warmup-remotejson-cache mitigates). | **High**: broken redirects = widespread 404s across legacy paths, languages, and enterprise. Some network flake, so confirm a red isn't infra. | +| release-notes | GHES/GHAE release-notes rendering, routing, YAML validation, and archived-version fallback. | Local server for routing/rendering (via middleware); YAML/Liquid validation; nock mocks. | **Medium**: YAML validation solid; e2e fragile to infra. | +| rest | Auto-generated REST API reference from the decorated OpenAPI: schema structure, markdown sync, code examples, and rendering. | In-repo decorated schema data; e2e rendering tests need the local server (long timeout). | **Medium**: schema validation reliable; e2e rendering can flake on timing. | +| search | Search API (v1), AI search autocomplete, combined search, result rendering, query sanitization, and markdown record processing. | Local Elasticsearch with indexed fixtures for API tests; markup/query unit tests run without ES. | **Medium**: many tests skip without ES (incomplete signal); required API tests fail loudly on real regressions. | +| secret-scanning | That the auto-generated secret-scanning patterns reference page exists and renders without crashing on malformed URLs. | Live local server on :4000; version-specific YAML pattern data. | **Medium**: reds block critical docs, but e2e can flake on server startup. | +| shielding | Detection/blocking of malicious HTTP requests: honeypotting, malformed URLs, bad query strings/headers, junk paths, and XSS/open-redirect attempts. | Local server via e2e helpers; observability/frame middleware. | **High**: broken here = compromised prod abuse/XSS protection. Security boundary. | +| versions | The product versioning system: which versions exist and how version-based content rendering works. | Schema validation + Liquid rendering; semver; no external services. | **High**: foundational; every page depends on it. Breakage = broken routing/unavailable docs for all. | +| webhooks | The auto-generated webhook events/payloads reference, including complex oneOf parameter structures. | Local server (getDOM); schema data synced from rest-api-description. | **Medium**: deterministic but coupled to the e2e server + externally-synced schema. | +| workflows | Unit tests for three automation scripts: GitHub Actions workflow validation, PR deploy batch commenting, and llms.txt generation. | None live; Octokit mocked. | **Low**: isolated unit tests, mocked, no live deps. | + +## Playwright suites (`.github/workflows/headless-tests.yml`) + +| Suite | Covers | Prereqs | Admin-merge risk | +|---|---|---|---| +| playwright-rendering | Client-side JS behavior: navigation, sidebar, search, platform/tool pickers, code tabs, hovercards, responsive layouts, versioning, and Liquid features. | Built app on :4000, Elasticsearch, and Chromium downloaded from a CDN. | **Medium**: real client-side regressions, but the CDN Chromium download flakes (disabled before for that). Confirm a red isn't the browser install. | +| playwright-a11y | Accessibility violations on a set of representative pages via axe-core, with and without experimental feature flags. | Local Next.js fixture server; Chromium. | **Low**: explicitly non-blocking; a red may be real a11y or an axe false positive. Doesn't gate PRs. | +| playwright-secret-scanning | Client-side accessibility and UI behavior of the secret-scanning patterns reference page. | CDN Chromium, dev server on :4000, and ES fixtures. | **Medium**: real UI/a11y regressions, but CDN Chromium flake adds noise. | + +## Lint / check workflows (PR-gating) + +These run as their own PR checks rather than through `test.yml`. Each self-documents in its workflow header comment. + +| Check | Covers | Prereqs | Admin-merge risk | +|---|---|---|---| +| lint-code | ESLint, Prettier, and TypeScript checks across the repo. | None live; runs on PR + merge group. | **Low**: deterministic; reds = real lint/type errors. | +| content-lint-markdown | Lints changed content/data markdown against the content-linter rules. | Changed files only. | **Low**: deterministic; reds = real content problems. | +| link-check-on-pr | Checks internal links in changed content files. | Changed files; internal links only. | **Low**: deterministic, internal-only; reds = real broken links. | +| package-lock-lint | Validates package-lock.json integrity. | Runs only when the lockfile changes. | **Low**: deterministic; reds = real lockfile issues. | +| orphaned-features-check | Detects feature flags no longer referenced. | Changed paths. | **Low**: deterministic; reds = real orphaned features. | +| orphaned-files-check | Detects orphaned content/asset files. | Changed paths. | **Low**: deterministic; reds = real orphaned files. | +| validate-asset-images | Validates added/changed asset images (format, size). | Changed image paths. | **Low**: deterministic; reds = real invalid images. | +| validate-openapi-check | Validates the decorated OpenAPI schema in a Docker container. | Docker build; changed OpenAPI paths. | **Medium**: deterministic logic, but Docker setup adds some infra flake surface. | +| article-api-docs | Checks the article-api docs stay in sync with the code. | Changed paths. | **Low**: deterministic; reds = docs need updating. | +| content-linter-rules-docs | Checks content-linter rule docs stay in sync with the rules. | Changed paths. | **Low**: deterministic; reds = rule docs need updating. | +| triage-unallowed-contributions | Flags PRs that change files forks aren't allowed to change. | pull_request_target; changed paths. | **Low**: deterministic guard; a red is usually a legit gate. | +| test-changed-content | Runs targeted tests for the content changed in the PR. | Local server/fixtures for changed content. | **Medium**: targeted e2e on changed content; can flake like other e2e suites. | +| zizmor | Security lint of the GitHub Actions workflows themselves. | Changed workflow files. | **Low**: deterministic; reds = real workflow security issues. | +| codeql | CodeQL static security analysis of the codebase. | Runs on PR + push; long-running. | **Medium**: real security findings, but slow and occasionally infra-flaky. | +| dont-delete-assets | Blocks PRs that delete in-use asset files. | Changed asset paths. | **Low**: deterministic guard; a red is a real deletion to justify. | +| dont-delete-features | Blocks PRs that delete in-use feature files. | Changed feature paths. | **Low**: deterministic guard; a red is a real deletion to justify. | + +## Notes + +- Adding/removing a vitest suite requires updating branch-protection required checks (see the `test.yml` header comment). +- `languages` only runs on github/docs-internal (needs private translation repos). +- Some lint/checks also run on a schedule (full-repo link checks, full content/data markdown lint). Those don't gate PRs, so they're omitted here. From 092dfd60461effde7b3ce5e8eb2535c163b5c20f Mon Sep 17 00:00:00 2001 From: Larissa Fortuna <56982181+lkfortuna@users.noreply.github.com> Date: Tue, 16 Jun 2026 23:33:18 -0700 Subject: [PATCH 03/12] Remove preview note for 5-vCPU macOS runner (#61771) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- content/actions/reference/runners/larger-runners.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/content/actions/reference/runners/larger-runners.md b/content/actions/reference/runners/larger-runners.md index 8012bcc14401..ad3700d5e36c 100644 --- a/content/actions/reference/runners/larger-runners.md +++ b/content/actions/reference/runners/larger-runners.md @@ -40,9 +40,7 @@ You can choose from several specifications for {% data variables.actions.hosted_ | 64 | 256 GB | 2040 GB | x64 | Ubuntu, Windows | | 96 | 384 GB | 2040 GB | x64 | Ubuntu, Windows | ->[!NOTE] The 4-vCPU Windows runner only works with the Windows Server 2025 or the Base Windows 11 Desktop image. - ->[!NOTE] The 5-vCPU macOS runner is in public preview and subject to change. +> [!NOTE] The 4-vCPU Windows runner only works with the Windows Server 2025 or the Base Windows 11 Desktop image. ### Specifications for GPU {% data variables.actions.hosted_runners %} From 4f55fde16c088068d700ed66ea650c279fb5c758 Mon Sep 17 00:00:00 2001 From: hubwriter Date: Wed, 17 Jun 2026 08:22:40 +0100 Subject: [PATCH 04/12] Copilot CLI: Update CLI config documentation with new details (#61763) --- .../cli-config-dir-reference.md | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/content/copilot/reference/copilot-cli-reference/cli-config-dir-reference.md b/content/copilot/reference/copilot-cli-reference/cli-config-dir-reference.md index 4a02065d15a7..e5c16a5524c3 100644 --- a/content/copilot/reference/copilot-cli-reference/cli-config-dir-reference.md +++ b/content/copilot/reference/copilot-cli-reference/cli-config-dir-reference.md @@ -26,6 +26,7 @@ The `~/.copilot` directory contains the following top-level items. | `agents/` | Directory | Personal custom agent definitions | | `config.json` | File | Automatically managed application state (authentication, installed plugins, and other internal data) | | `copilot-instructions.md` | File | Personal custom instructions (applied to all sessions) | +| `extensions/` | Directory | Personal extensions loaded by the CLI | | `hooks/` | Directory | User-level hook scripts | | `ide/` | Directory | IDE integration state | | `installed-plugins/` | Directory | Installed plugin files | @@ -33,6 +34,8 @@ The `~/.copilot` directory contains the following top-level items. | `logs/` | Directory | Session log files | | `lsp-config.json` | File | User-level LSP server definitions | | `mcp-config.json` | File | User-level MCP server definitions | +| `mcp-oauth-config/` | Directory | MCP OAuth token and registration fallback storage | +| `mcp-secrets/` | Directory | Local fallback storage and index for MCP secret placeholders | | `permissions-config.json` | File | Saved tool and directory permissions per project | | `plugin-data/` | Directory | Persistent data for installed plugins | | `session-state/` | Directory | Session history and workspace data | @@ -100,6 +103,12 @@ Store user-level hook scripts here. These hooks apply to all your sessions. You For more information, see [AUTOTITLE](/copilot/how-tos/copilot-cli/customize-copilot/use-hooks). +### `extensions/` + +Store user-level extension files here. Extensions in this directory are available across sessions. + +You can create files in this directory manually, or scaffold an extension and then edit the generated file. + ## Automatically managed files The following items are managed by the CLI. You generally should not edit them manually. @@ -138,6 +147,10 @@ If you delete this file, you can rebuild it using the `/chronicle reindex` comma Contains log files for CLI sessions. Each session creates a log file named `process-{timestamp}-{pid}.log`. These files are useful for debugging issues. +The CLI may also create extension-specific logs under `logs/extensions/`. + +This is separate from `~/.copilot/extensions/`, which stores user-authored extension code. + > [!TIP] > To find the log file for your current session, enter `/session` in an interactive session. The output includes the full path to the log file, along with other session details such as the session ID, duration, and working directory. @@ -155,6 +168,14 @@ Contains persistent data for installed plugins, organized by marketplace and plu Contains lock files and state for IDE integrations (for example, when {% data variables.copilot.copilot_cli_short %} connects to {% data variables.product.prodname_vscode %}). This directory is automatically managed. +### `mcp-oauth-config/` + +Contains MCP OAuth token, registration, and PKCE fallback files when keychain-backed storage is unavailable. This directory is automatically managed. + +### `mcp-secrets/` + +Contains fallback file storage and an index for MCP secret placeholders when keychain-backed storage is unavailable. This directory is automatically managed. + ## Changing the location of the configuration directory To override the default `~/.copilot` location, set the `COPILOT_HOME` environment variable to the path of the directory you want to use. @@ -181,10 +202,13 @@ To override the default `~/.copilot` location, set the `COPILOT_HOME` environmen | `agents/`, `skills/`, `hooks/` | Not recommended | You will lose your personal customizations. Back up first. | | `config.json` | With caution | Resets application state including authentication. You will need to re-authenticate and the CLI will re-detect internal state on next launch. | | `copilot-instructions.md`, `instructions/` | Not recommended | You will lose your personal custom instructions. Back up first. | +| `extensions/` | Not recommended | You will lose your personal extensions. Back up first. | | `installed-plugins/` | Not recommended | Use `copilot plugin uninstall` instead, to ensure plugin metadata in `config.json` remains accurate. | | `logs/` | Yes | Log files are re-created each session. Deleting them has no functional impact. | | `lsp-config.json` | Not recommended | You will lose your user-level LSP server definitions. Back up first. | | `mcp-config.json` | Not recommended | You will lose your user-level MCP server definitions. Back up first. | +| `mcp-oauth-config/` | With caution | Clears local MCP OAuth fallback state. You may need to re-authenticate MCP servers. | +| `mcp-secrets/` | With caution | Clears local MCP secret fallback state and mappings. Secret-backed MCP servers may need reconfiguration. | | `permissions-config.json` | With caution | Resets all saved permissions. The CLI will prompt you again for tool and directory approvals. | | `plugin-data/` | Yes | Plugin persistent data is re-created as needed. | | `session-state/` | With caution | Deleting removes session history. You will no longer be able to resume past sessions. | @@ -202,6 +226,8 @@ Settings cascade from user to repository to local, with more specific scopes ove | Repository | `.github/copilot/settings.json` | Shared repository configuration (committed to the repository). | | Local | `.github/copilot/settings.local.json` | Personal overrides (add this to `.gitignore`). | +The CLI also reads `.claude/settings.json` and `.claude/settings.local.json` for the shared cross-tool subset of repository settings (such as `companyAnnouncements`, `disableAllHooks`, `enabledPlugins`, `extraKnownMarketplaces`, and `hooks`). + ### User settings (`~/.copilot/settings.json`) These settings apply across all your sessions and repositories. You can use the `/settings` slash command to run an interactive dialog, or use specific slash commands to update individual values, or edit this file directly. @@ -215,9 +241,10 @@ These settings apply across all your sessions and repositories. You can use the | `banner` | `"always"` \| `"once"` \| `"never"` | `"once"` | Animated banner display frequency. | | `bashEnv` | `boolean` | `false` | Enable `BASH_ENV` support for bash shells. Can also be set with `--bash-env` or `--no-bash-env`. | | `beep` | `boolean` | `true` | Play an audible beep when attention is required. | +| `beepOnSchedule` | `boolean` | `true` | Play an audible beep when a scheduled `/every` or `/after` run finishes. | | `builtInAgents.rubberDuck` | `boolean` | `true` | Enable the rubber-duck subagent that provides adversarial feedback on agent plans. | | `builtInAgents.rubberDuckAutoInvoke` | `boolean` | `false` | Include proactive prompting for automatic rubber-duck invocation. Set to `true` to opt into additional rubber-duck nudges during agent turns. | -| `colorMode` | `"default"` \| `"dim"` \| `"high-contrast"` \| `"colorblind"` | `"default"` | Color contrast mode. Managed by the `/theme` slash command. | +| `colorMode` | `"default"` \| `"github"` \| `"dim"` \| `"high-contrast"` \| `"colorblind"` | `"default"` | Color contrast mode. Managed by the `/settings` and `/theme` slash commands. | | `compactPaste` | `boolean` | `true` | Collapse large pastes (more than 10 lines) into compact tokens. | | `companyAnnouncements` | `string[]` | `[]` | Custom messages shown randomly on startup. One message is randomly selected each time the CLI starts. Useful for team announcements or reminders. | | `continueOnAutoMode` | `boolean` | `false` | Automatically switch to auto mode when rate-limited. When `true`, eligible rate limit errors trigger an automatic switch to auto mode and retry. Does not apply to global rate limits or BYOK providers. | @@ -232,7 +259,7 @@ These settings apply across all your sessions and repositories. You can use the | `enabledPlugins` | `Record` | `{}` | Declarative plugin auto-install. Keys are plugin specs; values are `true` (enabled) or `false` (disabled). | | `experimental` | `boolean` | `false` | Enable experimental features. Can also be enabled with the `--experimental` command-line option or the `/experimental` slash command. | | `extraKnownMarketplaces` | `Record` | `{}` | Additional plugin marketplaces. Each key is a marketplace name; the value specifies the source (`"directory"`, `"git"`, or `"github"`). | -| `footer` | `object` | — | Controls which items appear in the status line. Sub-keys: `showModelEffort`, `showDirectory`, `showBranch`, `showContextWindow`, `showQuota`, `showAgent` (all `boolean`). Managed by the `/statusline` slash command. | +| `footer` | `object` | — | Controls which items appear in the status line. Sub-keys include `showModelEffort`, `showDirectory`, `showBranch`, `showContextWindow`, `showQuota`, `showAgent`, `showAiUsed`, `showCodeChanges`, `showUsername`, `showSandbox`, `showYolo`, and `showCustom` (all `boolean`). Managed by the `/statusline` slash command. | | `hooks` | `object` | — | Inline user-level hook definitions, keyed by event name. Uses the same schema as `.github/hooks/*.json` files. See [AUTOTITLE](/copilot/how-tos/copilot-cli/customize-copilot/use-hooks). | | `ide.autoConnect` | `boolean` | `true` | Automatically connect to an IDE workspace on startup. When `false`, you can still connect manually using the `/ide` command. | | `ide.openDiffOnEdit` | `boolean` | `true` | Open file edit diffs in the connected IDE for approval. When `false`, file edit approvals are shown only in the terminal. | From a0d4afdedabcc85dd91c9e1e3f84824233a0aceb Mon Sep 17 00:00:00 2001 From: Sophie <29382425+sophietheking@users.noreply.github.com> Date: Wed, 17 Jun 2026 10:04:22 +0200 Subject: [PATCH 05/12] Address confusion around cost center budgets and ULBs (#61756) Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../billing/budgets-for-usage-based-billing.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) 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 16e3c878e129..7919a32f0b5e 100644 --- a/content/copilot/concepts/billing/budgets-for-usage-based-billing.md +++ b/content/copilot/concepts/billing/budgets-for-usage-based-billing.md @@ -34,7 +34,7 @@ For a complete view of all licensed users regardless of activity, use the **AI u ### Cost center budget -A cost center budget caps metered charges for a defined group of users or an organization. It does not limit how much a team draws from the pool. It is only active after the shared pool is exhausted. +A cost center budget caps metered charges for a defined group of users or an organization. It does not limit how much a team draws from the pool. It is only active after the shared pool is exhausted. A cost center budget **does not extend or override a user-level budget**: if a user has reached their user-level budget, they are blocked even if their cost center still has remaining budget. When a cost center's budget is exhausted, only users in that cost center are blocked. Other users and cost centers are unaffected. @@ -74,7 +74,7 @@ When someone in your enterprise uses {% data variables.product.prodname_copilot_ Each request for an {% data variables.product.prodname_ai_credit_singular %}-consuming feature goes through these checks: -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. **User-level budget check.** The system first checks whether the user has exceeded their user-level budget. If yes, the request is blocked immediately. ULBs are always a hard stop, and no other budget can override or supplement them. 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, organization, or enterprise check.** For metered usage, the system checks budgets in the following order: @@ -89,13 +89,15 @@ Each request for an {% data variables.product.prodname_ai_credit_singular %}-con ## How user-level budgets and spending limits interact -User-level budgets and spending limits are independent controls that serve different purposes. User-level budgets control how much each person can consume. Spending limits control how much metered usage your organization will pay for. +User-level budgets and spending limits are independent controls that serve different purposes. ULBs control how much each person can consume. Spending limits control how much metered usage your organization will pay for. -If these are not aligned, users can get blocked unexpectedly. The system applies a "lowest remaining headroom wins" rule: whichever budget has the least capacity remaining blocks the user first, regardless of what other budgets still have available. For example, if a user has $5 USD remaining on their individual user-level budget but the enterprise budget only has $1 USD remaining, the enterprise budget blocks them—even though their personal budget isn't exhausted. +If these are not aligned, users can get blocked unexpectedly. The system applies a "lowest remaining headroom wins" rule: whichever budget has the least capacity remaining blocks the user first, regardless of what other budgets still have available. For example, if a user has $5 USD remaining on their individual ULB but the enterprise budget only has $1 USD remaining, the enterprise budget blocks them, even though their personal budget isn't exhausted. -This means that if your user-level budgets collectively allow more consumption than the shared pool provides, the difference spills over into metered charges. If your enterprise budget is too low to cover that gap, users get blocked before they reach their individual limits. +This means that if your ULBs collectively allow more consumption than the shared pool provides, the difference spills over into metered charges. If your enterprise budget is too low to cover that gap, users get blocked before they reach their individual limits. -When you raise user-level budgets, check that your spending limits can still cover the resulting gap. +When you raise ULBs, check that your spending limits can still cover the resulting gap. + +The reverse is also true: raising a cost center or enterprise budget does not unblock a user who has hit their ULB. For example, if a user exhausts their $5 USD ULB at the same moment the shared pool runs out, they cannot consume from any remaining cost center budget, even if that cost center has $10 USD remaining. The ULB is a total cap on that user's consumption across both pool and metered phases. To unblock them, you must raise their individual ULB or increase the universal ULB. ## Cost center exclusion From 8643d8816c32ac71970656c5e0c8b355870035ec Mon Sep 17 00:00:00 2001 From: Sophie <29382425+sophietheking@users.noreply.github.com> Date: Wed, 17 Jun 2026 10:20:26 +0200 Subject: [PATCH 06/12] Review and improve 'Supported AI models' article (#61762) Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../reference/ai-models/supported-models.md | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/content/copilot/reference/ai-models/supported-models.md b/content/copilot/reference/ai-models/supported-models.md index 7c65edaa375c..c8988cc5fd33 100644 --- a/content/copilot/reference/ai-models/supported-models.md +++ b/content/copilot/reference/ai-models/supported-models.md @@ -21,13 +21,12 @@ redirect_from: contentType: reference --- -{% data variables.product.prodname_copilot %} supports multiple models, each with different strengths. Some models prioritize speed and cost-efficiency, while others are optimized for accuracy, reasoning, or working with multimodal inputs (like images and code together). +{% data variables.product.prodname_copilot %} supports multiple AI models, each with different strengths. Some prioritize speed and cost-efficiency, while others are optimized for accuracy, reasoning, or multimodal inputs. The right model depends on your task. For a side-by-side comparison to help you choose, see [AUTOTITLE](/copilot/reference/ai-models/model-comparison). -Depending on your {% data variables.product.prodname_copilot_short %} plan and where you're using it—such as {% data variables.product.prodname_dotcom_the_website %} or an IDE—you may have access to different models. +The models available to you depend on your {% data variables.product.prodname_copilot_short %} plan and where you're using {% data variables.product.prodname_copilot_short %}, such as {% data variables.product.prodname_dotcom_the_website %} or an IDE. > [!NOTE] -> * Model availability is subject to change. Some models may be replaced or updated over time. -> * In {% data variables.product.prodname_vscode %} you can add more models than those that are available by default with your {% data variables.product.prodname_copilot_short %} subscription. See [AUTOTITLE](/copilot/how-tos/use-ai-models/change-the-chat-model?tool=vscode#adding-more-models). +> Model availability is subject to change. Some models may be replaced or updated over time. For all of the default AI models, input prompts and output completions run through {% data variables.product.prodname_copilot %}'s content filters for harmful, offensive, or off-topic content, and for public code matching when enabled. @@ -118,6 +117,9 @@ The following table shows which models are available in each client. {% endrowheaders %} +> [!NOTE] +> In {% data variables.product.prodname_vscode %} you can add more models than those that are available by default with your {% data variables.product.prodname_copilot_short %} subscription. See [AUTOTITLE](/copilot/how-tos/use-ai-models/change-the-chat-model?tool=vscode#adding-more-models). + ## Minimum IDE versions for recent models Some {% data variables.product.prodname_copilot_short %} models require minimum versions of supported IDEs or {% data variables.product.prodname_copilot_short %} extensions or plugins. The table below lists the minimum versions known from changelog entries or provided release guidance. This information is tentative and subject to change as model support rolls out. For best results, keep your IDE and {% data variables.product.prodname_copilot_short %} extension or plugin updated to the latest available version. @@ -152,18 +154,22 @@ The following table shows which AI models are available in each {% data variable {% data reusables.copilot.available-models-per-plan %} +> [!NOTE] +> If you're an organization or enterprise owner, you can enable or restrict access to specific models for your members. See [AUTOTITLE](/copilot/how-tos/copilot-on-github/set-up-copilot/configure-access-to-ai-models#setup-for-organization-and-enterprise-use). + ## Fallback and long-term support (LTS) models For more information about fallback and LTS models, see [AUTOTITLE](/copilot/concepts/fallback-and-lts-models). ## Evaluation models + {% data variables.product.prodname_copilot %} offers access to evaluation models. > [!IMPORTANT] > * Testing revealed evaluation models may perform worse than other models on security-related, or other categories of prompts. > * Users should always carefully review and validate code, including code security, using a range of models and with a thorough human review before incorporating suggestions into production. -Evaluation models may appear in product with codenames rather than official model or provider names. These models come from, or are fine-tuned by, one or more of the following providers: Microsoft, OpenAI, Anthropic, Google. Data handling for each provider is limited to GitHub's existing agreement with that provider, and evaluation models undergo GitHub and Microsoft testing and verification before release. +Evaluation models may appear in the product with codenames rather than official model or provider names. These models come from or are fine-tuned by one or more of the following providers: Microsoft, OpenAI, Anthropic, and Google. Data handling for each provider is limited to {% data variables.product.github %}'s existing agreement with that provider, and evaluation models undergo {% data variables.product.github %} and Microsoft testing and verification before release. Evaluation models may be added, updated, or removed without notice. Availability and rate limits may differ from generally available models. @@ -183,8 +189,6 @@ Utility models power background features across surfaces, and cannot be disabled ## Next steps -* For task-based guidance on selecting a model, see [AUTOTITLE](/copilot/reference/ai-models/model-comparison). -* To configure which models are available to you, see [AUTOTITLE](/copilot/using-github-copilot/ai-models/configuring-access-to-ai-models-in-copilot). -* To learn how to change your current model, see [AUTOTITLE](/copilot/using-github-copilot/ai-models/changing-the-ai-model-for-copilot-chat) or [AUTOTITLE](/copilot/how-tos/use-ai-models/change-the-completion-model). +* To get up and running with {% data variables.product.prodname_copilot_short %}, see [AUTOTITLE](/copilot/get-started/quickstart). +* To configure which models are available to you, see [AUTOTITLE](/copilot/how-tos/copilot-on-github/set-up-copilot/configure-access-to-ai-models). * To learn more about Responsible Use and Responsible AI, see [{% data variables.product.prodname_copilot_short %} Trust Center](https://copilot.github.trust.page/) and [AUTOTITLE](/copilot/responsible-use-of-github-copilot-features). -* To learn how {% data variables.copilot.copilot_chat_short %} serves different AI models, see [AUTOTITLE](/copilot/reference/ai-models/model-hosting). From 647918f8571094d3b2d73e38bdd1bdf050b8bfe6 Mon Sep 17 00:00:00 2001 From: docs-bot <77750099+docs-bot@users.noreply.github.com> Date: Wed, 17 Jun 2026 01:45:18 -0700 Subject: [PATCH 07/12] docs: update copilot-cli content from source docs (#61744) Co-authored-by: github-actions[bot] Co-authored-by: hubwriter Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../cli-command-reference.md | 8 +++- .../cli-config-dir-reference.md | 2 + .../cli-plugin-reference.md | 1 + content/copilot/reference/hooks-reference.md | 39 ++++++++++++------- src/content-pipelines/state/copilot-cli.sha | 2 +- 5 files changed, 35 insertions(+), 17 deletions(-) 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 78cecac225e3..2a717c770796 100644 --- a/content/copilot/reference/copilot-cli-reference/cli-command-reference.md +++ b/content/copilot/reference/copilot-cli-reference/cli-command-reference.md @@ -165,6 +165,7 @@ When diff mode is open (entered via `/diff`): | `c` | Add or edit a comment on the selected line. | | `s` | Show comments summary (when comments exist). | | `b` | Toggle between unstaged changes and branch diff. | +| `w` | Toggle hiding whitespace-only changes. | | Enter | Submit all comments (when comments exist). | | `r` | Refresh the diff (remote sessions only). | | Esc / Ctrl+C | Exit diff mode. | @@ -198,6 +199,7 @@ Holding or accelerates scrolling after the first 1 | `/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). | +| `/app` | Launch the {% data variables.copilot.github_copilot_app %}, or show the download URL if the app is not installed. | | `/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). | | `/changelog [summarize] [VERSION\|last N\|since VERSION]`, `/release-notes [summarize] [VERSION\|last N\|since VERSION]` | Display the CLI changelog. Optionally specify a version, a count of recent releases, or a starting version. Add the keyword `summarize` for an AI-generated summary. | @@ -227,7 +229,7 @@ Holding or accelerates scrolling after the first 1 | `/login` | Log in to {% data variables.product.prodname_copilot_short %}. | | `/logout` | Log out of {% data variables.product.prodname_copilot_short %}. | | `/lsp [show\|test\|reload\|help] [SERVER-NAME]` | Manage the language server configuration. | -| `/mcp [show\|add\|edit\|delete\|disable\|enable\|auth\|reload] [SERVER-NAME]` | Manage the MCP server configuration. See [AUTOTITLE](/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers#managing-mcp-servers). | +| `/mcp [show\|add\|edit\|delete\|disable\|enable\|auth\|reload\|search] [SERVER-NAME]` | Manage the MCP server configuration. See [AUTOTITLE](/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers#managing-mcp-servers). | | `/model`, `/models [MODEL]` | Select the AI model you want to use. | | `/permissions [show\|reset]` | View or clear in-memory tool and path approvals for the current session. | | `/plan [PROMPT]` | Create an implementation plan before coding. | @@ -243,16 +245,18 @@ Holding or accelerates scrolling after the first 1 | `/rubber-duck [PROMPT]` | Consult the rubber duck agent for a second opinion on plans, code, and tests. See [AUTOTITLE](/copilot/concepts/agents/copilot-cli/rubber-duck). | | `/sandbox [enable\|disable]` | Configure shell command sandboxing. | | `/search [QUERY]`, `/find [QUERY]` | Search the conversation timeline. {% data reusables.copilot.experimental %} | +| `/security-review [PROMPT]` | Run the security review agent to analyze changes for vulnerabilities. | | `/session [info\|checkpoints [n]\|files\|plan\|rename [NAME]\|cleanup\|prune\|delete [ID]\|delete-all]`, `/sessions [info\|checkpoints [n]\|files\|plan\|rename [NAME]\|cleanup\|prune\|delete [ID]\|delete-all]` | Show session information and manage sessions. The `info` subcommand shows session details including the session link (when available). Subcommands: `info`, `checkpoints`, `files`, `plan`, `rename`, `cleanup`, `prune`, `delete`, `delete-all`. | | `/settings [show\|[KEY VALUE]\|reset KEY]` | Open the settings dialog, set a setting inline with a KEY and VALUE, or reset a setting to its default. See [AUTOTITLE](/copilot/reference/copilot-cli-reference/cli-config-dir-reference#configuration-file-settings). | | `/share [file\|html\|gist] [session\|research] [PATH]`, `/export [file\|html\|gist] [session\|research] [PATH]` | Share the session to a Markdown file, interactive HTML file, or {% data variables.product.github %} gist. | | `/skills [list\|info\|add\|remove\|reload] [ARGS...]` | Manage skills for enhanced capabilities. See [AUTOTITLE](/copilot/how-tos/copilot-cli/customize-copilot/create-skills). | | `/statusline`, `/footer` | Configure which items appear in the status line. | +| `/subagents`, `/agents` | Configure default and per-agent subagent models. See [AUTOTITLE](/copilot/reference/copilot-cli-reference/cli-config-dir-reference#configuration-file-settings). | | `/tasks` | View and manage tasks (subagents and shell commands). | | `/terminal-setup` | Configure the terminal for multiline input support (Shift+Enter and Ctrl+Enter). | | `/theme [default\|dim\|high-contrast\|colorblind]` | View or set the color mode. | | `/tuikit [colors\|icons\|select\|tabbar]` | Preview TUIkit design-system components and color tokens. | -| `/undo`, `/rewind` | Rewind the last turn and revert file changes. | +| `/undo`, `/rewind` | Rewind the last turn and revert file changes. File tracking is done via the tool layer and does not require Git. | | `/update`, `/upgrade` | Update the CLI to the latest version. | | `/usage` | Display session usage metrics and statistics. | | `/user [show\|list\|switch]` | Manage the current {% data variables.product.github %} user. | diff --git a/content/copilot/reference/copilot-cli-reference/cli-config-dir-reference.md b/content/copilot/reference/copilot-cli-reference/cli-config-dir-reference.md index e5c16a5524c3..29682ca74a37 100644 --- a/content/copilot/reference/copilot-cli-reference/cli-config-dir-reference.md +++ b/content/copilot/reference/copilot-cli-reference/cli-config-dir-reference.md @@ -282,6 +282,8 @@ These settings apply across all your sessions and repositories. You can use the | `storeTokenPlaintext` | `boolean` | `false` | Allow authentication tokens to be stored in plain text in `config.json` when no system keychain is available. | | `stream` | `boolean` | `true` | Enable streaming responses. | | `streamerMode` | `boolean` | `false` | Hide preview model names and quota details. Useful when demonstrating {% data variables.copilot.copilot_cli_short %} or screen sharing. | +| `subagents.agents` | `object` | `{}` | Per-agent model configuration, keyed by agent name. Each value is an object with optional `model` (string), `effortLevel` (string), and `contextTier` (`"default"`, `"long_context"`, or `"inherit"`) fields. Set any field to `"inherit"` to use the parent session's value at dispatch time. Use the `/subagents` slash command to configure these settings interactively. | +| `subagents.disabledSubagents` | `string[]` | `[]` | Agent names to prevent from being dispatched. The `explore`, `task`, and `rubber-duck` agents cannot be disabled. | | `tabs.enabled` | `boolean` | `true` | Show the home tab bar. Set to `false` to hide it entirely. | | `tabs.hide` | `string[]` | `[]` | Tab identifiers to hide. Accepted values: `"copilot"`, `"agents"`, `"issues"`, `"pull-requests"`, `"gists"` (matched case-insensitively). | | `tabs.sort` | `string[]` | `[]` | Order in which tabs are displayed. Tabs not listed keep their default relative order after the listed ones. Unknown identifiers are ignored. | diff --git a/content/copilot/reference/copilot-cli-reference/cli-plugin-reference.md b/content/copilot/reference/copilot-cli-reference/cli-plugin-reference.md index cd6e4f93634d..9134bb67df74 100644 --- a/content/copilot/reference/copilot-cli-reference/cli-plugin-reference.md +++ b/content/copilot/reference/copilot-cli-reference/cli-plugin-reference.md @@ -77,6 +77,7 @@ These tell the CLI where to find your plugin's components. All are optional. The | `skills` | string \| string[] | `skills/` | Path(s) to skill directories (`SKILL.md` files). | | `commands` | string \| string[] | — | Path(s) to command directories. | | `hooks` | string \| object | — | Path to a hooks config file, or an inline hooks object. | +| `extensions`| string \| string[] \| object | — | Path(s) to extension directories. Use `{ paths: [...], exclusive: true }` to suppress built-in extensions. | | `mcpServers`| string \| object | — | Path to an MCP config file (e.g., `.mcp.json`), or inline server definitions. | | `lspServers`| string \| object | — | Path to an LSP config file, or inline server definitions. | diff --git a/content/copilot/reference/hooks-reference.md b/content/copilot/reference/hooks-reference.md index 3b931dab5e87..5dad6354ab14 100644 --- a/content/copilot/reference/hooks-reference.md +++ b/content/copilot/reference/hooks-reference.md @@ -93,10 +93,10 @@ Command hooks run shell scripts and are supported on all hook types. "preToolUse": [ { "type": "command", - "bash": "your-bash-command", - "powershell": "your-powershell-command", - "cwd": "optional/working/directory", - "env": { "VAR": "value" }, + "bash": "YOUR_BASH_COMMAND", + "powershell": "YOUR_POWERSHELL_COMMAND", + "cwd": "OPTIONAL/WORKING/DIRECTORY", + "env": { "VAR": "VALUE" }, "timeoutSec": 30 } ] @@ -194,7 +194,7 @@ Prompt hooks auto-submit text as if the user typed it. They are only supported o "sessionStart": [ { "type": "prompt", - "prompt": "Your prompt text or /slash-command" + "prompt": "YOUR_PROMPT_TEXT_OR_SLASH_COMMAND" } ] } @@ -214,15 +214,15 @@ The table below lists every supported event. The **Cloud agent** column shows wh |-------|-----------|------------------|-------------| | `agentStop` | The main agent finishes a turn. | Yes — can block and force continuation. | Fires. `decision: "block"` forces another turn, which still counts against the job's timeout. | | `errorOccurred` | An error occurs during execution. | No | Fires. | -| `notification` | Fires asynchronously when the CLI emits a system notification (shell completion, agent completion or idle, permission prompts, elicitation dialogs). Fire-and-forget: never blocks the session. Supports `matcher` regex on `notification_type`. | Optional — can inject `additionalContext` into the session. | **Does not fire.** Cloud agent does not surface notifications to a user (see the **Interactivity** row in the Cloud agent execution environment table above). | -| `permissionRequest` | Fires before the permission service runs (rules engine, session approvals, auto-allow/auto-deny, and user prompting). If the merged hook output returns `behavior: "allow"` or `"deny"`, that decision short-circuits the normal permission flow. Supports `matcher` regex on `toolName`. | Yes — can allow or deny programmatically. | Tool calls are pre-approved, so this hook either does not fire or has no effect. Use `preToolUse` to make permission decisions instead. | +| `notification` | Fires asynchronously when the CLI emits a system notification (shell completion, agent completion or idle, permission prompts, elicitation dialogs). Fire-and-forget: never blocks the session. Supports a `matcher` regex pattern (the value of the `matcher` field) on `notification_type`. | Optional — can inject `additionalContext` into the session. | **Does not fire.** Cloud agent does not surface notifications to a user (see the **Interactivity** row in the Cloud agent execution environment table above). | +| `permissionRequest` | Fires before the permission service runs (rules engine, session approvals, auto-allow/auto-deny, and user prompting). If the merged hook output returns `behavior: "allow"` or `"deny"`, that decision short-circuits the normal permission flow. Supports a `matcher` regex pattern (the value of the `matcher` field) on `toolName`. | Yes — can allow or deny programmatically. | Tool calls are pre-approved, so this hook either does not fire or has no effect. Use `preToolUse` to make permission decisions instead. | | `postToolUse` | After each tool completes successfully. | Yes — can modify the tool result or inject additional context for the model. | Fires. | | `postToolUseFailure` | After a tool completes with a failure. | Yes — can provide recovery guidance via `additionalContext` (exit code `2` for command hooks). | Fires. | -| `preCompact` | Context compaction is about to begin (manual or automatic). Supports `matcher` to filter by trigger (`"manual"` or `"auto"`). | No — notification only. | Fires only with `trigger: "auto"`. There is no user to request manual compaction. | +| `preCompact` | Context compaction is about to begin (manual or automatic). Supports a `matcher` regex pattern (the value of the `matcher` field) to filter by trigger (`"manual"` or `"auto"`). | No — notification only. | Fires only with `trigger: "auto"`. There is no user to request manual compaction. | | `preToolUse` | Before each tool executes. | Yes — can allow, deny, or modify. | Fires. A decision of `"ask"` is treated as `"deny"` because no user is available to answer. | | `sessionEnd` | The session terminates. | No | Fires once per job. `reason` is typically `"complete"`, `"error"`, or `"timeout"`; `"abort"` and `"user_exit"` are not expected because there is no user. | | `sessionStart` | A new or resumed session begins. | Optional — can inject `additionalContext` into the session. | Fires once per job, as a new session (not a resume). See the Prompt hooks note above for the behavior of `prompt` entries under cloud agent. | -| `subagentStart` | A subagent is spawned (before it runs). Supports `matcher` to filter by agent name. | Optional — cannot block creation, but `additionalContext` is prepended to the subagent's prompt. | Fires. | +| `subagentStart` | A subagent is spawned (before it runs). Supports a `matcher` regex pattern (the value of the `matcher` field) to filter by agent name. | Optional — cannot block creation, but `additionalContext` is prepended to the subagent's prompt. | Fires. | | `subagentStop` | A subagent completes. | Yes — can block and force continuation. | Fires. | | `userPromptSubmitted` | The user submits a prompt. | No | Fires at most once, for the prompt supplied to the job. There is no follow-up user input. | @@ -341,9 +341,9 @@ 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. +* `*`, `**`, or an empty `matcher` value 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). +* 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`). @@ -614,6 +614,16 @@ Return `{}` or empty output to keep the original successful result. > [!NOTE] > `modifiedResult` is honored by both SDK programmatic hooks and command/HTTP config-file `postToolUse` hooks. +**Matcher:** Optional regex tested against `toolName`. The regex pattern is the value of the `matcher` field, compiled as `^(?:PATTERN)$`, and must match the entire tool name. If the pattern is not a valid regular expression, the hook is skipped. Omit `matcher` to receive results from all tools. + +```json +{ + "type": "command", + "matcher": "bash|edit", + "bash": "./scripts/log-tool.sh" +} +``` + ## `permissionRequest` decision control > [!NOTE] @@ -623,7 +633,7 @@ The `permissionRequest` hook fires before the permission service runs—before r All configured `permissionRequest` hooks run for each request (except `read` and `hook` permission kinds, which short-circuit before hooks). Hook outputs are merged with later hook outputs overriding earlier ones. -**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. +**Matcher:** Optional regex tested against `toolName`. The regex pattern is the value of the `matcher` field, anchored as `^(?:PATTERN)$`, and 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. @@ -680,16 +690,17 @@ The `notification` hook fires asynchronously when the CLI emits a system notific If `additionalContext` is returned, the text is injected into the session as a prepended user message. This can trigger further agent processing if the session is idle. Return `{}` or empty output to take no action. -**Matcher:** Optional regex on `notification_type`. The pattern is anchored as `^(?:pattern)$`. Omit `matcher` to receive all notification types. +**Matcher:** Optional regex on `notification_type`. The regex pattern is the value of the `matcher` field, anchored as `^(?:PATTERN)$`. Omit `matcher` to receive all notification types. ## Matcher filtering -Several events accept an optional `matcher` regex on each hook entry that filters which invocations the hook fires for. The pattern is anchored as `^(?:matcher)$` and must match the full value. Invalid regexes cause the hook entry to be skipped. +Several events accept an optional `matcher` regex on each hook entry that filters which invocations the hook fires for. It is compiled as `^(?:PATTERN)$` and must match the full value. Invalid regexes cause the hook entry to be skipped. | Event | `matcher` is matched against | |-------|------------------------------| | `notification` | `notification_type` | | `permissionRequest` | `toolName` | +| `postToolUse` | `toolName` | | `preCompact` | `trigger` (`"manual"` or `"auto"`) | | `preToolUse` | `toolName` | | `subagentStart` | `agentName` | diff --git a/src/content-pipelines/state/copilot-cli.sha b/src/content-pipelines/state/copilot-cli.sha index c1ece678dd0e..2a3ead36bf92 100644 --- a/src/content-pipelines/state/copilot-cli.sha +++ b/src/content-pipelines/state/copilot-cli.sha @@ -1 +1 @@ -005830f576fb7f53962c8080fdd86d7a382587c6 +35dfa8c5f6900218bffb76f6b899a85a4b49534b From bc9daf4a405fbc7e4b4c785865fdc355c70ea8a2 Mon Sep 17 00:00:00 2001 From: Laura Coursen Date: Wed, 17 Jun 2026 10:02:19 +0100 Subject: [PATCH 08/12] Remove defunct docs-content-enterprise team from CODEOWNERS (#61755) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/CODEOWNERS | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e4dcd13455d9..43c2ca6b814a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -6,9 +6,5 @@ # Site Policy content/site-policy/ @github/site-policy-admins -# Enterprise -data/release-notes/**/*.yml @github/docs-content-enterprise -src/ghes-releases/lib/enterprise-dates.json @github/docs-content-enterprise - # Requires review of #actions-oidc-integration, docs-engineering/issues/1506 # content/actions/deployment/security-hardening-your-deployments/** @github/oidc From 7a720df4719737202e73f39b1df41c6bb85688b6 Mon Sep 17 00:00:00 2001 From: Kynan Ware <47394200+BagToad@users.noreply.github.com> Date: Wed, 17 Jun 2026 05:55:27 -0600 Subject: [PATCH 09/12] Add gh CLI documentation for Issues 2.0 (sub-issues, types, dependencies) (#61577) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Anne-Marie <102995847+am-stead@users.noreply.github.com> --- .../using-issues/adding-sub-issues.md | 23 +++++++ .../using-issues/browsing-sub-issues.md | 37 ++++++++++ .../using-issues/creating-an-issue.md | 62 ++++++++++++----- .../creating-issue-dependencies.md | 38 +++++++++++ .../using-issues/editing-an-issue.md | 67 +++++++++++++++++++ 5 files changed, 211 insertions(+), 16 deletions(-) diff --git a/content/issues/tracking-your-work-with-issues/using-issues/adding-sub-issues.md b/content/issues/tracking-your-work-with-issues/using-issues/adding-sub-issues.md index 57be64949fde..d161f587696d 100644 --- a/content/issues/tracking-your-work-with-issues/using-issues/adding-sub-issues.md +++ b/content/issues/tracking-your-work-with-issues/using-issues/adding-sub-issues.md @@ -45,3 +45,26 @@ You can add up to {% data variables.projects.sub-issue_limit %} sub-issues per p * Select an issue from one of the suggestions. * In the "Search issues" field, type an issue title or issue number, then click on the results. * To add issues from other repositories, click {% octicon "arrow-left" aria-label="Back to repository selection" %} next to the repository name and select a different repository. + +## Working with sub-issues using {% data variables.product.prodname_cli %} + +{% data reusables.cli.about-cli %} To learn more about {% data variables.product.prodname_cli %}, see [AUTOTITLE](/github-cli/github-cli/about-github-cli). + +To create a new issue as a sub-issue of an existing parent, use the `--parent` flag with `gh issue create`. The parent can be specified by issue number or URL. + +```shell +gh issue create --title "TITLE" --body "ISSUE-DESCRIPTION" --parent PARENT-ISSUE-NUMBER +``` + +To add existing issues as sub-issues of a parent, use the `--add-sub-issue` flag with `gh issue edit`. The flag accepts a comma-separated list of issue numbers or URLs. + +```shell +gh issue edit PARENT-ISSUE-NUMBER --add-sub-issue SUB-ISSUE-NUMBER +``` + +To remove a sub-issue from its parent, use `--remove-sub-issue` on the parent or `--remove-parent` on the sub-issue. + +```shell +gh issue edit PARENT-ISSUE-NUMBER --remove-sub-issue SUB-ISSUE-NUMBER +gh issue edit SUB-ISSUE-NUMBER --remove-parent +``` diff --git a/content/issues/tracking-your-work-with-issues/using-issues/browsing-sub-issues.md b/content/issues/tracking-your-work-with-issues/using-issues/browsing-sub-issues.md index 287f32124482..c1903afcfddf 100644 --- a/content/issues/tracking-your-work-with-issues/using-issues/browsing-sub-issues.md +++ b/content/issues/tracking-your-work-with-issues/using-issues/browsing-sub-issues.md @@ -28,3 +28,40 @@ When you view a sub-issue, you can always find a link back to the parent issue i ## Using sub-issues in your projects You can add sub-issues to your projects and make use of the hierarchy data for building views, grouping items, and filtering your views. See [AUTOTITLE](/issues/planning-and-tracking-with-projects/understanding-fields/about-parent-issue-and-sub-issue-progress-fields). + +## Browsing issue hierarchy with {% data variables.product.prodname_cli %} + +{% data reusables.cli.about-cli %} To learn more about {% data variables.product.prodname_cli %}, see [AUTOTITLE](/github-cli/github-cli/about-github-cli). + +To view a parent issue along with its sub-issues, use the `gh issue view` subcommand. + +```shell +gh issue view ISSUE-NUMBER +``` + +The output includes the parent reference (if any) and a "Sub-issues" section that lists each sub-issue with its state and completion progress. + +```text +Build a scoreboard octo-org/octo-repo#123 +Feature · Open • monalisa opened 3 days ago • 2 comments +Assignees: monalisa +Labels: enhancement +Type: Feature + + + Track player scores across rounds. + + +Sub-issues · 1/3 (33%) +Closed octo-org/octo-repo#124 Design scoreboard layout +Open octo-org/octo-repo#125 Persist scores between sessions +Open octo-org/octo-repo#126 Add a leaderboard view + +View this issue on GitHub: https://github.com/octo-org/octo-repo/issues/123 +``` + +To get the same information in a machine-readable form, use the `--json` flag with the `parent`, `subIssues`, and `subIssuesSummary` fields. + +```shell +gh issue view ISSUE-NUMBER --json parent,subIssues,subIssuesSummary +``` diff --git a/content/issues/tracking-your-work-with-issues/using-issues/creating-an-issue.md b/content/issues/tracking-your-work-with-issues/using-issues/creating-an-issue.md index 12e85b1c7997..c127ae29a6bc 100644 --- a/content/issues/tracking-your-work-with-issues/using-issues/creating-an-issue.md +++ b/content/issues/tracking-your-work-with-issues/using-issues/creating-an-issue.md @@ -48,22 +48,6 @@ Issues can be used to keep track of bugs, enhancements, or other requests. For m {% data reusables.repositories.assign-an-issue-as-project-maintainer %} {% data reusables.repositories.submit-new-issue %} -## Creating an issue with {% data variables.product.prodname_cli %} - -{% data reusables.cli.about-cli %} To learn more about {% data variables.product.prodname_cli %}, see [AUTOTITLE](/github-cli/github-cli/about-github-cli). - -To create an issue, use the `gh issue create` subcommand. To skip the interactive prompts, include the `--body` and the `--title` flags. - -```shell -gh issue create --title "My new issue" --body "Here are more details." -``` - -You can also specify assignees, labels, milestones, and projects. - -```shell -gh issue create --title "My new issue" --body "Here are more details." --assignee @me,monalisa --label "bug,help wanted" --project onboarding --milestone "learning codebase" -``` - ## Creating an issue from a comment You can open a new issue from a comment in an issue or pull request. When you open an issue from a comment, the issue contains a snippet showing where the comment was originally posted. @@ -152,6 +136,52 @@ Query parameter | Example You can also use URL query parameters to fill custom text fields that you have defined in issue form templates. Query parameters for issue form fields can also be passed to the issue template chooser. For more information, see [AUTOTITLE](/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#keys). {% endif %} +## Creating an issue with {% data variables.product.prodname_cli %} + +{% data reusables.cli.about-cli %} To learn more about {% data variables.product.prodname_cli %}, see [AUTOTITLE](/github-cli/github-cli/about-github-cli). + +To create an issue, use the `gh issue create` subcommand. To skip the interactive prompts, include the `--body` and the `--title` flags. + +```shell +gh issue create --title "TITLE" --body "ISSUE-DESCRIPTION" +``` + +You can also specify assignees, labels, milestones, and projects. + +```shell +gh issue create --title "TITLE" --body "ISSUE-DESCRIPTION" --assignee @me,USERNAME --label "LABEL-1,LABEL-2" --project PROJECT-NAME --milestone "MILESTONE-NAME" +``` + +{% ifversion issue-types %} + +To set the issue type, use the `--type` flag. + +```shell +gh issue create --title "TITLE" --body "ISSUE-DESCRIPTION" --type "ISSUE-TYPE" +``` + +{% endif %} + +{% ifversion sub-issues %} + +To create the issue as a sub-issue of an existing parent, use the `--parent` flag with an issue number or URL. + +```shell +gh issue create --title "TITLE" --body "ISSUE-DESCRIPTION" --parent PARENT-ISSUE-NUMBER +``` + +{% endif %} + +{% ifversion fpt or ghec %} + +To create dependencies at the same time, use the `--blocked-by` and `--blocking` flags. Both accept a comma-separated list of issue numbers or URLs. + +```shell +gh issue create --title "TITLE" --body "ISSUE-DESCRIPTION" --blocked-by BLOCKED-BY-ISSUE-NUMBER --blocking BLOCKING-ISSUE-NUMBER +``` + +{% endif %} + {% ifversion copilot %} ## Creating an issue with {% data variables.copilot.copilot_chat_short %} on {% data variables.product.github %} diff --git a/content/issues/tracking-your-work-with-issues/using-issues/creating-issue-dependencies.md b/content/issues/tracking-your-work-with-issues/using-issues/creating-issue-dependencies.md index 186c3a08336b..b425fb86b768 100644 --- a/content/issues/tracking-your-work-with-issues/using-issues/creating-issue-dependencies.md +++ b/content/issues/tracking-your-work-with-issues/using-issues/creating-issue-dependencies.md @@ -32,3 +32,41 @@ Blocked issues are marked with a "Blocked" icon on your project boards or reposi * To indicate that your issue no longer depends on another issue being completed, select **Change blocked by**. * To indicate that your issue is no longer preventing another issue from being completed, select **Change blocking**. 1. In the dialog box that opens, deselect the issues that are no longer blocked by, or blocking, your issue. + +## Managing issue dependencies with {% data variables.product.prodname_cli %} + +{% data reusables.cli.about-cli %} To learn more about {% data variables.product.prodname_cli %}, see [AUTOTITLE](/github-cli/github-cli/about-github-cli). + +To create a new issue with dependencies, use the `--blocked-by` and `--blocking` flags on `gh issue create`. Each flag accepts a comma-separated list of issue numbers or URLs. + +```shell +gh issue create --title "TITLE" --body "ISSUE-DESCRIPTION" --blocked-by BLOCKED-BY-ISSUE-NUMBER --blocking BLOCKING-ISSUE-NUMBER +``` + +To add or remove dependencies on an existing issue, use the corresponding flags on `gh issue edit` with the issue number or URL. + +```shell +gh issue edit ISSUE-NUMBER --add-blocked-by BLOCKED-BY-ISSUE-NUMBER --add-blocking BLOCKING-ISSUE-NUMBER +gh issue edit ISSUE-NUMBER --remove-blocked-by BLOCKED-BY-ISSUE-NUMBER --remove-blocking BLOCKING-ISSUE-NUMBER +``` + +To see an issue's dependencies, use `gh issue view`. The output includes "Blocked by" and "Blocking" rows when relationships are set. + +```text +My new issue octo-org/octo-repo#123 +Open • monalisa opened 3 days ago • 0 comments +Blocked by: octo-org/octo-repo#200 Database schema migration +Blocking: octo-org/octo-repo#300 Release v2.0 + + + Here are more details. + + +View this issue on GitHub: https://github.com/octo-org/octo-repo/issues/123 +``` + +You can also access dependencies programmatically with the `--json` flag using the `blockedBy` and `blocking` fields. + +```shell +gh issue view ISSUE-NUMBER --json blockedBy,blocking +``` diff --git a/content/issues/tracking-your-work-with-issues/using-issues/editing-an-issue.md b/content/issues/tracking-your-work-with-issues/using-issues/editing-an-issue.md index 44699b18f15a..c8638cbda326 100644 --- a/content/issues/tracking-your-work-with-issues/using-issues/editing-an-issue.md +++ b/content/issues/tracking-your-work-with-issues/using-issues/editing-an-issue.md @@ -52,6 +52,73 @@ You can add an issue type or make changes to an existing issue type. {% endif %} +## Editing an issue with {% data variables.product.prodname_cli %} + +{% data reusables.cli.about-cli %} To learn more about {% data variables.product.prodname_cli %}, see [AUTOTITLE](/github-cli/github-cli/about-github-cli). + +### Editing a single issue + +To edit an issue, use the `gh issue edit` subcommand with the issue number or URL. + +```shell +gh issue edit ISSUE-NUMBER --title "TITLE" --body "ISSUE-DESCRIPTION" +``` + +### Editing multiple issues + +You can pass multiple issue numbers to apply the same change to several issues at once. + +```shell +gh issue edit ISSUE-NUMBER-1 ISSUE-NUMBER-2 --add-label "LABEL" +``` + +{% ifversion issue-types %} + +### Editing the issue type + +To set or remove the issue type, use the `--type` or `--remove-type` flag. + +```shell +gh issue edit ISSUE-NUMBER --type "ISSUE-TYPE" +gh issue edit ISSUE-NUMBER --remove-type +``` + +{% endif %} + +{% ifversion sub-issues %} + +### Editing the parent issue + +To set or remove the parent issue, use the `--parent` or `--remove-parent` flag. The parent can be specified by issue number or URL. + +```shell +gh issue edit ISSUE-NUMBER --parent PARENT-ISSUE-NUMBER +gh issue edit ISSUE-NUMBER --remove-parent +``` + +### Editing sub-issues + +To add or remove sub-issues, use the `--add-sub-issue` or `--remove-sub-issue` flag with a comma-separated list of issue numbers or URLs. + +```shell +gh issue edit PARENT-ISSUE-NUMBER --add-sub-issue SUB-ISSUE-NUMBER +gh issue edit PARENT-ISSUE-NUMBER --remove-sub-issue SUB-ISSUE-NUMBER +``` + +{% endif %} + +{% ifversion fpt or ghec %} + +### Editing dependencies + +To manage dependencies, use the `--add-blocked-by`, `--remove-blocked-by`, `--add-blocking`, and `--remove-blocking` flags. Each accepts a comma-separated list of issue numbers or URLs. + +```shell +gh issue edit ISSUE-NUMBER --add-blocked-by BLOCKED-BY-ISSUE-NUMBER --add-blocking BLOCKING-ISSUE-NUMBER +``` + +{% endif %} + ## Further reading * [AUTOTITLE](/issues/tracking-your-work-with-issues/administering-issues/closing-an-issue) From 288a586c54b47649b3dd0c268284072ff2467699 Mon Sep 17 00:00:00 2001 From: Kevin Heis Date: Wed, 17 Jun 2026 07:32:18 -0700 Subject: [PATCH 10/12] Add workflow-generated label to workflow-failure issues (#61735) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/actions/create-workflow-failure-issue/action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/create-workflow-failure-issue/action.yml b/.github/actions/create-workflow-failure-issue/action.yml index 0e0176b89d36..8c98f7359706 100644 --- a/.github/actions/create-workflow-failure-issue/action.yml +++ b/.github/actions/create-workflow-failure-issue/action.yml @@ -89,5 +89,6 @@ runs: gh issue create \ --repo "$ISSUE_REPO" \ --label "workflow-failure" \ + --label "workflow-generated" \ --title "[Workflow Failure] $WORKFLOW_NAME" \ --body "$body" From d44594a74c7645076ed208b722b9433e1080abf8 Mon Sep 17 00:00:00 2001 From: Kevin Heis Date: Wed, 17 Jun 2026 07:32:32 -0700 Subject: [PATCH 11/12] Detect and remove orphaned data/tables files and schemas (#61738) Co-authored-by: docs-bot <77750099+docs-bot@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/orphaned-files-check.yml | 13 +- package.json | 1 + .../scripts/find-orphaned-tables.ts | 203 ++++++++++++++++++ .../tests/find-orphaned-tables.ts | 66 ++++++ 4 files changed, 279 insertions(+), 4 deletions(-) create mode 100644 src/data-directory/scripts/find-orphaned-tables.ts create mode 100644 src/data-directory/tests/find-orphaned-tables.ts diff --git a/.github/workflows/orphaned-files-check.yml b/.github/workflows/orphaned-files-check.yml index 22d757c106f5..26e320798dbf 100644 --- a/.github/workflows/orphaned-files-check.yml +++ b/.github/workflows/orphaned-files-check.yml @@ -1,6 +1,6 @@ name: 'Orphaned files check' -# **What it does**: Checks that there are no files in ./assets/ and ./data/reusables that aren't mentioned in any source file. +# **What it does**: Checks that there are no files in ./assets/, ./data/reusables, or ./data/tables that aren't mentioned in any source file. # **Why we have it**: To avoid orphans into the repo. # **Who does it impact**: Docs content. @@ -16,6 +16,7 @@ on: - 'package*.json' - src/assets/scripts/find-orphaned-assets.ts - src/content-render/scripts/reusables-cli/find/unused.ts + - src/data-directory/scripts/find-orphaned-tables.ts - src/workflows/walk-files.ts - src/languages/lib/languages.ts - .github/actions/clone-translations/action.yml @@ -67,7 +68,8 @@ jobs: # information about the npm script alias. assetFilesToRemove=$(npm run -s find-orphaned-assets) reusableFilesToRemove=$(npm run -s reusables -- find unused | grep '^data/reusables' || true) - [ -z "$assetFilesToRemove" ] && [ -z "$reusableFilesToRemove" ] && exit 0 + tableFilesToRemove=$(npm run -s find-orphaned-tables) + [ -z "$assetFilesToRemove" ] && [ -z "$reusableFilesToRemove" ] && [ -z "$tableFilesToRemove" ] && exit 0 if [ -n "$assetFilesToRemove" ]; then echo $assetFilesToRemove | xargs git rm @@ -75,6 +77,9 @@ jobs: if [ -n "$reusableFilesToRemove" ]; then echo $reusableFilesToRemove | xargs git rm fi + if [ -n "$tableFilesToRemove" ]; then + echo $tableFilesToRemove | xargs git rm + fi git status @@ -100,11 +105,11 @@ jobs: git push origin $branchname body=$(cat <<-EOM - Found with the `npm run find-orphaned-assets` and `npm run -s reusables -- find unused` scripts. + Found with the `npm run find-orphaned-assets`, `npm run -s reusables -- find unused`, and `npm run find-orphaned-tables` scripts. The orphaned files workflow file .github/workflows/orphaned-files-check.yml runs every Monday at 16:20 UTC / 8:20 PST. - 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. + If you are the first responder, please spot check some of the unused assets, reusables, and tables 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). diff --git a/package.json b/package.json index c4764c901218..4e4950b1d08b 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "enable-automerge": "tsx src/workflows/enable-automerge.ts", "find-orphaned-assets": "tsx src/assets/scripts/find-orphaned-assets.ts", "find-orphaned-features": "tsx src/data-directory/scripts/find-orphaned-features/index.ts", + "find-orphaned-tables": "tsx src/data-directory/scripts/find-orphaned-tables.ts", "find-past-built-pr": "tsx src/workflows/find-past-built-pr.ts", "find-unused-variables": "tsx src/content-linter/scripts/find-unsed-variables.ts", "fixture-dev": "cross-env ROOT=src/fixtures/fixtures npm start", diff --git a/src/data-directory/scripts/find-orphaned-tables.ts b/src/data-directory/scripts/find-orphaned-tables.ts new file mode 100644 index 000000000000..a254863b9b6a --- /dev/null +++ b/src/data-directory/scripts/find-orphaned-tables.ts @@ -0,0 +1,203 @@ +// [start-readme] +// +// Print a list of all the YAML-powered table files in ./data/tables/ that +// can't be found mentioned in any source file (content, data & code), along +// with their paired schema files. Mirrors find-orphaned-assets.ts. +// +// Tables are referenced from Liquid like: +// +// {% data tables.. %} +// {% for entry in tables.. %} +// +// so a table file `data/tables//.yml` is "used" if the string +// `tables..` appears anywhere. A deeper reference such as +// `tables...` also counts, because the file key is a +// prefix of it. +// +// [end-readme] + +import fs from 'fs' +import path from 'path' +import { pathToFileURL } from 'url' +import { program } from 'commander' +import walk from 'walk-sync' + +import walkFiles from '@/workflows/walk-files' +import languages from '@/languages/lib/languages-server' + +const TABLES_DIR = 'data/tables' +const SCHEMAS_DIR = 'src/data-directory/lib/data-schemas/tables' + +// Tables that are referenced dynamically (not via Liquid) and must never be +// flagged as orphans. Add an entry here (the dotted key, e.g. `copilot.foo`) +// if a table is loaded by code rather than mentioned in content. +const EXCEPTIONS = new Set([]) + +export type TableFile = { + // Repo-relative path to the YAML file, e.g. data/tables/copilot/model-multipliers.yml + yml: string + // Repo-relative path to the paired schema, if it exists on disk. + schema?: string + // Dotted key used in Liquid, e.g. copilot.model-multipliers + key: string +} + +function getTableFiles(): TableFile[] { + if (!fs.existsSync(TABLES_DIR)) return [] + return walk(TABLES_DIR, { includeBasePath: true, directories: false }) + .filter((filePath) => filePath.endsWith('.yml')) + .map((ymlPath) => { + const relative = path.relative(TABLES_DIR, ymlPath) + const key = relative.slice(0, -'.yml'.length).split(path.sep).join('.') + const schemaPath = path.join(SCHEMAS_DIR, relative.replace(/\.yml$/, '.ts')) + return { + yml: ymlPath, + schema: fs.existsSync(schemaPath) ? schemaPath : undefined, + key, + } + }) +} + +program + .description('Print all tables in ./data/tables/ not found in any source file') + .option('-e, --exit', 'Exit script by count of orphans (useful for CI)') + .option('-v, --verbose', 'Verbose outputs') + .option('--json', 'Output in JSON format') + .option('--exclude-translations', "Don't search in translations/") + +type MainOptions = { + json: boolean + verbose: boolean + exit: boolean + excludeTranslations: boolean +} + +// Given the table files and the contents of every source file, return the +// tables whose Liquid key is never mentioned. Pulled out of main() so it can +// be unit tested without touching the filesystem. +export function getOrphanedTables( + tables: TableFile[], + sourceContents: Iterable, +): TableFile[] { + const orphans = new Map(tables.map((table) => [table.key, table])) + for (const content of sourceContents) { + if (orphans.size === 0) break + for (const [key] of orphans) { + if (EXCEPTIONS.has(key) || content.includes(`tables.${key}`)) { + orphans.delete(key) + } + } + } + return [...orphans.values()].sort((a, b) => a.yml.localeCompare(b.yml)) +} + +// Only parse argv and run when invoked directly (e.g. via `npm run +// find-orphaned-tables`), not when imported by a test. +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { + program.parse(process.argv) + main(program.opts()) +} + +async function main(opts: MainOptions) { + const { json, verbose, exit, excludeTranslations } = opts + + const englishFiles: string[] = [] + englishFiles.push(...walkFiles(path.join(languages.en.dir, 'content'), ['.md'])) + englishFiles.push(...walkFiles(path.join(languages.en.dir, 'data'), ['.md', '.yml'])) + + const sourceFiles: string[] = [...englishFiles] + + if (!excludeTranslations) { + // Translations are often behind English. A table can still be referenced + // in a translation even when no English content references it, so we must + // search translations too. We only look at files that also exist in + // English, because translations rarely delete renamed/removed files. + const englishRelativeFiles = new Set( + englishFiles.map((englishFile) => path.relative(languages.en.dir, englishFile)), + ) + for (const [language, { dir }] of Object.entries(languages)) { + if (language === 'en') continue + if (!fs.existsSync(dir)) { + throw new Error( + `${dir} does not exist. Get around this by using the flag \`--exclude-translations\`.`, + ) + } + const languageFiles: string[] = [] + languageFiles.push(...walkFiles(path.join(dir, 'content'), ['.md'])) + languageFiles.push(...walkFiles(path.join(dir, 'data'), ['.md', '.yml'])) + sourceFiles.push( + ...languageFiles.filter((languageFile) => + englishRelativeFiles.has(path.relative(dir, languageFile)), + ), + ) + } + } + + // Tables can also be referenced from code (e.g. table-rendering helpers), so + // search src and contributing as well. Searching more files only ever marks + // a table as used, never as an orphan, so it errs on the safe side. + for (const root of ['contributing', 'src']) { + if (!fs.existsSync(root)) continue + sourceFiles.push( + ...walk(root, { + includeBasePath: true, + directories: false, + globs: ['!**/*.+(png|jpe?g|csv|graphql|json|svg)'], + }), + ) + } + + if (verbose) { + console.error(`${sourceFiles.length.toLocaleString()} source files found in total.`) + } + + const tables = getTableFiles() + if (verbose) { + console.error(`${tables.length.toLocaleString()} table files found in total.`) + } + + // Read files lazily so we can stop early once every table is accounted for. + function* readContents(): Generator { + for (const sourceFile of sourceFiles) { + yield fs.readFileSync(sourceFile, 'utf-8') + } + } + + const orphanTables = getOrphanedTables(tables, readContents()) + + // Safety net: if every table looks orphaned, the detection is almost + // certainly broken (e.g. content wasn't checked out). Refuse to suggest + // deleting everything. + if (tables.length > 0 && orphanTables.length === tables.length) { + console.error( + 'Every table was flagged as orphaned, which is almost certainly a bug. ' + + 'Refusing to output anything. Was the content checked out?', + ) + process.exit(1) + } + + if (verbose && orphanTables.length) { + console.error('The following tables are not mentioned anywhere in any source file:') + } + + if (json) { + console.log(JSON.stringify(orphanTables, undefined, 2)) + } else { + const filesToRemove: string[] = [] + for (const table of orphanTables) { + filesToRemove.push(table.yml) + if (table.schema) filesToRemove.push(table.schema) + } + for (const filePath of filesToRemove) { + console.log(filePath) + } + } + + if (verbose) { + console.error(`${orphanTables.length.toLocaleString()} orphan tables left.`) + } + + if (exit) { + process.exit(orphanTables.length) + } +} diff --git a/src/data-directory/tests/find-orphaned-tables.ts b/src/data-directory/tests/find-orphaned-tables.ts new file mode 100644 index 000000000000..b3ac92a04978 --- /dev/null +++ b/src/data-directory/tests/find-orphaned-tables.ts @@ -0,0 +1,66 @@ +import { describe, expect, test } from 'vitest' + +import { getOrphanedTables, type TableFile } from '@/data-directory/scripts/find-orphaned-tables' + +function table(key: string): TableFile { + const relative = key.split('.').join('/') + return { + key, + yml: `data/tables/${relative}.yml`, + schema: `src/data-directory/lib/data-schemas/tables/${relative}.ts`, + } +} + +describe('getOrphanedTables', () => { + const tables = [ + table('copilot.model-multipliers'), + table('copilot.copilot-matrix'), + table('rest-api-versions'), + ] + + test('flags a table that is never referenced', () => { + const sources = ['{% for entry in tables.copilot.copilot-matrix %}', 'tables.rest-api-versions'] + const orphans = getOrphanedTables(tables, sources) + expect(orphans.map((t) => t.key)).toEqual(['copilot.model-multipliers']) + }) + + test('returns the paired yml and schema paths for an orphan', () => { + const orphans = getOrphanedTables([table('copilot.model-multipliers')], ['nothing here']) + expect(orphans[0].yml).toBe('data/tables/copilot/model-multipliers.yml') + expect(orphans[0].schema).toBe( + 'src/data-directory/lib/data-schemas/tables/copilot/model-multipliers.ts', + ) + }) + + test('counts the `{% data tables.X %}` form as a reference', () => { + const orphans = getOrphanedTables( + [table('rest-api-versions')], + ['see {% data tables.rest-api-versions %} below'], + ) + expect(orphans).toHaveLength(0) + }) + + test('counts a deeper sub-key reference as using the table file', () => { + // A reference to `tables.copilot.copilot-matrix.ides` should mark the + // `copilot.copilot-matrix` file as used. + const orphans = getOrphanedTables( + [table('copilot.copilot-matrix')], + ['{% for row in tables.copilot.copilot-matrix.ides %}'], + ) + expect(orphans).toHaveLength(0) + }) + + test('does not let a longer key falsely mark a shorter, unrelated table', () => { + // `tables.copilot.annual-subscriber-model-multipliers` must NOT mark + // `copilot.model-multipliers` as used. + const orphans = getOrphanedTables( + [table('copilot.model-multipliers')], + ['{% data tables.copilot.annual-subscriber-model-multipliers %}'], + ) + expect(orphans.map((t) => t.key)).toEqual(['copilot.model-multipliers']) + }) + + test('returns nothing when there are no tables', () => { + expect(getOrphanedTables([], ['anything'])).toEqual([]) + }) +}) From a0682b4d5cfac902abcf77fadc473dc43551dd59 Mon Sep 17 00:00:00 2001 From: Kevin Heis Date: Wed, 17 Jun 2026 08:00:03 -0700 Subject: [PATCH 12/12] Require consecutive _build matches before Fastly purge (#61746) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .github/workflows/purge-fastly.yml | 36 +++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/.github/workflows/purge-fastly.yml b/.github/workflows/purge-fastly.yml index 18dc5847c24b..f60e6f96604f 100644 --- a/.github/workflows/purge-fastly.yml +++ b/.github/workflows/purge-fastly.yml @@ -38,23 +38,47 @@ jobs: - uses: ./.github/actions/node-npm-setup - - name: Wait for production to match build number + - name: Wait for production to match build commit SHA if: github.event_name != 'workflow_dispatch' + # A single /_build match only proves *one* Moda instance is serving the + # new build; others can still be mid-rollout. If we purge then, Fastly's + # soft purge serves stale-while-revalidate and may revalidate against a + # lagging instance, re-caching old content as fresh for a full TTL. So we + # require several consecutive matches to confirm the rollout has settled + # across instances before purging. run: | needs=$(git rev-parse HEAD) start_time=$(date +%s) timeout_seconds=1200 - while [[ $needs != $(curl -s --fail --retry-connrefused --retry 5 https://docs.github.com/_build) ]] + required_matches=5 + interval_seconds=10 + consecutive=0 + while [[ $consecutive -lt $required_matches ]] do if [[ $(($(date +%s) - $start_time)) -gt $timeout_seconds ]] then - echo "Production did not match the build number within $timeout_seconds seconds" + echo "Production did not reach $required_matches consecutive build matches within $timeout_seconds seconds" exit 1 fi - echo "Production is not up to date with the build commit" - sleep 10 + if [[ $needs == $(curl -s --fail --retry-connrefused --retry 5 https://docs.github.com/_build) ]] + then + consecutive=$((consecutive + 1)) + echo "Production matches the build commit ($consecutive/$required_matches)" + else + if [[ $consecutive -gt 0 ]] + then + echo "Production stopped matching the build commit; resetting consecutive count" + else + echo "Production is not up to date with the build commit" + fi + consecutive=0 + fi + if [[ $consecutive -lt $required_matches ]] + then + sleep $interval_seconds + fi done - echo "Production is up to date with the build commit" + echo "Production is up to date with the build commit ($required_matches consecutive matches)" - name: Purge Fastly edge cache per language env: