Agent Identity for Real Teams
Practical guide: which AI agents need their own identity, where that identity actually lives, best practices vs. anti-patterns, and copy-paste templates for AGENTS.md and .claude/agents/ — by team size and sophistication.
What kind of agent are we even talking about?
The word "agent" covers a huge range. For PCA — and for governance generally — the right question isn't "is it an LLM-powered agent?" but "does it persist long enough that someone might ask later who told it to do that?"
Two ends of the spectrum:
| Ephemeral tool | Persistent principal |
|---|---|
| Lives for one task | Lives for weeks, months, years |
| Spawned by a parent session | Has its own deployment, its own auth |
| Inherits the parent's auth and audit trail | Has its own audit trail tied to its own identity |
| No name worth printing in a log | Has a stable, public-facing name |
| Example: a Claude Code teammate that researches one bug, then exits | Example: a code-reviewer bot that runs as a GitHub App, comments on every PR |
Claude Code's Agent Teams documentation is explicit about this: "teammates are ephemeral by design — they exist for the duration of a session and then they're gone, with no persistent identity, no memory across sessions, and no resume capability." That's a deliberate design choice, and it's the right one for in-session task decomposition. Those teammates don't need PCA. They don't need a DID. They don't need an entry in your agent_identities table.
PCA is for the other column. A persistent principal:
- has a name that means something across sessions (
code-reviewer, notagent-7c4a3f), - has an operator — a specific human accountable for what the agent does,
- has capabilities and constraints that exist between invocations (you can read them from a file, not infer them from prompt history),
- and gets referenced in audit logs, governance events, and downstream credentials by that name.
Quick check: would you be embarrassed to write "$AGENT_NAME made this commit" in a release note next year? If the name is meaningful to a future reader, the agent is a principal. If not, it's a tool.
Where does an agent actually "live"?
This trips people up the most. The short answer:
- The agent itself runs wherever its operator deploys it: a laptop, a CI runner, a Lambda function, a long-lived server, a Docker container, a Kubernetes pod, a managed cloud service. PCA doesn't care.
- The agent's identity is a small JSON document at a publicly resolvable URL. That document says: who the agent is, who's accountable for it, what it can do, and (optionally) what its public signing key is.
The identity document is what an external verifier looks at when they want to answer "is this thing real?" It's not the agent. It's metadata about the agent.
For Dictiva agents, the document URL pattern is:
did:web:dictiva.com:agents:code-reviewer
↓ resolves to
https://dictiva.com/agents/code-reviewer/did.json
The DID (Decentralized Identifier) is just a stable string that points to a URL. The W3C did:web method spec defines the URL transformation. Anyone can resolve it; no auth, no API key, no Dictiva account.
The did.json document at that URL is the agent's identity card. It carries:
id— the canonical DIDalsoKnownAs— alternate identifiers (email, GitHub handle, etc.)service— addressable endpoints (the agent's workbench page, MCP endpoint, webhook)verificationMethod— public key material (only if the agent self-signs; most don't)- Free-form fields like
description,selfDescribedRole,modelfor human / agent inspection
Where does one find them?
Three places, depending on who's asking:
- External verifier (any third party): they hit the public
did.jsonURL. No auth required. They get the metadata, can verify any signature the agent is named in. - Tenant operator (you, in the Dictiva workbench): the Teams → AI Workforce page lists every registered agent in your tenant, with operator, model, lifecycle state, and capability scopes.
- Programmatic access (your own integration):
GET /api/agent/identitiesreturns the same list as JSON, paginated, filterable. Auth: API key withagent_identity:read.
If you're searching for an agent and you don't know its DID, start at Teams → AI Workforce. Search by name, operator, lifecycle. Click through to a profile page that shows everything the DID document carries plus PCA credentials the agent has issued or been the subject of.
What does the agent's ID actually point to?
A DID is a layered indirection. Walking it:
"did:web:dictiva.com:agents:code-reviewer" ← stable identifier
↓ (resolved by W3C did:web method)
"https://dictiva.com/agents/code-reviewer/did.json" ← URL
↓ (HTTP GET)
{ ← DID document
"id": "did:web:dictiva.com:agents:code-reviewer",
"alsoKnownAs": ["mailto:code-reviewer@agents.dictiva.com"],
"service": [...],
"selfDescribedRole": "PR code quality reviewer for the team's repos",
"model": "claude-opus-4.6"
}
The DID is not an API key. It's not a credential. It's an identifier — like a URL, but designed to be portable across hosts and decentralized. The actual thing the DID points to is the JSON metadata, and from there you walk to keys, services, and other identifiers.
If you've used GitHub Apps, this is roughly the same shape: the App has a stable name, a metadata page (the App's settings), and optional signing material. PCA's DID is the standards-compliant version of that pattern.
A taxonomy by team size
You don't need all of this on day one. The right amount of agent-identity ceremony depends on how many agents you have, who relies on them, and what regulators (or auditors, or customers) might ask about them later.
Level 1 — Solo developer with Claude Code
You probably need none of this.
If your only "agents" are Claude Code teammates that spawn for a task and exit, or in-editor copilots, you don't need DIDs, AGENTS.md, or PCA. The Claude Code session has its own audit trail (terminal history, git commits authored by you). Your subagents are tools.
If you ever stand up a long-lived bot — a daily Cron job that opens PRs, an MCP server you share with collaborators — come back. Until then, optimize for getting work done.
Level 2 — Small team (2–10 people, 1–3 long-lived agents)
This is where AGENTS.md becomes useful. Drop one of these in your repo root:
# AGENTS.md
## Agent Identity
- **name**: code-reviewer
- **version**: 1.0
- **operator**: alice@example.com
- **model**: claude-opus-4.6 (or equivalent)
- **runtime**: GitHub App `acme-code-reviewer`
## Capabilities
- Read repository contents
- Comment on pull requests
- Suggest code changes (does NOT push or merge)
- Run designated test suites
## Boundaries
- MUST NOT push to `main` or any release branch
- MUST NOT modify CI configuration
- MUST NOT access secrets or environment variables
- MUST escalate to operator on dependency updates
## Source of authority
This agent operates under [docs/policies/code-review-bot.md](./docs/policies/code-review-bot.md), approved by alice@example.com 2026-03-15.
That's it. No PCA yet. Just a single human-readable document anyone can read — including the agent itself, since AGENTS.md is now stewarded by the Linux Foundation Agentic AI Foundation and supported by Claude Code, Codex, Cursor, and most modern coding agents. The OpenAI + Anthropic donation in December 2025 cemented it as a standard.
If a regulator or customer asks "what does this agent do?" you point them at AGENTS.md. That's level-2 sophistication.
Level 3 — Mid-size organization (10+ agents, regulated industry, customers asking)
Now you want:
- Stable DIDs for every persistent agent. Register them in your tenant. Operators get assigned. Capability scopes get formalized.
- AGENTS.md plus per-agent files at
.claude/agents/{name}.mdor your tool's equivalent. - Refusal rules in W3C ODRL format — machine-readable constraints that an MCP server or hook can enforce.
- PCA credentials at tier T4 or T5 — the agent has codified its commitment to specific governance statements with verifiable evidence.
- A revocation playbook — if the agent is compromised or decommissioned, who flips the bit? How fast?
This is where Dictiva becomes useful: registering agents, issuing PCA credentials, running the daily revalidation sweep, exposing public verification endpoints. Read PCA Overview and PCA API Reference for the mechanics.
Level 4 — Regulated enterprise (audit-driven, EU AI Act in scope)
Add to level 3:
- OSCAL
assessment-resultsexport of your agent fleet's PCA credentials, mapped to controls. - EU AI Act Article 14 evidence trail — for every high-risk decision, show the human-oversight checkpoint and the agent's commitment to following it.
- Cross-vendor verifiability — credentials issued by Dictiva but verified by a customer's own toolchain (no Dictiva account on the verifier side).
- Compliance bundle generation — point-in-time snapshot of every active agent, every active credential, every revocation event, signed and exportable.
PCA is built specifically for this layer. The composition of W3C VC + DID + Status List 2021 + ODRL + OSCAL means every part of the audit trail is validated by an external standards body, not by Dictiva's word.
Best practices
The OWASP Top 10 for Agentic Applications 2026 — published December 2025 by the OWASP Gen AI Security Project with 100+ industry experts — names Identity & Privilege Abuse (ASI03) as a top-tier risk and explicitly says agents should be treated as managed Non-Human Identities (NHIs). The patterns below are what that looks like in practice.
| Practice | Why |
|---|---|
| Stable identifiers | DIDs and slugs should outlive specific deployments. Don't churn IDs when you redeploy. |
| Named operators | Every agent has a specific human accountable for its behavior. Not a team alias. |
| Capability scopes | Explicit lists of what the agent CAN and CANNOT do, in machine-readable form. |
| Treat agents as principals | First-class user records (actor_type='agent'), not API keys masquerading as humans. |
| Public DID documents | Anyone can resolve them; no private API access needed. |
| Per-agent credentials | Each agent has its own client ID and secret. Not a shared service account. |
| Short-lived runtime tokens | Long-lived API keys are credentials of last resort. Prefer OAuth 2.1 + PKCE per the MCP Authorization spec. |
| Auditable revocation | When an agent is decommissioned, every verifier sees the revocation immediately — without your help. |
Anti-patterns (what NOT to do)
These are common, and they each create either a security or audit failure mode.
| Anti-pattern | Why it's bad |
|---|---|
| API keys as identity | Keys rotate, expire, get leaked. They're credentials, not identifiers. The same key can be used by multiple humans or agents. Audit logs read "key X did this", not "agent Y did this". |
| Service accounts under human users | Agent actions appear as the human's actions in audit logs. When something goes wrong, the human looks responsible. Reverses accountability. |
| Anonymous bots | "Some LLM commented on PR #42." Which LLM? Run by whom? Following what policy? Auditors hate this. So do incident responders. |
| Conflating ephemeral subagents with principals | Giving a Claude Code teammate its own DID is over-engineering — and inflates your agent_identities table with rows nobody can meaningfully revoke. Tools don't need names. |
| No revocation story | If an agent gets compromised, can you make every external verifier reject its credentials today, not next quarter? If the answer involves "we'll send out an email", you're not ready. |
| Conflating model and identity | "GPT-5" is a model. "claude-opus-4.6" is a model. Models change. Identities don't. The agent's identity outlives its model — when you upgrade, the same DID points to the new model. |
| Identity-as-prompt | "You are a code reviewer agent named Alpha." That's a system prompt, not an identity. It can't be verified externally. It changes every time the prompt changes. |
Templates
Copy these into your repository and edit. They're starting points; the actual content reflects your team's reality.
AGENTS.md (root of repo)
# AGENTS.md
> This file follows the [AGENTS.md spec](https://agents.md/), stewarded by
> the Linux Foundation Agentic AI Foundation. It is read by Claude Code,
> Codex, Cursor, Aider, and most modern coding agents at session start.
## Persistent agents in this repository
| Name | Operator | Runtime | DID |
|------------------|------------------|----------------------|--------------------------------------------------|
| code-reviewer | alice@acme.com | GitHub App | did:web:acme.com:agents:code-reviewer |
| docs-writer | bob@acme.com | Cloud Run service | did:web:acme.com:agents:docs-writer |
| sec-monitor | sec@acme.com | Self-hosted runner | did:web:acme.com:agents:sec-monitor |
> Ephemeral agents — Claude Code teammates, Codex workers — are NOT listed.
> They inherit identity and audit trail from the human session that spawned them.
## Conventions for all agents
- All agents MUST commit through their own GitHub App identity, never as a human.
- All agents MUST link to a governance statement they're acting under in the
PR description (`Attests: stmt-XXX tier=N`).
- All agents MUST escalate to their operator on any of:
- Production data access
- Secret rotation
- CI configuration changes
- Dependency updates touching > 1 major version
## See also
- [docs/policies/code-review-bot.md](docs/policies/code-review-bot.md)
- [docs/policies/docs-writer.md](docs/policies/docs-writer.md)
- [docs/policies/sec-monitor.md](docs/policies/sec-monitor.md)
.claude/agents/.md (per-agent file)
---
did: did:web:acme.com:agents:code-reviewer
operator: alice@acme.com
model: claude-opus-4.6
lifecycle: active
icon_key: CodeSquare
---
# Code Reviewer Agent
## Self-described role
I review every pull request opened against `acme/main-app` for code quality,
security issues, and adherence to our coding conventions. I post comments
inline with specific suggestions. I do not approve, request changes, or merge.
## Capabilities
- read all repository files except `secrets/**`
- comment on pull requests
- suggest line-level code changes
- run designated CI workflows for verification
## Refusal rules (ODRL-shaped)
- MUST NOT push to `main`, `release/*`, or any branch I'm not the author of
- MUST NOT modify `.github/workflows/**` or `infra/**`
- MUST NOT comment with secrets, credentials, or PII
- MUST escalate to alice@acme.com on:
- dependency upgrades crossing a major version
- any modification to authentication code
- PR descriptions referencing CVEs
## Source of authority
I operate under the policies enumerated in
[docs/policies/code-review-bot.md](../../docs/policies/code-review-bot.md),
approved by alice@acme.com 2026-03-15. My PCA credentials are issued by
acme.com tenant `did:web:acme.com:tenants:{tenantId}` and listed at
[Teams → AI Workforce](https://acme.dictiva.com/workbench/teams).
did.json (auto-generated when you register the agent)
You typically don't write this by hand. Dictiva generates and serves it at https://dictiva.com/agents/{slug}/did.json once you register the agent. For self-hosted scenarios:
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/ed25519-2020/v1"
],
"id": "did:web:acme.com:agents:code-reviewer",
"alsoKnownAs": [
"mailto:code-reviewer@agents.acme.com",
"https://github.com/apps/acme-code-reviewer"
],
"service": [
{
"id": "did:web:acme.com:agents:code-reviewer#workbench",
"type": "AcmeWorkbench",
"serviceEndpoint": "https://acme.dictiva.com/workbench/teams/code-reviewer"
}
],
"selfDescribedRole": "PR code quality reviewer for acme/main-app",
"model": "claude-opus-4.6"
}
Note: no verificationMethod field. The agent doesn't sign anything — its operating tenant does. The agent is a subject of credentials, not an issuer.
How this connects to PCA
A PCA credential answers "this agent committed to this rule, here's the proof." For that sentence to mean anything, the agent part has to refer to something stable, addressable, and verifiable.
Agent identity is the prerequisite. Without it:
- The credential's
subjectDidis a meaningless string - Verifiers can't dereference the agent for context
- Audit logs show actions taken by an unnamed entity
- Revocation has nothing to revoke against
With it:
subjectDid: did:web:acme.com:agents:code-reviewerresolves to the JSON above- The verifier sees who the operator is, what the capabilities are, and what model is running
- Audit logs name the agent, link to its profile, link to all its credentials
- Revocation flips a bit for that specific agent's credentials
If you're at level 2 or beyond, register your persistent agents first. Then issue PCA credentials. Don't skip ahead.
Where to go next
- PCA Overview — the credential side of the story
- PCA API Reference — every endpoint
- MCP Governance Server Guide — how agents authenticate at runtime
- AGENTS.md spec — the open standard, Linux Foundation AAIF
- OWASP Top 10 for Agentic Applications 2026 — the threat model
- Microsoft AI Agent Governance Toolkit — alternate reference implementation, OWASP-mapped
References
This page draws on:
- AGENTS.md spec, Linux Foundation Agentic AI Foundation, donated by OpenAI + Anthropic 2025-12-09
- OWASP Top 10 for Agentic Applications 2026, OWASP Gen AI Security Project
- OWASP Top 10 for Non-Human Identities, as referenced by Entro Security and ReversingLabs
- Claude Code Agent Teams documentation, Anthropic
- Model Context Protocol Authorization Specification, MCP project
- W3C Decentralized Identifiers v1.1 and W3C Verifiable Credentials Data Model 2.0