Record agentic invocations in User-Agent header#13023
Conversation
| ) | ||
|
|
||
| const ( | ||
| accept = "Accept" |
c1daf35 to
d1a2ae7
Compare
There was a problem hiding this comment.
Pull request overview
This PR adds lightweight agent detection (via well-known environment variables) and threads the detected agent name into API client construction so that gh includes an Agent/<name> suffix in the User-Agent header for GitHub API requests, improving visibility into agentic CLI usage.
Changes:
- Introduces
internal/agentswithDetect()plus tests for supported agent environment variable signals and precedence. - Extends factory and HTTP client plumbing to pass an
invokingAgentvalue intoapi.NewHTTPClient, appending it to theUser-Agent. - Updates call sites and tests for the new factory/HTTP client function signatures.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
internal/agents/detect.go |
Adds agent detection + validation for AI_AGENT values. |
internal/agents/detect_test.go |
Adds unit tests covering detection signals and precedence. |
internal/ghcmd/cmd.go |
Wires detected agent into factory creation at CLI entrypoint. |
api/http_client.go |
Adds InvokingAgent option and appends it to User-Agent. |
api/http_client_test.go |
Adds test asserting agent suffix is included in User-Agent. |
pkg/cmd/factory/default.go |
Threads invokingAgent through factory into HTTP client options. |
pkg/cmd/factory/default_test.go |
Updates factory constructor usage for new parameter. |
pkg/cmd/search/shared/shared_test.go |
Updates factory constructor usage for new parameter. |
pkg/cmd/attestation/verify/verify_integration_test.go |
Updates factory constructor usage for new parameter. |
api/client.go |
Removes an unused header constant. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ua := fmt.Sprintf("GitHub CLI %s", opts.AppVersion) | ||
| if opts.InvokingAgent != "" { | ||
| ua = fmt.Sprintf("%s Agent/%s", ua, opts.InvokingAgent) | ||
| } |
There was a problem hiding this comment.
opts.InvokingAgent is appended to the User-Agent verbatim. If a future caller passes an untrusted/unsanitized value (e.g. containing \r/\n or other invalid header characters), requests can fail with "invalid header field value" and this undermines the stated header-injection hardening. Consider validating/sanitizing opts.InvokingAgent inside NewHTTPClient (e.g. allow only [A-Za-z0-9_-]+ and otherwise omit the agent suffix), and add a small test for the invalid-value case.
There was a problem hiding this comment.
Nah we sanitize at the agent layer. I don't want to create a gh.AgentName just to deal with this.
| agentOpencode AgentName = "opencode" | ||
| ) | ||
|
|
||
| var validAgentName = regexp.MustCompile(`^[a-zA-Z0-9_-]+$`) |
There was a problem hiding this comment.
Maybe also dots, slashes (/ and ), and brackets? As some agent may decide to add versions (in brackets).
There was a problem hiding this comment.
Purely based on what we've seen so far out in the wild, I'm inclined to leave this alone until we see something otherwise.
Detect which AI coding agent is invoking gh by checking well-known environment variables and include the agent name in the User-Agent header sent to GitHub APIs. Supported agents: Codex, Gemini CLI, Copilot CLI, OpenCode, Claude Code, and Amp. Generic AI_AGENT env var is also supported with validation to prevent header injection. Fixes github/cli#1111 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
d1a2ae7 to
c51769c
Compare
|
Bypassing package security review cause it's not that interesting. |
This MR contains the following updates: | Package | Update | Change | |---|---|---| | [cli/cli](https://github.com/cli/cli) | minor | `v2.88.1` → `v2.89.0` | MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot). **Proposed changes to behavior should be submitted there as MRs.** --- ### Release Notes <details> <summary>cli/cli (cli/cli)</summary> ### [`v2.89.0`](https://github.com/cli/cli/releases/tag/v2.89.0): GitHub CLI 2.89.0 [Compare Source](cli/cli@v2.88.1...v2.89.0) ####`gh agent-task` now works on ghe.com tenancies `gh agent-task` commands previously failed with `401 Unauthorized` for users on ghe.com tenancy hosts because the Copilot API URL was hardcoded. The URL is now resolved dynamically per host, so `gh agent-task` works correctly regardless of your GitHub hosting environment. #### Experimental new prompter A new TUI-based prompter powered by [charmbracelet/huh](https://github.com/charmbracelet/huh) is available behind the `GH_EXPERIMENTAL_PROMPTER` environment variable. This is an early preview — try it out and share feedback! ``` export GH_EXPERIMENTAL_PROMPTER=1 ``` #### `gh issue create` and `gh issue transfer` no longer require extra token scopes `gh issue create` and `gh issue transfer` previously fetched repository fields they didn't need, which could require additional token scopes. These commands now fetch only the minimal fields necessary for issue operations. #### What's Changed ##### ✨ Features - `gh pr create`, `gh issue create`, `gh issue edit`: search-based assignee selection and login-based mutation on github.com by [@​BagToad](https://github.com/BagToad) in [#​13009](cli/cli#13009) - Add experimental huh-only prompter gated by `GH_EXPERIMENTAL_PROMPTER` by [@​BagToad](https://github.com/BagToad) in [#​12859](cli/cli#12859) ##### 🐛 Fixes - fix(agent-task): resolve Copilot API URL dynamically for ghe.com tenancies by [@​BagToad](https://github.com/BagToad) in [#​12956](cli/cli#12956) - fix(issue): avoid fetching unnecessary fields in `issue create` and `issue transfer` by [@​babakks](https://github.com/babakks) in [#​12884](cli/cli#12884) - fix: resolve data race in codespaces port forwarder by [@​Lslightly](https://github.com/Lslightly) in [#​13033](cli/cli#13033) ##### 📚 Docs & Chores - Record agentic invocations in User-Agent header by [@​williammartin](https://github.com/williammartin) in [#​13023](cli/cli#13023) - docs: clarify that `gh pr edit --add-reviewer` can re-request reviews by [@​joshjohanning](https://github.com/joshjohanning) in [#​13021](cli/cli#13021) - Add AGENTS.md by [@​williammartin](https://github.com/williammartin) in [#​13024](cli/cli#13024) - Fix typo: remove extra space in README.md link by [@​realMelTuc](https://github.com/realMelTuc) in [#​12725](cli/cli#12725) - Align triage.md with current triage process by [@​tidy-dev](https://github.com/tidy-dev) in [#​13030](cli/cli#13030) - Remove auto-labels from issue templates by [@​tidy-dev](https://github.com/tidy-dev) in [#​12972](cli/cli#12972) - Consolidate actor-mode signals into `ApiActorsSupported` by [@​BagToad](https://github.com/BagToad) in [#​13025](cli/cli#13025) - Fix acceptance test failures: git identity, headRepository JSON, obsolete traversal test by [@​BagToad](https://github.com/BagToad) in [#​13037](cli/cli#13037) #####
Dependencies - chore(deps): bump google.golang.org/grpc from 1.79.2 to 1.79.3 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​12963](cli/cli#12963) - chore(deps): bump github.com/google/go-containerregistry from 0.20.7 to 0.21.3 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​12962](cli/cli#12962) - chore(deps): bump github.com/zalando/go-keyring from 0.2.6 to 0.2.8 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​13031](cli/cli#13031) - chore(deps): bump microsoft/setup-msbuild from 2.0.0 to 3.0.0 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​13005](cli/cli#13005) - chore(deps): bump mislav/bump-homebrew-formula-action from 3.6 to 4.1 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​13004](cli/cli#13004) - chore(deps): bump azure/login from 2.3.0 to 3.0.0 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​12951](cli/cli#12951) #### New Contributors - [@​joshjohanning](https://github.com/joshjohanning) made their first contribution in [#​13021](cli/cli#13021) - [@​realMelTuc](https://github.com/realMelTuc) made their first contribution in [#​12725](cli/cli#12725) - [@​Lslightly](https://github.com/Lslightly) made their first contribution in [#​13033](cli/cli#13033) **Full Changelog**: [v2.88.1...v2.89.0](cli/cli@v2.88.1...v2.89.0) </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this MR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box --- This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My45MS40IiwidXBkYXRlZEluVmVyIjoiNDMuOTEuNCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiUmVub3ZhdGUgQm90IiwiYXV0b21hdGlvbjpib3QtYXV0aG9yZWQiLCJkZXBlbmRlbmN5LXR5cGU6Om1pbm9yIl19-->
Description
There has been a significant increase in agentic use of
ghin the last few months and it's important we are able to identify that usage. This PR tries to detect which agent is invokingghby checking well-known environment variables and includes the agent name in theUser-Agentheader sent to GitHub APIs.Supported agents: Codex, Gemini CLI, Copilot CLI, OpenCode, Claude Code, and Amp. The generic
AI_AGENTenv var is also supported with validation ([a-zA-Z0-9_-]) to prevent header injection.Format
Acceptance Criteria
Given I set
GH_DEBUG=apiin the environmentWhen I invoke
ghin a shell tool in Claude Code CLI, Gemini CLI, Codex CLI, Copilot CLI, Amp, or OpenCodeThen I see that the
User-Agentheader in http requests contains the agent nameRunning in
copilotCLI:Given I set
GH_DEBUG=apiin the environmentWhen I invoke
ghdirectly (in copilot CLI, run withCOPILOT_CLIunset in the environment)Then I see that the
User-Agentheader in http requests does not contain an agent nameRunning in shell: