Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 30 additions & 4 deletions .github/instructions/instruction-architecture.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,36 @@ applyTo: ".github/instructions/**,.github/agents/**"

# Editing Copilot content instruction and agent files

This applies when you add, edit, or remove a Copilot instruction or shared agent file that guides how **content** (articles, data files) is written. It does **not** apply to code instructions or agents owned by the engineering team (for example `code.instructions.md`).
This applies when you add, edit, review, or remove a Copilot instruction or shared agent file that guides how **content** (articles, data files) is written. It does **not** apply to code instructions or agents owned by the engineering team (for example `code.instructions.md`).

When it applies, you **must** first read the instruction-architecture doc in full and follow it:
Content-writing guidance goes in one of two places. Decide which before writing anything.

https://github.com/github/technical-content/blob/main/contributing-to-docs/docs-work/copilot-instruction-architecture.md
## Always-on instruction files (`.github/instructions/*.instructions.md`)

Read the current version every time (from a local `github/technical-content` checkout if you have one, otherwise fetch the URL); do not rely on your memory of it, because it changes. If you cannot access it, say so and stop rather than guessing.
These load automatically into every Copilot interaction whose files match the `applyTo` pattern. Use them only for rules that apply to every content interaction, regardless of persona, task, or phase.

* Keep the always-on set that loads for content under roughly **150 discrete rules**, with a soft backstop of **~6,500 tokens**. Rule count matters more, because adherence slips as the number of instructions grows. Both are soft warnings: slightly over is fine. Run `npm run measure-instruction-budget` to see where a change lands, and report the before and after numbers.
* Front-load the most important rules. Rules earlier in a file are followed more reliably, and the order in which separate files are combined is not guaranteed.
* A rule earns a spot only if it scores well on these factors:
* **Model default gap**: The model consistently gets it wrong without the rule.
* **Breadth**: It applies to every content interaction, not just some personas, tasks, or phases.
* **Cost of missing it**: Getting it wrong causes expensive rework (wrong audience, wrong scope), not polish that is cheap to catch in review.
* **Conciseness**: It fits in one or two short, actionable rules.
* Write rules as short imperatives, not multi-paragraph explanations.

## Shared agent files (`.github/agents/`)

Writers invoke these deliberately. Each agent has its own budget (up to 30,000 characters), so guidance that is narrow, detailed, or needs room to explain goes here. There are three kinds:

* **Persona agents** target a specific audience: `builder-writer` (developers building software) and `driver-writer` (admins and decision-makers enabling developers at scale).
* **Task agents** help with a specific type of work, such as a content design plan or release notes.
* **Review agents** give a focused editing pass on existing content, such as readability.

Use agents, not skills, for docs-writing guidance. Skills can be invoked automatically and unpredictably, which undermines consistent output across the team.

## Always

* Do not duplicate guidance that already exists in another instruction file or shared agent. Check before adding.
* Keep content-writing guidance in these shared files, never in personal instructions, so it stays consistent across the team.

The reasoning behind these rules is written up for humans at https://github.com/github/technical-content/blob/main/contributing-to-docs/docs-work/copilot-instruction-architecture.md. You do not need to read it to follow them.
34 changes: 18 additions & 16 deletions .github/workflows/reviewers-docs-engineering.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
name: Reviewers - Docs Engineering
name: Add engineering PRs to review board

# **What it does**: Automatically add reviewers based on paths, but only for the docs-internal repo.
# And sets the 'engineering' label on the PR. It also edits the PR body to add a template
# for asking questions for the sake of being confident about the PRs rollout.
# **Why we have it**: So we can have reviewers automatically without getting open source notifications.
# **Who does it impact**: Docs team.
# Routes non-draft engineering PRs to the Docs & Blog Engineering PR Reviews board for triage.
# Labels each PR, so later pushes skip board work unless the PR reopens.

on:
pull_request:
Expand All @@ -19,9 +16,9 @@ on:
- '**.tsx'
- '**.scss'
- 'src/**'
- '!src/**.json' # So that Docs Engineering isn't reviewing automated pipeline data PRs
- '!src/**.yml' # So that Docs Engineering isn't reviewing automated pipeline data PRs
- '!src/**.sha' # So that Docs Engineering isn't reviewing automated pipeline data PRs
- '!src/**.json' # Docs Engineering does not triage automated pipeline data PRs.
- '!src/**.yml' # Docs Engineering does not triage automated pipeline data PRs.
- '!src/**.sha' # Docs Engineering does not triage automated pipeline data PRs.
- '.github/**'
- 'config/**'
- '.devcontainer/**'
Expand All @@ -39,7 +36,8 @@ jobs:
if: >-
${{ github.repository == 'github/docs-internal' &&
!github.event.pull_request.draft &&
!contains(github.event.pull_request.labels.*.name, 'reviewers-docs-engineering') &&
(github.event.action == 'reopened' ||
!contains(github.event.pull_request.labels.*.name, 'reviewers-docs-engineering')) &&
!contains(github.event.pull_request.labels.*.name, 'lockfile-churn-only') &&
github.event.pull_request.head.ref != 'repo-sync' }}
runs-on: ubuntu-latest
Expand All @@ -52,13 +50,13 @@ jobs:

