Agent Detector
agent-detector is a small, dependency-free Python package for detecting which
AI coding agent is driving the current process, and for parsing that identity
back out of a User-Agent header on the receiving side.
It returns evidence rather than only a boolean, so callers can distinguish an explicit identity from a broad environmental hint.
Installation
pip install agent-detector
Usage
from agent_detector import detect_agent
detection = detect_agent()
if detection:
print(detection.agent) # "codex"
print(detection.confidence) # "high"
print(detection.signal) # "CODEX_THREAD_ID"
The returned DetectionResult contains:
agent: anAgentNameliteral containing a supported agent nameconfidence:high,medium, orlowsource:environment,path, oruser-agentsignal: the name of the matched signal, never its value
Pass a mapping to make detection deterministic in tests:
assert detect_agent({"OPENCODE": "1"}).agent == "opencode"
Require a minimum confidence when broad environmental hints are not useful:
detection = detect_agent(minimum_confidence="high")
minimum_confidence is typed as Literal["high", "medium", "low"] and
defaults to "low".
User-Agent propagation
A client can propagate a detected identity to a server as a second User-Agent
product. The value must be exactly two whitespace-separated products:
<product>/<version> AI-Agent/<agent>
For example:
example-cli/1.2.3 AI-Agent/codex
The rules are strict and case-sensitive:
productandversionare both required and must be non-empty RFC 9110 tokens (letters, digits, and!#$%&'*+-.^_`|~; no/, spaces, or parentheses)- the marker must be exactly
AI-Agent(mirroring theAI_AGENTenvironment variable) agentmust be one of the supported agent names below, in lowercase- comments such as
(darwin)and additional products are rejected - leading and trailing whitespace is ignored
A client can build the value like this:
from agent_detector import detect_agent
user_agent = "example-cli/1.2.3"
if detection := detect_agent(minimum_confidence="high"):
user_agent += f" AI-Agent/{detection.agent}"
Use parse_invoking_agent on the receiving side. It returns a
DetectionResult with confidence="high", source="user-agent", and
signal="User-Agent", or None when the value does not match:
from agent_detector import parse_invoking_agent
detection = parse_invoking_agent(
request.headers.get("user-agent"),
expected_product="example-cli",
)
if detection:
print(detection.agent) # "codex"
expected_product is optional. When given, it must be a non-empty string and
only values whose product matches it exactly are accepted; anything else
returns None. Use it to ignore unrelated clients that happen to send a
similar header. It is a filter, not authentication: as with environment
detection, the identity is informational and any HTTP client can send it.
Supported agents
| Agent | Signals | Confidence |
|---|---|---|
| Explicit override | AI_AGENT containing a supported agent name |
high |
| Amp | AGENT=amp, AMP_CURRENT_THREAD_ID |
high / medium |
| Codex | CODEX_THREAD_ID, CODEX_CI, CODEX_SANDBOX |
high |
| Gemini CLI | GEMINI_CLI |
high |
| Copilot CLI | COPILOT_CLI |
medium |
| OpenCode | OPENCODE |
high |
| Antigravity | ANTIGRAVITY_AGENT |
medium |
| Augment CLI | AUGMENT_AGENT |
medium |
| Cowork | CLAUDE_CODE_IS_COWORK |
high |
| Claude Code | CLAUDE_CODE_CHILD_SESSION, CLAUDECODE, CLAUDE_CODE |
high / medium |
| Cursor | CURSOR_TRACE_ID |
medium |
| Cursor CLI | CURSOR_AGENT, CURSOR_EXTENSION_HOST_ROLE=agent-exec |
high / medium |
| Grok Bot | CURSOR_AGENT + SAND_BOX_BOOT_ID + SAND_BOX_STORE_ID (all required) |
high |
| Kiro | TERM_PROGRAM=kiro |
low |
| Pi | .pi/agent entry in PATH |
medium |
| Replit | REPL_ID |
low |
| Goose | GOOSE_PROVIDER |
low |
AI_AGENT takes precedence over inferred signals when its value is one of the
supported agent names. Unknown values are ignored.
The detector is deliberately ordered. For example, Amp is checked before
Claude Code because Amp also sets CLAUDECODE, and Grok Bot is checked before
Cursor CLI because it also sets CURSOR_AGENT.
Important limitations
Detection is best-effort. None means unattributed, not "human". Some
signals can also be present in an integrated terminal where a person typed the
command manually.
This package detects the execution harness. It cannot determine whether a particular skill, plugin, prompt, or model caused the command. Use a separate explicit marker when that attribution matters.
Neither environment detection nor the User-Agent format verifies the caller.
Do not use a detected identity to grant access or bypass checks.
Privacy
Environment values such as thread IDs are never returned. A result contains
only a normalized agent name and the name and category of the matched signal.
parse_invoking_agent likewise returns only the agent name, never the client
product, version, or the raw header.
Development
uv sync --all-groups
uv run ruff check .
uv run ruff format --check .
uv run mypy
uv run pytest
uv build
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agent_detector-1.1.1.tar.gz.
File metadata
- Download URL: agent_detector-1.1.1.tar.gz
- Upload date:
- Size: 54.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fe1c96a3868a07541763e12eff70df41920ab41668f3b4f15a0e880e7984d035
|
|
| MD5 |
9160ce935a91383c3739c19533274878
|
|
| BLAKE2b-256 |
7778519763aba8d8ec63d564e01410fc7b6b6bfe38f5eadbc9a5a1ac8ca23a1a
|
File details
Details for the file agent_detector-1.1.1-py3-none-any.whl.
File metadata
- Download URL: agent_detector-1.1.1-py3-none-any.whl
- Upload date:
- Size: 8.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
18d706d088962f85eca0cda5aa363b751efdd76acff2efcd7f2408d4cd38b163
|
|
| MD5 |
e7e7b01d9d910a59b285fe33ccceed8c
|
|
| BLAKE2b-256 |
3a2cff2826a85fedfaee10ef0768fd63ccfd6191f2a47a770f63c6de616be0cd
|