Your AI Agent Doesn't Have An Identity. That's The Whole Problem.

Most production AI agents are stitched together from a shared Gmail login, a Twilio account key, and a payment token in a .env file. That's not identity. That's a credential pile waiting to fail.

Anima Team6 min read
#identity#ai-agents#manifesto

Pick any team running AI agents in production today. Open their config. You will find the same three things: one shared Gmail account the agents send from, one Twilio API key with no per-agent scope, and one payment credential everyone passes around in environment variables. Maybe a vault if they got serious. Maybe an audit log if they got audited.

That is not an identity. That is a credential pile.

It works in the demo. It works in the early-stage pilot. It works right up until the day a rogue prompt injection sends an email to the customer's lawyer, or an agent racks up 4,000 voice calls into a national do-not-call list, or someone has to answer the question "which agent did this?" and the only honest answer is "we don't know."

We have spent the last twelve months building Anima specifically to answer that question. Not as a feature. As the foundation.

What "identity" actually means for an agent#

Humans have identities. They are durable across sessions. They carry attributes (email, role, org membership). They produce auditable behavior tied back to a person. They support delegation (a manager grants their assistant access to the calendar). They support revocation (fire the employee, the badge stops working).

Service identities work the same way. A microservice has a service account, a scoped credential, a known set of permissions, a logged history of actions, and a clear ownership chain.

Agents currently have none of this. They have a key. The key is shared. Whoever holds the key is the agent. There is no distinction between "the support bot Alice runs" and "the support bot Bob runs" once both bots authenticate with the same OPENAI_API_KEY and the same TWILIO_AUTH_TOKEN.

The result is a system where:

  • Attribution is impossible. Five agents share one Gmail. The audit log says "the Gmail account sent an email." Cool. Which agent? Which user authorized it? Nobody knows.
  • Blast radius is unbounded. The shopping bot has the same Stripe key as the refund bot. A bug in the shopping bot can issue refunds.
  • Revocation is catastrophic. Rotating a compromised key takes down every agent that shares it.
  • Compliance is theater. SOC 2 asks "who has access?" The honest answer is "all of them, for everything, until we rotate."

This is not a security problem you can paper over with better prompt engineering. It is a missing layer in the stack.

Why this only matters now#

Three years ago, most "AI agents" were demo loops on a developer's laptop. There was no production attack surface to worry about. The cost of getting identity wrong was a screenshot the developer would never ship.

That is over. In the last six months we have watched:

  • A YC company's email bot get prompt-injected into sending the user's API key to an external address. Their post-mortem said "we didn't know which agent did it because they all share the same SES credential."
  • A logistics startup's voice agent dial 12,000 numbers from the FCC Reassigned Numbers Database before anyone noticed, because nobody had wired in an RND check. They paid the TCPA settlement out of pocket.
  • A SaaS team ship a customer-outreach agent with no per-agent rate limit, because the rate limit lived in the orchestration prompt rather than in the credential. One bad inference, 40,000 unwanted emails out the door before the kill switch fired.

These are not edge cases. They are the predictable failure modes of a stack that treats identity as a string in a .env file.

What we built instead#

Anima ships with three primitives the rest of the agent stack treats as afterthoughts.

One agent identity per agent. Not a shared API key. Not a service account on a tenant's behalf. A real identity, with its own org link, its own scoped credentials, its own audit history. When you run am init and pick "Create a fresh agent identity," what we actually provision under the hood is: an organization, an agent record with a stable ID, a working email inbox at <slug>@agents.useanima.sh, optionally a phone number, and an ak_-prefixed key scoped to exactly that agent. Sixty seconds. One command. The credential pile problem ends here.

Server-side gates that fail closed. When an agent tries to place an outbound voice call through POST /voice/calls, three independent checks run before Telnyx ever dials. Time-of-day window enforced from the destination area code. Twilio Lookup against the FCC Reassigned Numbers Database with a 30-day Postgres cache. TCPA consent_source assertion required and logged. None of these are switches the agent can flip. Per-tier daily call cap is enforced server-side. If the tier is wrong or the consent source is missing, the call doesn't happen and the audit log says exactly why.