# Detect PRs that only changed package-lock.json (no engineering source files).
# These are usually cross-platform `npm install` churn from contributors
# editing content. We comment with reset instructions instead of pulling in
# docs-engineering for review.
# editing content. We comment with reset instructions instead of adding
# them to the engineering review board.
#
# Dependabot is exempt. Its security updates for transitive dependencies
# change only the lockfile, because the dependency is not in package.json.
# Those PRs are intentional, so the reset instructions are wrong and
# suppressing the review request leaves them with no reviewer at all.
# keeping them off the board leaves them without engineering triage.
- name: Detect lockfile-only churn
id: detect
env:
Expand Down Expand Up @@ -97,15 +95,19 @@ jobs:
git push
```
If the lockfile change is intentional, remove the `lockfile-churn-only` label and request docs-engineering review.
If the lockfile change is intentional, remove the `lockfile-churn-only` label and push or reopen the PR so this workflow sends it to the engineering review board.
EOF
gh pr comment "$PR" --body-file /tmp/lockfile-churn-body.md
gh pr edit "$PR" --add-label lockfile-churn-only
- name: Add docs engineering as a reviewer
- name: Add PR to board and label
if: steps.detect.outputs.lockfile_only != 'true'
env:
GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }}
REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
uses: ./.github/actions/retry-command
with:
command: gh pr edit $PR --add-reviewer github/docs-engineering --add-label reviewers-docs-engineering
command: >-
gh project item-add 25672 --owner github --url "$PR" &&
gh api "repos/$REPO/issues/$PR_NUMBER/labels" -f 'labels[]=reviewers-docs-engineering' --silent
1 change: 1 addition & 0 deletions content/copilot/reference/ai-models/model-hosting.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Used for:
* {% data variables.copilot.copilot_gpt_6_astra %}
* {% data variables.copilot.copilot_gpt_6_luna %}
* {% data variables.copilot.copilot_gpt_6_sol %}
* {% data variables.copilot.copilot_gpt_61_sol %}

These models are hosted by OpenAI and {% data variables.product.github %}'s Azure infrastructure.

Expand Down
2 changes: 2 additions & 0 deletions content/copilot/reference/ai-models/supported-models.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ Choosing a larger context window or higher reasoning will impact {% data variabl
| {% data variables.copilot.copilot_gpt_6_astra %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} |
| {% data variables.copilot.copilot_gpt_6_luna %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} |
| {% data variables.copilot.copilot_gpt_6_sol %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} |
| {% data variables.copilot.copilot_gpt_61_sol %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} |
| {% data variables.copilot.copilot_kimi_k3 %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} |

{% endrowheaders %}
Expand Down Expand Up @@ -140,6 +141,7 @@ Some {% data variables.product.prodname_copilot_short %} models require minimum
| {% data variables.copilot.copilot_gpt_6_astra %} | `1.136.1` | `17.14.19` | TBD | TBD | TBD |
| {% data variables.copilot.copilot_gpt_6_luna %} | TBD | `17.14.19` | TBD | TBD | TBD |
| {% data variables.copilot.copilot_gpt_6_sol %} | TBD | `17.14.19` | TBD | TBD | TBD |
| {% data variables.copilot.copilot_gpt_61_sol %} | TBD | `17.14.19` | TBD | TBD | TBD |
| {% data variables.copilot.copilot_claude_opus_48 %} | `v1.118` | `17.14.6` | TBD | TBD | TBD |
| {% data variables.copilot.copilot_claude_opus_5 %} | `v1.128.0` | `17.14.22` | TBD | TBD | TBD |
| {% data variables.copilot.copilot_claude_opus_55 %} | TBD | `17.14.6` | TBD | TBD | TBD |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ All prices are **per 1 million tokens**.

{% data reusables.copilot.extended-context-pricing %}

{% data variables.copilot.copilot_gpt_56_sol %}, {% data variables.copilot.copilot_gpt_56_terra %}, {% data variables.copilot.copilot_gpt_56_luna %}, {% data variables.copilot.copilot_gpt_6_astra %}, {% data variables.copilot.copilot_gpt_6_luna %}, and {% data variables.copilot.copilot_gpt_6_sol %} include a cache write cost in addition to cached input. Earlier OpenAI models have no cache write cost.
{% data variables.copilot.copilot_gpt_56_sol %}, {% data variables.copilot.copilot_gpt_56_terra %}, {% data variables.copilot.copilot_gpt_56_luna %}, {% data variables.copilot.copilot_gpt_6_astra %}, {% data variables.copilot.copilot_gpt_6_luna %}, {% data variables.copilot.copilot_gpt_6_sol %}, and {% data variables.copilot.copilot_gpt_61_sol %} include a cache write cost in addition to cached input. Earlier OpenAI models have no cache write cost.

| Model | Release status | Category | Tier | Threshold (input tokens) | Input | Cached input | Cache write | Output |
| --- | --- | --- | --- | --- | ---: | ---: | ---: | ---: |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* {% data variables.copilot.copilot_gpt_6_astra %}
* {% data variables.copilot.copilot_gpt_6_luna %}
* {% data variables.copilot.copilot_gpt_6_sol %}
* {% data variables.copilot.copilot_gpt_61_sol %}
* {% data variables.copilot.copilot_grok_45 %}
* {% data variables.copilot.copilot_grok_46 %}
* {% data variables.copilot.copilot_grok_47 %}
Expand Down
7 changes: 6 additions & 1 deletion data/tables/copilot/model-comparison.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,16 @@
- name: GPT-6 Luna
task_area: Fast help with simple or repetitive tasks
excels_at: Quick, cost-efficient responses for smaller, faster tasks
further_reading: 'Coming soon'
further_reading: '[GPT-6 Luna model card](https://deploymentsafety.openai.com/gpt-6-astra/gpt-6-astra.pdf)'

- name: GPT-6 Sol
task_area: Interactive and agentic coding
excels_at: All-round development tasks that benefit from careful, multistep validation
further_reading: '[GPT-6 Sol model card](https://deploymentsafety.openai.com/gpt-6-astra/gpt-6-astra.pdf)'

- name: GPT-6.1 Sol
task_area: Complex coding tasks
excels_at: Advanced, efficient reasoning for complex coding tasks
further_reading: 'Coming soon'

# Anthropic
Expand Down
4 changes: 4 additions & 0 deletions data/tables/copilot/model-release-status.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@
provider: 'OpenAI'
release_status: 'GA'

- name: 'GPT-6.1 Sol'
provider: 'OpenAI'
release_status: 'GA'

# Anthropic models

- name: 'Claude Fable 5'
Expand Down
7 changes: 7 additions & 0 deletions data/tables/copilot/model-supported-plans.yml
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,13 @@
business: true
enterprise: true

- name: GPT-6.1 Sol
pro: false
pro_plus: true
max: true
business: true
enterprise: true

- name: Grok 4.5
pro: true
pro_plus: true
Expand Down
22 changes: 22 additions & 0 deletions data/tables/copilot/models-and-pricing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,28 @@
output: $15.00
cache_write: $5.00

- model: GPT-6.1 Sol
provider: openai
release_status: GA
category: Powerful
threshold: '≤ 272K'
tier: Default
input: $2.00
cached_input: $0.10
output: $10.00
cache_write: $2.50

- model: GPT-6.1 Sol
provider: openai
release_status: GA
category: Powerful
threshold: '> 272K'
tier: 'Long context'
input: $4.00
cached_input: $0.20
output: $15.00
cache_write: $5.00

# Anthropic
- model: Claude Haiku 4.5
provider: anthropic
Expand Down
1 change: 1 addition & 0 deletions data/variables/copilot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ copilot_gpt_56_terra: 'GPT-5.6 Terra'
copilot_gpt_6_astra: 'GPT-6 Astra'
copilot_gpt_6_luna: 'GPT-6 Luna'
copilot_gpt_6_sol: 'GPT-6 Sol'
copilot_gpt_61_sol: 'GPT-6.1 Sol'
# OpenAI 'o' series:
copilot_o3: 'o3'
copilot_o4_mini: 'o4-mini'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
title: Debug a workflow
intro: Diagnose a failed workflow.
versions:
fpt: '*'
category:
- Debugging code
surface:
- CLI
complexity:
- Advanced
---

Diagnose a failed workflow.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: Cookbook examples
versions:
fpt: '*'
children:
- /testing
- /debugging
---
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
title: Write unit tests
intro: Generate tests for a function.
versions:
fpt: '*'
category:
- Improve quality and maintainability
surface:
- Chat
complexity:
- Simple
---

Generate tests for a function.
16 changes: 16 additions & 0 deletions src/fixtures/fixtures/content/get-started/cookbook/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
title: Cookbook filters
intro: Test search and category landing filters.
versions:
fpt: '*'
layout: category-landing
filters:
- category
- surface
- complexity
spotlight:
- article: /examples/testing
image: /assets/images/placeholder.png
children:
- /examples
---
1 change: 1 addition & 0 deletions src/fixtures/fixtures/content/get-started/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ children:
- /multi-carousel
- /non-child-resolution
- /discovery-filtered
- /cookbook
communityRedirect:
name: Provide HubGit Feedback
href: 'https://hubgit.com/orgs/community/discussions/categories/get-started'
Expand Down
80 changes: 80 additions & 0 deletions src/fixtures/tests/playwright-rendering.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1634,6 +1634,86 @@ test.describe('Docs 2026 in-article navigation', () => {
})
})

test.describe('CookBookFilter component', () => {
const filters = [
{ name: 'Category', value: 'Improve quality and maintainability' },
{ name: 'Surface', value: 'Chat' },
{ name: 'Complexity', value: 'Simple' },
]

for (const { name, value } of filters) {
test(`${name} filters articles`, async ({ page }) => {
await page.goto('/get-started/cookbook')
await expect(page.getByRole('heading', { name: 'Explore 2 examples' })).toBeVisible()

const trigger = page.getByRole('button', { name: new RegExp(`^${name}:`) })
await trigger.click()
const menu = page.getByRole('menu', { name, exact: true })
await menu.getByRole('menuitemradio', { name: value, exact: true }).click()

await expect(page.getByRole('heading', { name: 'Explore 1 examples' })).toBeVisible()
await expect(trigger).toHaveText(`${name}: ${value}`)
await trigger.click()
await expect(menu.getByRole('menuitemradio', { checked: true })).toHaveText(value)
})
}

test('search combines with filters and reset clears both', async ({ page }) => {
await page.goto('/get-started/cookbook')
for (const { name, value } of filters) {
await page.getByRole('button', { name: `${name}: All`, exact: true }).click()
await page.getByRole('menuitemradio', { name: value, exact: true }).click()
}

const search = page.getByRole('textbox', { name: 'Search examples' })
await search.fill('workflow')
await expect(page.getByRole('heading', { name: 'Explore 0 examples' })).toBeVisible()
await search.fill('tests')
await expect(page.getByRole('heading', { name: 'Explore 1 examples' })).toBeVisible()

await page.getByRole('button', { name: 'Reset filters', exact: true }).click()
await expect(search).toHaveValue('')
await expect(page.getByRole('heading', { name: 'Explore 2 examples' })).toBeVisible()
for (const { name } of filters) {
await expect(page.getByRole('button', { name: `${name}: All`, exact: true })).toBeVisible()
}
})

for (const key of ['Enter', 'Space']) {
test(`category menu supports ${key} selection and Escape`, async ({ page }) => {
await page.goto('/get-started/cookbook')
const trigger = page.getByRole('button', { name: /^Category:/ })
await trigger.focus()
await page.keyboard.press(key)
const menu = page.getByRole('menu', { name: 'Category', exact: true })
await expect(menu.getByRole('menuitemradio', { name: 'All', exact: true })).toBeFocused()
await page.keyboard.press('ArrowDown')
await page.keyboard.press(key)

await expect(menu).toHaveCount(0)
await expect(trigger).toBeFocused()
await expect(trigger).toContainText('Improve quality and maintainability')
await expect(page.getByRole('heading', { name: 'Explore 1 examples' })).toBeVisible()
await trigger.click()
await page.keyboard.press('Escape')
await expect(menu).toHaveCount(0)
await expect(trigger).toBeFocused()
})
}

test('long category options fit within the mobile viewport', async ({ page }) => {
await page.setViewportSize({ width: 320, height: 1000 })
await page.goto('/get-started/cookbook')
await page.getByRole('button', { name: 'Category: All', exact: true }).click()
const menu = page.getByRole('menu', { name: 'Category', exact: true })
await expect(menu).toBeVisible()
const bounds = await menu.boundingBox()
expect(bounds).not.toBeNull()
expect(bounds!.x).toBeGreaterThanOrEqual(0)
expect(bounds!.x + bounds!.width).toBeLessThanOrEqual(320)
})
})

test.describe('LandingArticleGridWithFilter component', () => {
test('category menu selects once via keyboard and preserves URL state', async ({ page }) => {
await page.goto('/get-started/article-grid-discovery?articles-filter=Grid&articles-page=2')
Expand Down
Loading
Loading