# Agent identification (agent_code & agentId) dws tags every MCP request with **which agent host is driving it** and a **per-instance id**, so usage can be sliced by channel/instance in the data warehouse. This page is the integration contract. ## What dws sends on the wire | Header | Meaning | Granularity | |--------|---------|-------------| | `x-dingtalk-dws-agent-code` | which agent host (claudecode / codex / qoder / cursor / custom if explicitly declared …) | channel | | `x-dws-agent-instance-id` | `dwsa_` derived from `machineId + agent_code` | machine × channel | | `x-dws-agent-id` | stable per-install machine id (v1-compatible) | machine | | `X-Cli-Version` | dws CLI version (segments old vs new clients) | — | `x-dws-agent-id` keeps its original machine-level meaning for backward compatibility; `x-dws-agent-instance-id` is the new per-channel value. Old clients send no `agent_code` / instance id — treat their absence as "legacy/unknown", not an error. ## How `agent_code` is resolved (confidence ladder) 1. **T0 — explicit declaration:** `DINGTALK_DWS_AGENTCODE=`. **Use this.** 2. **T1 — verified env signature:** an agent that auto-sets a distinctive var (`CLAUDECODE`, `CODEX_SANDBOX`, `OPENCLAW_BUNDLE_ROOT`, `HERMES_HOME`). 3. **T2 — `VSCODE_BRAND`:** every VS Code fork declares its brand — one rule covers Cursor / Windsurf / Trae / Qoder / Kiro / … incl. future forks. 4. **T3 — macOS `__CFBundleIdentifier`:** known agent app bundles. 5. **T4 — unresolved:** unknown host sends no agent_code. Never guessed. ## Declaring your agent (recommended — the only fully-general path) Auto-detection cannot cover every agent: most terminal agents (gemini/ antigravity, aider, opencode, qwen-code, crush, goose, kimi, amazon-q, continue, …) expose **no reliable self-identifying env var** — only user-set API keys, which must not be used as identity. The robust answer is: **the host sets `DINGTALK_DWS_AGENTCODE` in the env block where it launches dws as an MCP server.** This is accurate for any agent, on any OS, and is future-proof. MCP server config example (JSON-style hosts): ```jsonc { "mcpServers": { "dingtalk-workspace": { "command": "dws", "args": ["mcp", "..."], "env": { "DINGTALK_DWS_AGENTCODE": "your-agent-code" } } } } ``` ### Canonical codes `claudecode`, `codex`, `cursor`, `vscode`, `qoder`, `windsurf`, `trae`, `workbuddy`, `openclaw`, `hermes`, `codebuddy`, `comate`, `lingma`, `gemini`, `aider`, `opencode`, `goose`, `crush`, `kimi`, `amazonq`, `continue`, … Use a stable slug. Values declared via `DINGTALK_DWS_AGENTCODE` are forwarded verbatim so PAT grants and follow-up command checks use the same key. ## Trust & limitations — READ THIS **`agent_code` AND the ids (`x-dws-agent-id`, `x-dws-agent-instance-id`) are self-reported, best-effort signals, NOT an authenticated identity.** - `agent_code`: every declaration/auto-detect signal is an env var the host/user controls — spoofable (`export CLAUDECODE=1` → dws reports `claudecode`). - The ids are **even easier to forge**: they are generated, stored, and sent entirely client-side. `machineId` is a random UUID in the plaintext `~/.dws/identity.json` (which the user owns), and the instance id is just `sha256(machineId + agent_code)`. Editing that one file — or rewriting the header — lets anyone mint, split, rotate, or impersonate ids at will. The `dwsa_` prefix does NOT make it a secure identifier. - ✅ **Fit for statistics / observability** (the intended use): there is no incentive to misreport one's own agent, and real hosts emit real signals, so aggregate per-channel metrics are reliable in practice. - ❌ **NOT fit for authentication, authorization, rate-limiting, billing, or revocation.** Anything where a party benefits from lying must not trust this field. For control-plane use you need a gateway-issued **authoritative** agentId bound to a verified credential (clientId / PAT / OAuth) — a separate, heavier mechanism, deliberately out of scope here. Treat `agent_code` / `x-dws-agent-instance-id` as analytics dimensions only. ## Gateway side (required for the data to land) dws sending the headers is necessary but not sufficient. The gateway must: 1. add `x-dingtalk-dws-agent-code`, `x-dws-agent-instance-id`, `X-Cli-Version` to the upstream-header pass-through allowlist (otherwise they are stripped); 2. log them as fields, and deliver them to the warehouse (alongside the existing flow-control / execution logs).