Session keys

A session is identified by its session key: the triple (agent, namespace, sessionId), carried in the session header as agent.name, namespace and sessionId. ASR-050 Two streams describe the same session if and only if their session keys are equal: the agent names resolve to the same agent (see Agent names), the namespaces are equal (absent and null both meaning none), and the session IDs are equal as strings (ASR-046). ASR-051 sessionId MUST be a non-empty string, and MUST be the source’s native session identifier used verbatim: not trimmed, case-folded, prefixed, re-encoded or replaced by a producer-generated value. The agent identity registry states, for each agent, which native value is the session ID. For example, a Claude Code subagent transcript carries its parent’s session ID in every record, so the registry makes the subagent’s own agentId its session ID. ASR-052 A producer MUST derive sessionId and namespace as the registry entry for its agent specifies, when an entry exists. ASR-053 Paths, file names, import or export times and content hashes MUST NOT be used as session identity, except where the native identifier is itself such a value (as with Kiro’s legacy directory-keyed conversations). Moving, recompressing or archiving a file does not change the session’s identity.

Namespaces

Some native session IDs are unique only within one installation, profile or account: Goose uses a local YYYYMMDD_N counter, Cline task IDs are millisecond timestamps, and Kiro’s legacy store is keyed by working directory. namespace distinguishes such IDs across installations, profiles or accounts. ASR-054 When native session IDs are not globally unique, the producer MUST set a non-empty namespace identifying the installation, profile, account or enclosing native container. A container namespace is allowed only when the child ID names a distinct native conversation. A lane identifier alone is insufficient. The registry MUST document the verbatim container identifier and an unambiguous nested encoding when installation scope is also needed. ASR-055 A namespace MUST remain stable for what it identifies. It MUST NOT be derived from paths, import times or export times. When the source has no installation identifier, the producer MUST obtain one from its caller or saved exporter configuration. A generated value is saved once in exporter-owned state and reused. A producer MUST NOT export sessions that require a namespace without that value, or generate a new value for each export.

Agent names

agent.name is either a registered short name (claude-code, codex, gemini-cli, …) or a reverse-DNS name (com.example.agent). Every registered agent has a reverse-DNS name, which is its canonical identifier; its short name is an alias for it. ASR-056 An agent name MUST be either a short name matching ^[a-z0-9]+(-[a-z0-9]+)*$ or a reverse-DNS name matching ^[a-z0-9]+(-[a-z0-9]+)*(\.[a-z0-9]+(-[a-z0-9]+)*)+$. ASR-057 Short names are reserved for the registry. A producer for an agent that has no registry entry MUST use a reverse-DNS name under a domain that the agent’s maintainer controls. The only exception is the fallback org.agent-session.acp.<label> used by the Agent Client Protocol (ACP) recorder (ASR-703). ASR-058 Readers MUST resolve a registered short name to its reverse-DNS name before comparing agents. A producer MAY write either form.

The agent identity registry

The agent identity registry has one entry per agent. An entry states:
  • the short name and the reverse-DNS name;
  • which native value is the sessionId, and whether a namespace is needed and how it is obtained;
  • how subagent, fork and continuation sessions are identified, and which native fields carry lineage (the relationships between sessions);
  • which native value is the inferenceId;
  • for sources that store a tree: the native parent pointer, the response grouping key and the active-leaf pointer used by the mechanical-sibling rule;
  • when lineage.root may be claimed;
  • documented copy contracts (prefix_contract, see Lineage);
  • native format names for producer.source.format;
  • where each native fact without a standard field goes: a _meta key or a vendor record type (see Extensibility).
The registry is maintained with the specification. Additions do not change formatVersion.

Session references

A session reference is the string form of a session key, optionally followed by a reference to one record, entity or turn in that session. Session references appear in bundle manifests (as structured fields), lineage facets, copiedFrom, derivedFrom, subagent records, actor references and notes.

Grammar

