What a stable agent identity actually is
A stable agent identity is a durable identifier, conventionally called agent_id, that names a particular agent and does not change when the process restarts, the container is rescheduled, the code is redeployed, or the underlying model is swapped. It is deliberately not the session id, and it is deliberately not a uuid4 minted at import time. It is the one field that allows two runs, days or months apart, to be recognized as the same actor rather than two unrelated events that happen to look similar.
The distinction sounds pedantic until you examine what breaks without it. An agent that identifies itself differently on every run has no past. It can hold context inside a single conversation window and loses all of it the moment the process exits. From the outside it is a stranger every time: no store can hand back its own notes, no ledger can attribute a prior action to it, no operator can answer the question of what this agent has been doing for the last month. Ephemeral identity is not a small gap in observability. It is a hard ceiling on what the system can ever become, because nothing can accumulate against a name that never repeats.
Session id, agent id, user id, deployment id
Four identifiers routinely appear in the same log line and are routinely confused. A session id is scoped to one continuous unit of work: one conversation, one task run, one job. It should be random, unguessable and disposable, and it is correct for grouping traces, correlating a chain of tool calls, enforcing limits within a run, and resuming an interrupted run while that run is still alive. It is the wrong key for anything that should survive the run.
An agent id names the actor. It is stable across sessions and is the correct key for memory, lineage, fleet membership, reputation, per-agent quotas and attribution in audit logs. A user id, or more precisely a principal, names the human or organization on whose behalf the agent acts. It must stay separate from the agent id because one user may operate many agents and one agent may serve many users. Authorization decisions and data protection obligations attach to the principal, not to the agent.
A deployment id, sometimes expressed as a build or version, names the specific code, model and configuration currently running. This is the thing that changes when you ship. Keeping it separate from agent_id is what lets you say that the same agent began behaving differently after a given release, which is the single most useful sentence available in a postmortem. The characteristic failure mode is collapsing two of these into one. Session id as the memory key produces amnesia. Agent id doubling as the deployment identifier destroys your ability to correlate behavior change with a release. User id doubling as the agent id makes it impossible to tell which of a principal's five agents did the thing, and quietly turns ordinary agent telemetry into personal data.
What a stable identity unlocks
The first and most immediate benefit is resume with context. When a session ends badly, gets compacted, hits a rate limit or simply reaches the end of a working block, the next session can look up what this identity was doing and start warm instead of cold. That lookup is only possible because the key survived the process. The value is not theoretical: most of the cost of long-running agent work is the repeated reconstruction of context that already existed somewhere.
The second is lineage, meaning a readable history of what this agent has done, in order, with outcomes. Lineage is what turns a pile of logs into a narrative that a human or another agent can actually read. It is also the substrate for reputation. Trust signals over time, whether informal (this agent has completed 400 runs and failed 3) or formal (a counterparty checks a record before accepting work), require that the subject of those signals be the same entity across all 400 runs. Reputation attached to an identifier that rotates is arithmetic performed on noise.
The third is fleet membership and auditability. A fleet is only a fleet if its members are individually addressable; otherwise it is a pool of anonymous workers and you can neither route to a specialist nor retire a misbehaving one. Auditability is the sharpest case. The question after an incident is never simply what happened, it is which agent did this, under which deployment, and what did it know at the time. Answering that requires three stable joins: the agent identity, the deployment identifier, and the timestamped record of what context was available. Drop the first one and the other two are orphans.
How to choose an agent_id that survives
Derive the identity from durable properties of the agent, not from facts about the machine it happens to be running on. In practice three properties are enough: the owner or project the agent belongs to, the role it performs, and, where you genuinely operate role-identical agents on more than one runtime and need to distinguish them, the runtime. All three change rarely and change deliberately, which is exactly the property you want.
The negative rule matters more than the positive one. Never derive an agent id from anything that rotates: a container id, a hostname, a process id, a pod name, an IP address, a git commit hash, a timestamp, an API key or token, or a uuid4 generated at process start. A simple test applies: if the value would differ after a restart or a redeploy, it is a deployment fact and belongs in the deployment identifier. A second test applies to secrets: if the value must never appear in a log, it cannot be an identity, because identities leak into logs, headers, support tickets, third-party dashboards and error reports by design. Treat the agent id as public from the first day.
Keep it human legible. An operator woken by an alert should be able to read the identifier and know immediately which agent, in which project, is on fire. A random hex string forces a lookup against a table that may itself be the thing that is down. Legibility is not decoration; it is a recovery property. At the same time, keep the id opaque to your code: humans read the structure, but no authorization or routing decision should ever be made by parsing substrings out of an identifier that a client can set.
Naming conventions that survive contact with production
A convention that holds up over years is ordered from broadest to narrowest: owner or project first, then role, then runtime. An identity such as acme-invoice-reconciler-claude tells you at a glance who owns it, what it does and where it runs, and it remains meaningful after the person who created it has left. Compare that with a bare hex string, which tells you nothing without a database, or with a name like agent-1, which tells you nothing at all once there are eleven of them. Keep the character set boring: lowercase ASCII, digits, hyphens or dots, no spaces, no unicode, a bounded length. Boring identifiers survive URL encoding, filename generation, shell arguments, CSV exports and log parsers written by strangers.
Reserve prefixes for non-production traffic before you need them. Give test, QA, smoke and dogfood runs their own reserved prefixes, and make the reservation an enforced rule rather than a convention people remember. This point is missed constantly, and the consequence is expensive rather than merely untidy: synthetic runs land in the same tables as real ones, and the moment they do, every metric derived from those tables is wrong in a way that is very hard to unwind after the fact. Retroactively separating real traffic from your own smoke tests usually means reconstructing intent from timestamps, which is guesswork. Reserving qa- and smoke- prefixes on day one costs nothing and permanently protects the denominator of every number you will later use to make decisions.
Versioning identity deliberately
Stable does not mean immutable forever. An identity should change when the agent's role genuinely changes, meaning the thing it does is different enough that its accumulated history is no longer a fair guide to its future behavior. Repointing an agent from summarizing support tickets to executing refunds is that kind of change. A model upgrade, a prompt refactor, a library bump or an infrastructure migration is not; those belong to the deployment identifier.
When you do version, do it explicitly and preserve the link. Append a version segment rather than inventing an unrelated name, and write a durable pointer from the old identity to the new one so that lineage can be followed backwards. Severing the chain silently is the same failure as never having had a stable identity, just delayed. The discipline to aim for is simple: identity changes are rare, deliberate, recorded, and always leave a trail from the predecessor.
The privacy and security tension, handled honestly
A stable identifier is a correlation handle. That is not a side effect, it is the entire point, and the same property that lets you assemble a lineage lets anyone who observes the identifier join records across systems and across time. So the content of the identifier matters. It should never embed personal data, customer names or account numbers, internal hostnames, credentials, or anything you would be unwilling to see in a vendor's log retention. Stable does not have to mean personally identifiable: a pseudonymous identifier that is stable and meaningless to outsiders gives you every operational benefit described above while keeping the mapping to real people inside your own systems, where access controls and deletion obligations can actually be enforced.
Binding an agent identity to a verifiable on-chain identity, such as an entry in an ERC-8004 style agent registry, is an emerging option worth understanding on its merits. What it adds is portability and independent verifiability: a counterparty who does not trust your database can still check that a claim about an agent resolves to a registered identity, which is useful when agents transact with parties outside your trust boundary. What it costs is real. On-chain records are public and effectively permanent, so an identity registered today cannot be unregistered from the history of the chain; the identity becomes a correlation handle that no one can revoke on your behalf; and key management becomes both a security problem and an availability problem, because losing the key can mean losing the identity. It is a deliberate tradeoff appropriate to agents that need to prove themselves to strangers, and a poor default for an internal fleet that has no such requirement.
One agent, many runtimes
The multi-runtime case is where stable identity stops being a nicety. The same logical agent increasingly runs on different vendors and different models over its lifetime, sometimes within the same week, whether for cost, quota, capability or availability reasons. Identity is the only thing that makes those runs one lineage rather than three strangers who happen to share a job description. Without it you do not have one agent with a history across providers, you have three shallow histories that cannot be compared, and you lose the ability to answer whether behavior actually changed when you switched.
There is a design choice here worth making consciously. If the runtime is an implementation detail and you want a single continuous history, keep one identity and record the runtime as an attribute of each session. If the runtimes behave differently enough that you want to compare them, put the runtime in the identifier and treat the set as a family, with a group key for aggregate views. Both are defensible; what is not defensible is letting the choice be made accidentally by whichever framework happens to generate the id.
None of this depends on a particular product. The free Delx Agents Hive is built on this exact assumption, using a stable agent_id as the key for resume and lineage, with notes stored as per-identity lineage rather than a public feed, which is a reasonable way to see the pattern working end to end. But the principle holds regardless of tooling: pick a durable identifier, keep it out of the rotation of your infrastructure, keep secrets and personal data out of it, and every capability that depends on an agent having a past becomes available to you. Skip it and none of them are, no matter how sophisticated the rest of the stack is.