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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ This package can detect the following AI agents and development environments:
- **Cursor** (Anysphere)
- **Claude Code** (Anthropic)
- **Claude Cowork** (Anthropic)
- **Kimi Code** (Moonshot AI)
- **Grok Build** (xAI)
- **Devin** (Cognition Labs)
- **Gemini CLI** (Google)
- **Codex** (OpenAI)
Expand Down
20 changes: 12 additions & 8 deletions detect_agent/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,17 @@

CURSOR: Literal["cursor"] = "cursor"
CURSOR_CLI: Literal["cursor-cli"] = "cursor-cli"
CLAUDE: Literal["claude"] = "claude"
CLAUDE: Literal["claude_code"] = "claude_code"
COWORK: Literal["cowork"] = "cowork"
DEVIN: Literal["devin"] = "devin"
REPLIT: Literal["replit"] = "replit"
GEMINI: Literal["gemini"] = "gemini"
CODEX: Literal["codex"] = "codex"
KIMI: Literal["kimi"] = "kimi"
GROK: Literal["grok"] = "grok"
GEMINI: Literal["gemini_cli"] = "gemini_cli"
CODEX: Literal["codex_cli"] = "codex_cli"
ANTIGRAVITY: Literal["antigravity"] = "antigravity"
AUGMENT_CLI: Literal["augment-cli"] = "augment-cli"
OPENCODE: Literal["opencode"] = "opencode"
OPENCODE: Literal["open_code"] = "open_code"
GITHUB_COPILOT: Literal["github-copilot"] = "github-copilot"
CLINE: Literal["cline"] = "cline"
GOOSE: Literal["goose"] = "goose"
Expand All @@ -35,15 +37,17 @@
KnownAgentNames = Literal[
"cursor",
"cursor-cli",
"claude",
"claude_code",
"cowork",
"devin",
"replit",
"gemini",
"codex",
"kimi",
"grok",
"gemini_cli",
"codex_cli",
"antigravity",
"augment-cli",
"opencode",
"open_code",
"github-copilot",
"cline",
"goose",
Expand Down
31 changes: 26 additions & 5 deletions detect_agent/agents.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,30 @@
]
}
},
{
"key": "KIMI",
"name": "kimi",
"description": "Kimi Code plugin hooks. KIMI_CODE_HOME may be configured outside an active Kimi session, so detection uses the plugin-scoped KIMI_PLUGIN_ROOT marker.",
"match": {
"type": "anyOf",
"conditions": [{ "type": "env_set", "name": "KIMI_PLUGIN_ROOT" }]
}
},
{
"key": "GROK",
"name": "grok",
"description": "Grok Build plugin hooks. Evaluated before Claude Code because Grok supports Claude Code plugins and may expose compatibility markers.",
"match": {
"type": "anyOf",
"conditions": [
{ "type": "env_set", "name": "GROK_PLUGIN_ROOT" },
{ "type": "env_set", "name": "GROK_PLUGIN_DATA" }
]
}
},
{
"key": "GEMINI",
"name": "gemini",
"name": "gemini_cli",
"match": {
"type": "anyOf",
"conditions": [{ "type": "env_set", "name": "GEMINI_CLI" }]
Expand All @@ -45,7 +66,7 @@
},
{
"key": "CODEX",
"name": "codex",
"name": "codex_cli",
"match": {
"type": "anyOf",
"conditions": [
Expand Down Expand Up @@ -77,7 +98,7 @@
},
{
"key": "OPENCODE",
"name": "opencode",
"name": "open_code",
"match": {
"type": "anyOf",
"conditions": [
Expand Down Expand Up @@ -123,7 +144,7 @@
{
"key": "COWORK",
"name": "cowork",
"description": "Claude Cowork. Evaluated before `claude` so the more specific COWORK marker wins. Requires CLAUDE_CODE_IS_COWORK plus a Claude Code marker.",
"description": "Claude Cowork. Evaluated before `claude_code` so the more specific COWORK marker wins. Requires CLAUDE_CODE_IS_COWORK plus a Claude Code marker.",
"match": {
"type": "allOf",
"conditions": [
Expand All @@ -140,7 +161,7 @@
},
{
"key": "CLAUDE",
"name": "claude",
"name": "claude_code",
"match": {
"type": "anyOf",
"conditions": [
Expand Down
3 changes: 3 additions & 0 deletions tests/test_detect_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
"CURSOR_TRACE_ID",
"CURSOR_AGENT",
"CURSOR_EXTENSION_HOST_ROLE",
"KIMI_PLUGIN_ROOT",
"GROK_PLUGIN_ROOT",
"GROK_PLUGIN_DATA",
"GEMINI_CLI",
"CLINE_ACTIVE",
"CODEX_SANDBOX",
Expand Down
44 changes: 36 additions & 8 deletions tests/testcases.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,26 +54,54 @@
},

{
"name": "detects gemini from GEMINI_CLI",
"name": "detects kimi from KIMI_PLUGIN_ROOT",
"env": { "KIMI_PLUGIN_ROOT": "/tmp/kimi-plugin" },
"expectedIsAgent": true,
"expectedAgentKey": "KIMI"
},
{
"name": "does not detect kimi from KIMI_CODE_HOME alone",
"env": { "KIMI_CODE_HOME": "/tmp/kimi" },
"expectedIsAgent": false
},

{
"name": "detects grok from GROK_PLUGIN_ROOT",
"env": { "GROK_PLUGIN_ROOT": "/tmp/grok-plugin" },
"expectedIsAgent": true,
"expectedAgentKey": "GROK"
},
{
"name": "detects grok from GROK_PLUGIN_DATA before Claude compatibility markers",
"env": {
"GROK_PLUGIN_DATA": "/tmp/grok-data",
"CLAUDE_CODE": "1"
},
"expectedIsAgent": true,
"expectedAgentKey": "GROK"
},

{
"name": "detects gemini_cli from GEMINI_CLI",
"env": { "GEMINI_CLI": "1" },
"expectedIsAgent": true,
"expectedAgentKey": "GEMINI"
},

{
"name": "detects codex from CODEX_SANDBOX",
"name": "detects codex_cli from CODEX_SANDBOX",
"env": { "CODEX_SANDBOX": "seatbelt" },
"expectedIsAgent": true,
"expectedAgentKey": "CODEX"
},
{
"name": "detects codex from CODEX_CI",
"name": "detects codex_cli from CODEX_CI",
"env": { "CODEX_CI": "1" },
"expectedIsAgent": true,
"expectedAgentKey": "CODEX"
},
{
"name": "detects codex from CODEX_THREAD_ID",
"name": "detects codex_cli from CODEX_THREAD_ID",
"env": { "CODEX_THREAD_ID": "thread-123" },
"expectedIsAgent": true,
"expectedAgentKey": "CODEX"
Expand All @@ -94,13 +122,13 @@
},

{
"name": "detects opencode from OPENCODE_CLIENT",
"name": "detects open_code from OPENCODE_CLIENT",
"env": { "OPENCODE_CLIENT": "opencode" },
"expectedIsAgent": true,
"expectedAgentKey": "OPENCODE"
},
{
"name": "detects opencode from OPENCODE",
"name": "detects open_code from OPENCODE",
"env": { "OPENCODE": "1" },
"expectedIsAgent": true,
"expectedAgentKey": "OPENCODE"
Expand Down Expand Up @@ -148,13 +176,13 @@
},

{
"name": "detects claude from CLAUDE_CODE",
"name": "detects claude_code from CLAUDE_CODE",
"env": { "CLAUDE_CODE": "1" },
"expectedIsAgent": true,
"expectedAgentKey": "CLAUDE"
},
{
"name": "detects claude from CLAUDECODE",
"name": "detects claude_code from CLAUDECODE",
"env": { "CLAUDECODE": "1" },
"expectedIsAgent": true,
"expectedAgentKey": "CLAUDE"
Expand Down
Loading