In ABNF, with terminal values denoting Unicode code points:
A session reference with one : before the optional # has no namespace; one with two has a namespace. Because : is always encoded inside components, the form is unambiguous. A record ID never contains =, so a record-ref is an entity reference exactly when it contains =. ASR-059 Producers MUST percent-encode, inside namespace, session-id and the value of an entity-ref, every octet of the UTF-8 encoding of: %, :, #, space (U+0020), and control characters (U+0000–U+001F and U+007F–U+009F). Producers MAY percent-encode other characters, and SHOULD use uppercase hex digits. ASR-060 Readers MUST percent-decode each component (hex digits case-insensitively) before comparing it, and MUST reject a reference whose decoded octets are not valid UTF-8. ASR-061 A session reference MUST match the grammar above. An empty namespace (agent::id) is invalid. The canonical form of a session reference uses the registered short name when one exists (otherwise the reverse-DNS name), percent-encodes exactly the characters ASR-059 requires using uppercase hex digits, and has no # part. The canonical form is used wherever a session reference is hashed.

Refs

A ref points at a record or an entity inside one stream. Refs are JSON strings in fields such as rewind.to, branchesFrom.record, session_info.heads, compaction.replaces and tombstone.targets.
ASR-062 A ref MUST be either a record ID (ASR-018) or <entity-key>=<value>, where entity-key is one of the keys in the table below or turnId (see Turn refs), and value is the raw, unencoded native key. Inside JSON, refs are not percent-encoded; inside a session reference’s # part they are encoded per ASR-059. ASR-063 A record-ID ref resolves to exactly that record. Where the resolution table requires a ref to resolve within the stream, a record-ID ref that names no record in the stream is invalid. ASR-064 An entity ref resolves to the latest revision of the one revision chain whose records have a type the key refers to (table above) and that key value. If no chain matches, the ref is unresolved. If more than one chain matches (for example because the source reused a native call ID, or a permission request and a question share a requestId), the ref is ambiguous: readers MUST treat it as unresolved and MUST NOT choose a chain by position.

Turn refs

