commitlint-config-agent-coauthor
v1.0.0
Published
Shareable commitlint config that requires a Co-authored-by trailer for AI agents (Claude Code, OpenAI Codex, Gemini CLI, …) detected via environment variables.
Maintainers
Readme
commitlint-config-agent-coauthor
A shareable commitlint config that requires a Co-authored-by trailer for AI agents. When a commit is made from inside an agent's environment (Claude Code, OpenAI Codex, Gemini CLI, …), the agent must be credited as a co-author — otherwise the commit is rejected.
Detection is driven entirely by environment variables, so the rule is a no-op for human commits and only kicks in when an agent is actually running.
Ships as TypeScript-built JavaScript with type declarations and no dependencies. The declarations reference @commitlint/types, declared as an optional peerDependency — it's already in your tree via commitlint, so nothing extra is installed (it only matters when you type-check against these declarations).
How it works
| Agent | Detected via | Required trailer |
| --- | --- | --- |
| Claude Code | CLAUDECODE | Co-authored-by: Claude <[email protected]> |
| OpenAI Codex | CODEX_THREAD_ID | Co-authored-by: Codex <[email protected]> |
| Gemini CLI | GEMINI_CLI | Co-authored-by: Gemini <[email protected]> |
| Cursor CLI | CURSOR_AGENT | Co-authored-by: Cursor <[email protected]> |
Matching is by email by default — display names drift between releases (Claude, Claude Opus 4.8, …) but the address is stable.
Install
pnpm add -D commitlint-config-agent-coauthorUsage
Compose it with your base config (e.g. @commitlint/config-conventional):
// commitlint.config.js
export default {
extends: ['@commitlint/config-conventional', 'commitlint-config-agent-coauthor'],
};Then wire commitlint into a git hook with husky:
# .husky/commit-msg
pnpm exec commitlint --edit "$1"Configuration
The rule is registered as agent-coauthor and accepts an options object as its third value:
export default {
extends: ['@commitlint/config-conventional', 'commitlint-config-agent-coauthor'],
rules: {
'agent-coauthor': [
2, // 0 = off, 1 = warning, 2 = error
'always', // 'always' = require the trailer; 'never' = forbid it
{
match: 'email', // 'email' | 'name' | 'either' | 'both'
trailerName: 'Co-authored-by',
// Override or extend the agent registry:
agents: [
{
id: 'my-bot',
name: 'My Bot',
env: ['MY_BOT'], // active when MY_BOT is set & non-empty
// or: detect: (env) => Boolean(env.CI_AGENT),
coAuthor: { name: 'My Bot', email: '[email protected]' },
},
],
},
],
},
};| Option | Default | Description |
| --- | --- | --- |
| agents | built-in registry | Agents to check. Each has id, optional name, env/detect, and a coAuthor. |
| env | process.env | Environment to read (handy for tests). |
| trailerName | "Co-authored-by" | Trailer token to look for. |
| match | "email" | email, name (substring), either, or both. |
| appliesTo | "detected" | For never: forbid trailers from detected agents only (env-gated) or every configured agent (env-independent). Ignored by always. |
Forbidding the trailer
Set the condition to never to invert the rule — an AI co-author trailer becomes something to reject rather than require. There are two scopes:
// "a locally-running agent must not credit itself" — fires only when an agent
// is detected here; a no-op for human and CI commits.
'agent-coauthor': [2, 'never'],
// "no AI co-author trailers in this repo, ever, from anywhere" — rejects any
// known agent's trailer regardless of environment, so it also catches trailers
// added on CI, pasted by hand, or arriving via a pull request.
'agent-coauthor': [2, 'never', { appliesTo: 'configured' }],Use the default (appliesTo: 'detected') to police the agents running in your own environment; use appliesTo: 'configured' to enforce a repo-wide policy against AI co-author trailers. This package exists to encourage honest AI attribution, so treat the forbid modes as a deliberate, opt-in policy choice.
Programmatic exports
import config, {
agentCoauthor, // the raw rule function
plugin, // { rules: { 'agent-coauthor': agentCoauthor } }
agents, // built-ins keyed by id: agents.claude, agents.cursor, …
defaultAgents, // Object.values(agents) — the default registry, as an array
} from 'commitlint-config-agent-coauthor';Types (AgentDefinition, AgentCoauthorOptions, CoAuthor, MatchStrategy, AppliesTo, ParsedCommit, RuleCondition, RuleOutcome) are exported too.
Development
Source is TypeScript in src/, run directly via Node's native type stripping — no build step needed for local work:
pnpm test # node --test (runs the .ts tests as-is)
pnpm typecheck # tsc --noEmit over src + test
pnpm build # emit dist/ (JS + .d.ts) for publishingpnpm build compiles with tsc and rewrites the .ts import specifiers in the emitted declarations to .js. Publishing runs it automatically via prepack.
Changelog
See CHANGELOG.md or the GitHub releases.
License
MIT © Sho KUSANO
