Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Coding agents show as themselves on commits and contributors: Claude, Codex, Copilot, Gemini, Jules, Cursor, Devin, Aider, Dependabot, Renovate and GitHub Actions are known by the address they write on their commits (never by name), shown with their maker's mark, their own name and an agent or bot label, and a card saying what each is. Anyone else not on g1t gets a card too, saying so and how to claim the commits by adding the address. Contributor lists are worked out again (stats version 2) so an agent counts once. | 1 | /** |
| 2 | * Coding agents and bots that commit to repositories under their own | |
| 3 | * names: Claude Code, Codex, Copilot, Gemini, Cursor and the dependency | |
| 4 | * bots. None of them is an account on g1t, but each writes the same | |
| 5 | * address on every commit (or a GitHub bot's noreply address), so g1t | |
| 6 | * shows them as what they are, with their maker's mark and a card, | |
| 7 | * rather than as an unknown author. | |
| 8 | * | |
| 9 | * Matched by the commit's address only, never by the name: anyone can | |
| 10 | * write "Claude" as their name. An account that owns an address always | |
| 11 | * wins (lib/commit-people.ts in the site, services/repos contributors.rs); | |
| 12 | * these addresses can't be confirmed by anyone, so that never happens. | |
| 13 | * | |
| 14 | * The Rust side (crates/contracts/src/coding_agents.rs) keeps the same | |
| 15 | * ids, addresses and logins; a test there reads this file to keep them | |
| 16 | * equal. No imports, so it runs anywhere. | |
| 17 | */ | |
| 18 | ||
| 19 | export type CodingAgentId = "claude" | "codex" | "copilot" | "gemini" | "jules" | "cursor" | "devin" | "aider" | "dependabot" | "renovate" | "github-actions"; | |
| 20 | ||
| 21 | /** Whether it writes code for people (`agent`) or keeps dependencies and builds running (`bot`). */ | |
| 22 | export type CodingAgentKind = "agent" | "bot"; | |
| 23 | ||
| 24 | export type CodingAgent = { | |
| 25 | id: CodingAgentId; | |
| 26 | /** What it's called, as its card names it. */ | |
| 27 | name: string; | |
| 28 | /** Who makes it. */ | |
| 29 | maker: string; | |
| 30 | kind: CodingAgentKind; | |
| 31 | /** One line about it, for its card. */ | |
| 32 | about: string; | |
| 33 | /** Its own page. */ | |
| 34 | url: string; | |
| 35 | /** Addresses it writes on commits, lowercase. */ | |
| 36 | emails: readonly string[]; | |
| 37 | /** GitHub logins whose noreply addresses (`123+login@users.noreply.github.com`) are its, lowercase. */ | |
| 38 | logins: readonly string[]; | |
| 39 | /** Its mark's background, as a hex colour without `#`; null to use the page's own colours. */ | |
| 40 | color: string | null; | |
| 41 | }; | |
| 42 | ||
| 43 | export const CODING_AGENTS: readonly CodingAgent[] = [ | |
| 44 | { | |
| 45 | id: "claude", | |
| 46 | name: "Claude", | |
| 47 | maker: "Anthropic", | |
| 48 | kind: "agent", | |
| 49 | about: "Anthropic's coding agent. Commits made with Claude Code carry its address as author or co-author.", | |
| 50 | url: "https://claude.com/product/claude-code", | |
| 51 | emails: ["noreply@anthropic.com"], | |
| 52 | logins: ["claude", "claude[bot]"], | |
| 53 | color: "D97757", | |
| 54 | }, | |
| 55 | { | |
| 56 | id: "codex", | |
| 57 | name: "Codex", | |
| 58 | maker: "OpenAI", | |
| 59 | kind: "agent", | |
| 60 | about: "OpenAI's coding agent, committing through its GitHub app.", | |
| 61 | url: "https://openai.com/codex", | |
| 62 | emails: [], | |
| 63 | logins: ["chatgpt-codex-connector[bot]", "codex[bot]"], | |
| 64 | color: null, | |
| 65 | }, | |
| 66 | { | |
| 67 | id: "copilot", | |
| 68 | name: "Copilot", | |
| 69 | maker: "GitHub", | |
| 70 | kind: "agent", | |
| 71 | about: "GitHub's coding agent.", | |
| 72 | url: "https://github.com/features/copilot", | |
| 73 | emails: [], | |
| 74 | logins: ["copilot", "copilot-swe-agent[bot]", "copilot-pull-request-reviewer[bot]"], | |
| 75 | color: null, | |
| 76 | }, | |
| 77 | { | |
| 78 | id: "gemini", | |
| 79 | name: "Gemini", | |
| 80 | maker: "Google", | |
| 81 | kind: "agent", | |
| 82 | about: "Google's coding assistant, committing through its GitHub app.", | |
| 83 | url: "https://codeassist.google", | |
| 84 | emails: [], | |
| 85 | logins: ["gemini-code-assist[bot]", "gemini-cli[bot]"], | |
| 86 | color: "8E75B2", | |
| 87 | }, | |
| 88 | { | |
| 89 | id: "jules", | |
| 90 | name: "Jules", | |
| 91 | maker: "Google", | |
| 92 | kind: "agent", | |
| 93 | about: "Google's asynchronous coding agent.", | |
| 94 | url: "https://jules.google", | |
| 95 | emails: [], | |
| 96 | logins: ["google-labs-jules[bot]"], | |
| 97 | color: "8E75B2", | |
| 98 | }, | |
| 99 | { | |
| 100 | id: "cursor", | |
| 101 | name: "Cursor", | |
| 102 | maker: "Anysphere", | |
| 103 | kind: "agent", | |
| 104 | about: "Cursor's background agent.", | |
| 105 | url: "https://cursor.com", | |
| 106 | emails: ["cursoragent@cursor.com"], | |
| 107 | logins: ["cursor[bot]", "cursor-agent[bot]"], | |
| 108 | color: null, | |
| 109 | }, | |
| 110 | { | |
| 111 | id: "devin", | |
| 112 | name: "Devin", | |
| 113 | maker: "Cognition", | |
| 114 | kind: "agent", | |
| 115 | about: "Cognition's coding agent.", | |
| 116 | url: "https://devin.ai", | |
| 117 | emails: [], | |
| 118 | logins: ["devin-ai-integration[bot]"], | |
| 119 | color: null, | |
| 120 | }, | |
| 121 | { | |
| 122 | id: "aider", | |
| 123 | name: "Aider", | |
| 124 | maker: "Aider", | |
| 125 | kind: "agent", | |
| 126 | about: "An open-source coding agent for the terminal.", | |
| 127 | url: "https://aider.chat", | |
| 128 | emails: ["noreply@aider.chat", "aider@aider.chat"], | |
| 129 | logins: [], | |
| 130 | color: null, | |
| 131 | }, | |
| 132 | { | |
| 133 | id: "dependabot", | |
| 134 | name: "Dependabot", | |
| 135 | maker: "GitHub", | |
| 136 | kind: "bot", | |
| 137 | about: "Opens pull requests that update dependencies.", | |
| 138 | url: "https://github.com/dependabot", | |
| 139 | emails: ["support@dependabot.com"], | |
| 140 | logins: ["dependabot[bot]", "dependabot-preview[bot]"], | |
| 141 | color: "025E8C", | |
| 142 | }, | |
| 143 | { | |
| 144 | id: "renovate", | |
| 145 | name: "Renovate", | |
| 146 | maker: "Mend", | |
| 147 | kind: "bot", | |
| 148 | about: "Opens pull requests that update dependencies.", | |
| 149 | url: "https://docs.renovatebot.com", | |
| 150 | emails: ["bot@renovateapp.com"], | |
| 151 | logins: ["renovate[bot]"], | |
| 152 | color: "308BE3", | |
| 153 | }, | |
| 154 | { | |
| 155 | id: "github-actions", | |
| 156 | name: "GitHub Actions", | |
| 157 | maker: "GitHub", | |
| 158 | kind: "bot", | |
| 159 | about: "Commits made by a workflow on GitHub.", | |
| 160 | url: "https://github.com/features/actions", | |
| 161 | emails: ["action@github.com"], | |
| 162 | logins: ["github-actions[bot]"], | |
| 163 | color: "2088FF", | |
| 164 | }, | |
| 165 | ]; | |
| 166 | ||
| 167 | const GITHUB_NOREPLY = /^(?:\d+\+)?([^@]+)@users\.noreply\.github\.com$/; | |
| 168 | ||
| 169 | /** The coding agent a commit's address belongs to, or null. */ | |
| 170 | export function codingAgentFor(email: string | null | undefined): CodingAgent | null { | |
| 171 | const address = (email ?? "").trim().toLowerCase(); | |
| 172 | if (!address) return null; | |
| 173 | const login = GITHUB_NOREPLY.exec(address)?.[1] ?? null; | |
| 174 | return CODING_AGENTS.find((agent) => agent.emails.includes(address) || (login !== null && agent.logins.includes(login))) ?? null; | |
| 175 | } | |
| 176 | ||
| 177 | /** An agent by id, or null for one this g1t doesn't know (an older or newer list). */ | |
| 178 | export function codingAgentById(id: string | null | undefined): CodingAgent | null { | |
| 179 | return CODING_AGENTS.find((agent) => agent.id === id) ?? null; | |
| 180 | } |