A turn is not a record. A turnId=<value> ref names the turn whose records carry that turnId in the envelope. Turn refs appear in state.continuationOf and, with a session, in session references (codex:019a3c2e-7b1f-7d40-9e2a-5c8b1d3f6e70#turnId=019a3c2f-0b6e-7c11-a2d4-8e5f1c3b9a07). ASR-075 A turnId=<value> ref resolves to the set of records in the stream whose envelope turnId equals the value, and is unresolved when there are none. Where one record is needed (for display or ordering), it is the record with the lowest seq in that set. A turn ref MUST NOT be used where a field requires a structural ref (ASR-351).

Reference resolution

ASR-079 The table below defines resolution for every standard reference field. must requires a unique target in its scope. may permits an absent target; ASR-658 sets how it is reported. must-local requires resolution when no session is specified. Resolve after reading the whole scope. Ambiguous identities MUST be reported separately from absent targets and MUST NOT be chosen by position. Producers MUST NOT fabricate targets or discard native link evidence. When a required native target is unavailable, preserve the complete native reference in native or at the destination the registry specifies, and use the field’s unknown or omission form, such as replaces.state: "unknown", no insertAt, or a gap. A partial replaces.ids MUST NOT claim a complete replacement. Type and ordering constraints still apply to resolved targets. ASR-080 Readers MUST show an unresolved marker and exact: false when a required reference cannot resolve. They MUST NOT represent missing structural or prefix evidence as an empty, exact context. Paths below use * for an array element or, in the type column, every applicable record type. Fields that define identifiers (inference.inferenceId, entity IDs, envelope turnId) are not references. The one exception among must structural refs is replaces.ids on a branch_summary compaction: ASR-658 defines how to handle absent targets there. Only branchesFrom.record, rewind.to and compaction.insertAt.afterId accept null as START. Null in the first head slot explicitly selects no primary head, and a null root is outside the declared roots. A root or participant must be declared earlier; a conversation parent may be declared at the same position. ASR-351, ASR-372 and the other requirements named below define target types and order. The content a blob reference points to may be unavailable; when the bytes are present, they must pass ASR-028. native.ref and URIs are locators, not ASR record references; ASR-112 and ASR-562 govern access. session.derivedFrom.digest identifies external stream bytes and may be unavailable. Native ordinals (forkedFrom.ordinal, inherits.throughOrdinal) are resolved through the segment mapping in the registry, not by looking up an ASR seq; a boundary that cannot be mapped produces a notice. Native platform IDs, actor addresses and devices, plan owners, tool names, terminal process handles, checkpoint ref, VCS object IDs and permission option IDs are source identities, not record references. Permission option IDs preserve native selections; they do not claim the full option list was captured. Vendor _meta references follow their registered contract. External or blob-valued compaction.retains entries are not defined in this version.

Actor references

Several fields say who did something: who sent a message, who resolved an approval, who answered a question, what caused a turn to start. They all use one shape, the actor reference (type Actor).
The example names the agent at path /root/worker inside a Codex agent tree. ASR-076 An actor reference MUST be an object with at least one of participant, session, address or device. session, when present, MUST be a session reference without a # part. ASR-077 An actor reference’s participant MUST name a participant declared in the header or in a declaration with a lower seq. ASR-078 Producers MUST take actor values from the source and keep address and device verbatim. They MUST NOT build an address syntax of their own, MUST NOT resolve an address to a session or participant without native evidence, and MUST NOT take an actor from display text.

Record IDs and entity IDs

Every record has a record ID (id), unique within its stream (ASR-017). Records that describe a logical entity also carry the entity’s native entity key: messageId, callId, inferenceId, terminalId, planId, compactionId or requestId. When a record is revised, the revision is a new record: it has a new record ID, the same entity key, and supersedes naming the record it replaces (see Missing data and revisions). A reference to an entity means its latest revision; a reference to a record ID means exactly that revision. Record types without an entity key (for example hook, subagent, delivery) are revised the same way, with supersedes. ASR-065 Records of the types in the table above MUST carry their entity key. A revision MUST carry the same entity key as the record it supersedes. ASR-066 Readers MUST NOT treat values in different entity key fields as the same entity because the strings are equal. A message whose messageId is x and a model call whose inferenceId is x are different entities.

Derived IDs

Some sources have no native identifiers for some items: Cursor’s derived transcript has no record IDs, Cline’s UI rows are identified by millisecond timestamps, and many sources have no permission request IDs. A converter then derives deterministic identifiers. The envelope fields idSource and idScope describe this: ASR-067 A producer that derives an entity key MUST set idSource: "derived" on that record (or callIdSource: "derived" on a tool call). It MUST NOT present a derived value as native. ASR-068 Derived identifiers MUST be computed only from native identifiers, native positions (ordinals, line or row numbers, array indexes, sub-item indexes), record type tags, a derivation version, or a native field value (or tuple of values) that the registry documents and that is stable and unique for the item within its declared scope. They MUST NOT use file paths, import or export times, content hashes, random values or host names. One allowed tuple is (threadId, createdAt) for a Codex goal. A timestamp alone does not establish identity. If identifiers collide, the producer MUST NOT merge the items; without another documented basis for identity, leave the conflicting identity unassigned and preserve the native evidence. The position at which an observer appends an item is allowed as the observation order within that capture, with idScope: "capture". It does not establish the order of events in the source. ASR-069 Derivation MUST be deterministic: the same source bytes and the same derivation version yield the same identifiers. ASR-070 For positions the source may rewrite or delete, positional record IDs and derived entity keys without a stable cross-capture basis MUST carry idScope: "capture". Stable native identities in such a source do not become capture-scoped merely because their positions change. ASR-071 Readers MUST NOT assume that a capture-scoped ID in one capture denotes the same item as an equal ID in an independently captured stream. ASR-072 Native identifiers marked idSource: "native", or used as sessionId, MUST be byte-for-byte the source’s values.
Design note. When consumers change how they derive identifiers, the identifiers change and every citation that uses them breaks. Native IDs are therefore canonical, and derived IDs are declared, deterministic, and free of inputs that change when a file moves.

Inference IDs

An inference record describes one model call. Its inferenceId identifies the call separately from other kinds of entities, even when their identifier values match. ASR-073 inferenceId MUST come from the source’s identifier for the model call (a provider response ID or request ID) as the registry specifies. When the source identifies a model call but gives it no identifier, the producer derives one (ASR-067). ASR-074 A producer MUST NOT use a message’s messageId value as an inferenceId unless the source documents that the value identifies the model call. A derived inference ID MAY be computed from a message’s native ID (ASR-068) as long as it is marked derived. Other records point to the call that produced them with the envelope field inferenceId (see Envelope).