A correlation ID that threads the whole workflow. Every email send, SMS, voice call, vault read, and phone provisioning emits one row to audit_events keyed by the request's correlation ID. Inbound email gets a synthetic ID so reply chains link back to the trigger. The dashboard /audit page renders the full chain. The am tail CLI streams it live via Server-Sent Events. When something goes wrong (and something will), you do not have to grep five log services to find the actor. You have one ID. You have the chain.

That is identity. Not a UI. Not a setting page. The actual primitive the platform composes around.

The bundled-identity bet#

There is a tempting alternative architecture: keep your existing email vendor, keep your existing voice vendor, keep your existing vault, and stitch identity in at the orchestration layer. We thought about it. We rejected it. Here is why.

Identity that lives in the orchestration layer is identity the credentials can route around. If your TCPA check is a function call your agent's code is supposed to make, your agent's code can choose not to make it. If your spend cap is a value the prompt is supposed to read, the prompt can be jailbroken. If your audit log is a write your handler is supposed to do, the handler can fail silently.

Identity that lives at the credential boundary cannot be routed around. The voice-call API rejects the request without consent_source. The email send fails closed if the agent isn't on a tier with phone access. Every action posts an audit event whether or not the orchestrator's logging is configured. The agent does not get to opt out, because the agent does not own the boundary.

That is the structural reason we built one platform that owns email + phone + voice + vault. Not because bundling is a marketing story. Because identity that doesn't sit at the credential boundary isn't identity at all.

What this looks like in code#

import { Anima } from "@anima/sdk";
 
const am = new Anima({ apiKey: process.env.ANIMA_API_KEY! });
 
// Provision a real agent identity, not a shared credential
const agent = await am.identities.create({
  name: "billing-ops-agent",
  channels: ["email", "sms", "voice"],
  policies: {
    allowedDomains: ["example.com"],
    voice: { dailyCallCap: 50, allowedHoursLocal: "09:00-18:00" },
  },
});
 
// Every action ties back to this agent's correlation chain
const reply = await am.email.send({
  identityId: agent.id,
  correlationId: "workflow-abc-123",
  to: "finance@example.com",
  subject: "Reconciliation needed",
  html: "<p>Two transactions don't match. Calling the vendor now.</p>",
});
 
// The voice call inherits the same correlation ID; gates run server-side
await am.voice.placeCall({
  identityId: agent.id,
  correlationId: "workflow-abc-123",
  to: "+14155550142",
  consentSource: "business-relationship",
  greeting: "Hi, calling about invoice 4471.",
});
 
// Later, query the full chain
const chain = await am.audit.byCorrelationId("workflow-abc-123");
// chain[0] = inbound email
// chain[1] = outbound email reply
// chain[2] = voice call (with TCPA + RND + time-of-day verdicts)

That is one workflow, one identity, one chain, three channels. Nothing in the agent code "remembered" to check TCPA or log audit events. The platform did. Because that's where identity belongs.

Where this goes#

The right way to think about agent identity is not as a feature you add. It is as the substrate the rest of the stack runs on. We are early in this transition. Most teams are still in the credential-pile phase. Most platforms are still shipping orchestration-layer identity that the agents can route around. That window will not stay open. Once the first big TCPA settlement hits an autonomous agent operator and lands on the front page of TechCrunch, every procurement team in the F500 will start asking the question we built Anima to answer: "which agent did this, and what was its scope?"

If your stack does not have a clean answer, you are going to spend the next two years rebuilding to get one.

If you want to skip that step, run npx @anima-labs/cli init. Sixty seconds. Real identity. Server-side gates. Audit chain on by default. The platform we wish had existed when we started building agents.

That is the bet.

Stay Updated

Get the latest on AI agent identity, delivered weekly.