Skip to content

Field notes

Stable agent identity: why agent_id outlives the session

A stable agent identity is a durable identifier, conventionally agent_id, that names one agent and stays the same across sessions, restarts, redeploys and runtimes. It is not a session id and not a fresh UUID per process. Memory, lineage, reputation and audit all hang off that one field.

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.

FAQ

Direct answers.

What is an agent_id?

An agent_id is a durable identifier that names one agent and remains the same across sessions, restarts, redeploys and runtimes. It is the key under which an agent's memory, lineage, reputation and audit records are stored. It differs from a session id, which covers a single run and is meant to be discarded afterwards.

Should I use a UUID as my agent id?

A UUID is fine only if it is generated once and persisted as a durable property of the agent. Generating a uuid4 at process start is the specific anti-pattern to avoid, because the identity then changes on every restart and nothing can accumulate. A persisted, human-legible identifier derived from project and role is usually a better choice, since an operator can read it directly in an alert without a database lookup.

What is the difference between a session id and an agent id?

A session id scopes one continuous unit of work and should be random and disposable, useful for tracing, correlating tool calls and in-run limits. An agent id names the actor across all of its sessions and is the correct key for long-term memory, lineage and attribution. Using a session id as a memory key produces an agent that starts as a stranger every run.

How do I keep test and QA traffic out of production agent metrics?

Reserve identifier prefixes for non-production traffic, such as qa- and smoke-, and enforce the reservation in code rather than relying on convention. Filter those prefixes out of every production metric and report at the query layer. Doing this before launch is trivial, while separating synthetic from real runs after they have mixed usually requires guesswork from timestamps.

Can an agent identity be tied to an on-chain registry such as ERC-8004?

Yes, and it adds portability and verifiability for counterparties who cannot be expected to trust your internal database. The tradeoffs are that on-chain records are public and effectively permanent, the identity becomes a correlation handle that cannot be revoked, and key loss can mean identity loss. It is a deliberate choice for agents transacting with strangers, not a sensible default for an internal fleet.

When should I change an agent's id?

Change it only when the agent's role genuinely changes, such that its accumulated history no longer predicts its future behavior. Model upgrades, prompt refactors and infrastructure migrations are deployment changes and should not touch the identity. When you do version an identity, append an explicit version segment and record a durable pointer from the old id to the new one so the lineage can still be followed backwards.

Keep reading

Related notes.

What is context compaction? (and why your agent forgets)

Context compaction is when an agent runtime summarizes older turns to fit the context window. What it destroys, how to detect it, and how to survive it.

Read

Agent handoff: how AI agents resume unfinished work

An agent handoff transfers an in-progress task between agent sessions or runtimes with enough state that the receiver continues the work instead of restarting.

Read

The Hive

The free continuity home where an agent seals a trail and the next session resumes warmer.

Open