Extend AI-agent detection in the User-Agent header (Roo Code, Duo Agent Platform, IDE-terminal context)
<!-- AI-Sessions dir: ~/.claude/projects/-Users-samwiskow-projects-glab/ e1ce5f15-a4e8-48d8-960c-025061716347.jsonl (2026-05-21) --> ## Summary Expand `DetectCodingAgent` (`internal/api/coding_agent.go`) to recognise three additional sources so GitLab can attribute API traffic to a wider slice of the AI-coding-agent ecosystem. ## Background `glab` already appends a `Coding-Agent/<name>` token to the User-Agent header when it detects one of: Claude Code, Codex, Cursor, OpenCode, or a value passed via the universal `AI_AGENT` escape hatch. This shipped in commit `4508ae6b` (first released in **v1.98.0**). A follow-up branch adds Gemini CLI in commit `47a925e1`. The ecosystem has grown since the original list. This issue tracks adding the next batch of detections without changing the existing UA format or wire protocol. ## Proposed detections | Signal | Env condition | Returned name | |---|---|---| | Roo Code CLI | `ROO_CLI_RUNTIME == "1"` | `roo-code` | | GitLab Duo Agent Platform | `AGENT_PLATFORM_GITLAB_VERSION != ""` | `duo-agent-platform` | | Cursor terminal (fallback) | `TERM_PROGRAM == "cursor"` | `cursor-terminal` | | Windsurf terminal (fallback) | `TERM_PROGRAM == "windsurf"` (case-insensitive) | `windsurf-terminal` | | Zed terminal (fallback) | `TERM_PROGRAM == "zed"` | `zed-terminal` | ### Naming convention: the `-terminal` suffix Explicit "an agent invoked glab" signals (like `CLAUDECODE=1` or `CURSOR_AGENT=1`) stay as plain names. `TERM_PROGRAM`-based signals get a `-terminal` suffix because they can fire for human-typed commands inside those IDE terminals too — analytics can then split true agent invocations from "ran in an IDE terminal" context. ### Precedence `DetectCodingAgent` returns the first match. The order is: 1. `AI_AGENT` (escape hatch, validated) 2. Explicit agent env vars, alphabetical (existing behaviour preserved) — strong signals win 3. `TERM_PROGRAM`-based fallback (new) So `CURSOR_AGENT=1` with `TERM_PROGRAM=cursor` still returns `cursor`, not `cursor-terminal`. ## Files to change - `internal/api/coding_agent.go` — add the new branches in `DetectCodingAgent` - `internal/api/coding_agent_test.go` — table-driven cases for each new detection, the strong-signal-beats-terminal precedence, and add the three new env vars (`ROO_CLI_RUNTIME`, `AGENT_PLATFORM_GITLAB_VERSION`, `TERM_PROGRAM`) to the `allAgentVars` reset list No other changes needed — `BuildInfo.UserAgent()` already plumbs whatever `DetectCodingAgent()` returns into the `Coding-Agent/<name>` token. ## Acceptance criteria - [ ] `go test ./internal/api/ -run TestDetectCodingAgent` passes, including new cases - [ ] `go test ./internal/api/...` passes (no regression in other tests that read `TERM_PROGRAM`) - [ ] Manual: with each env var set in turn, `GLAB_DEBUG_HTTP=1 glab auth status 2>&1 | grep -i user-agent` shows the expected `Coding-Agent/<name>` token - [ ] Precedence sanity: `CURSOR_AGENT=1` + `TERM_PROGRAM=cursor` ⇒ `Coding-Agent/cursor` (not `cursor-terminal`) ## Non-goals - Capturing agent **version** — keeping the existing name-only format. If useful later, can be done as a follow-up. - Switching to a separate HTTP header — staying with the existing `Coding-Agent/<name>` UA token. - Snowplow / product analytics instrumentation — out of scope here; only the UA header is changed. ## Coordination - A separate branch `add_gemini_cli_detection` (commit `47a925e1`) adds Gemini CLI (`GEMINI_CLI=1` → `gemini`). This issue does **not** duplicate that work; whichever MR merges first wins, and the other rebases. The conflict is adjacent-line and trivial. - For the `duo-agent-platform` detection, `AGENT_PLATFORM_GITLAB_VERSION` is documented as Duo Agent Platform-specific in the [execution-variables docs](https://docs.gitlab.com/user/duo_agent_platform/flows/execution_variables/). Happy to swap it for a more explicit flag if the Duo team prefers something like a dedicated `DUO_AGENT=1`. ## Help wanted: other agents we should detect Anyone aware of a reliable, documented self-identification env var for any of these? Please drop a comment. - Aider - Cline - Goose - Jules - Continue CLI - Sourcegraph Cody / Amp The bar is "the agent sets a deterministic env var when it shells out to subprocesses". Falling back to `TERM_PROGRAM` for IDE-hosted agents is also an option.
issue