| Internet-Draft | Action Reference | June 2026 |
| Etcheverry | Expires 27 December 2026 | [Page] |
This document defines "action_ref", a deterministic, content-addressed identifier for autonomous agent actions. Any party holding the four preimage fields (agent_id, action_type, scope, timestamp) can independently compute and verify the identifier without trusting the emitting system. The document specifies the derivation algorithm, canonical serialization using RFC 8785 JSON Canonicalization Scheme (JCS), timestamp format requirements, canonical receipt envelope, optional fields for revocation and policy rotation auditability, scope conventions, and a composability model with existing exactly-once execution guarantees.¶
Discussion of this draft takes place on the argentum-core repository: <https://github.com/giskard09/argentum-core>. A conformance test suite with byte-verified vectors is maintained at <https://github.com/giskard09/argentum-core/tree/main/examples/conformance>.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 27 December 2026.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document.¶
Autonomous agents operating across distributed systems need a way to identify individual actions that is independent of any single system's infrastructure. Existing audit trail mechanisms rely on operator-managed identifiers — UUIDs, database primary keys, or system-specific event IDs — that cannot be verified by a third party without trusting the issuing system.¶
This document defines "action_ref": a deterministic identifier derived from four preimage fields that any party can independently compute. The identifier is content-addressed — it is derived from the action content itself, not from a sequencer or registry. A verifier holding the four fields can recompute it without any call to the operator's infrastructure.¶
The design goal is operator-independence: a receipt carrying action_ref can be verified by an auditor, a smart contract, or a competing system without trusting the emitter. This property is structural, not procedural — it follows from the derivation algorithm, not from operator policy.¶
An automated static analysis of 35,689 agent-ecosystem endpoints [AgentGraph-EvidenceAnchor] found that 636 of 7,029 MCP servers (~9%) carry a high or critical finding — hardcoded secrets, unsafe exec/eval, missing authentication, or known-vulnerable dependencies — detectable by static analysis alone. This motivates an independently-verifiable evidence anchor for scan results, so a relying party can confirm a verdict without trusting the scanner operator.¶
This document covers:¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
The preimage is a JSON object containing exactly four fields:¶
| Field | Type | Description |
|---|---|---|
| agent_id | string | Stable identifier for the executing agent at issuance time — the terminal executor after full delegation resolution. In a delegation chain A→B→C where C executes the action, agent_id is C. |
| action_type | string | Semantic label for what the agent did (e.g., "code.execute", "payment.send", "oracle.signal"). |
| scope | string | Terminal executing agent's requested-intent scope at the point of action. Non-empty string. MUST NOT be a derived hash of the intent object (see Section 6). |
| timestamp | string | RFC 3339 UTC with exactly 3 millisecond digits. Format: YYYY-MM-DDTHH:MM:SS.mmmZ. See Section 3.4. |
The four fields are REQUIRED. No additional fields enter the preimage. Optional fields in the receipt envelope (Section 4) do not affect the action_ref value.¶
The four fields MUST be serialized using RFC 8785 JSON Canonicalization Scheme (JCS) before hashing:¶
The resulting JCS payload for a conformant implementation will sort keys in this order: action_type < agent_id < scope < timestamp.¶
Implementations using the simple json.dumps approach (Python, Node.js) produce RFC 8785-compatible bytes for inputs within the safe band: ASCII-only field values, conformant RFC 3339 timestamps, no surrogate-pair Unicode. For inputs outside this band, implementations MUST use an RFC 8785-compliant library.¶
action_ref = SHA-256(JCS(preimage)), encoded as lowercase hexadecimal.¶
The output is a 64-character lowercase hex string (256 bits / 32 bytes). Uppercase hex is non-conformant.¶
The timestamp field MUST conform to the following format constraints:¶
These constraints close the [RFC3339] underspecification surface. RFC 3339 admits multiple lexically distinct encodings of the same instant that produce different SHA-256 digests under JCS. This specification closes that surface at the format level.¶
Implementations holding epoch-millisecond integers MUST convert to the conformant RFC 3339 string before hashing. Implementations that hash the epoch-ms integer directly are not conformant.¶
The W3C CG ai-agent-protocol discussion (issue #34) established epoch-millisecond integer as an application-layer representation. This specification uses the RFC 3339 string form in the preimage. The two representations are not interchangeable in the preimage — they produce different digests.¶
The following example is byte-verified in the conformance suite (vector "nexus-oracle-signal"):¶
Input:
agent_id = "nexus-agent-xa12.onrender.com"
action_type = "oracle.signal"
scope = "BTC"
timestamp = "2025-05-18T11:40:31.000Z"
JCS payload:
{"action_type":"oracle.signal","agent_id":"nexus-agent-xa12.on
render.com","scope":"BTC","timestamp":"2025-05-18T11:40:31.000Z"}
SHA-256:
fdd7f810499f06be24355ca8e2bfb8c4b965cc80c838f41fa074683443d89f5a
¶
Implementations that emit a receipt referencing this specification SHOULD include the following fields to ensure long-lived verifiability:¶
{
"packet_version": "1.0",
"action_ref": "<sha256 hex>",
"hash_algo": "sha256",
"preimage_format": "jcs-rfc8785-v1",
"preimage": {
"agent_id": "...",
"action_type": "...",
"scope": "...",
"timestamp": "2026-05-15T10:00:00.123Z"
}
}
¶
The canonical receipt envelope v1.0 records state at the moment the action was claimed. It does not record whether that state was still valid when the action was admitted for execution. Two failure modes this gap creates:¶
Three optional fields close this gap:¶
A verifier that requires post-rotation auditability SHOULD treat a receipt missing either field as unauditable for the rotation window — not as invalid.¶
The millisecond precision for revocation_check_at_ms is REQUIRED. Credential checks in live multi-agent systems happen at sub-second granularity. Systems that only have second-precision timestamps SHOULD multiply by 1000 and document the precision loss.¶
Note: the three optional fields in this section correspond to the "freshness" verification layer described in discussions on the agntcy/identity repository (issue #165). A verifier confirming offline signature integrity (integrity), checking that the executed scope sat within the delegated scope (authority), and establishing the key validity window at decision time (freshness) needs all three layers. The fields in this section address the freshness layer; the authorization_ref in Section 5 addresses the authority layer.¶
action_ref is the correlation key across a three-record trail:¶
A conformant verifier runs four independent checks across the trail:¶
| Check | Fields compared |
|---|---|
| Same call instance | action_ref in pre-execution == action_ref in receipt |
| Same proposed payload | original_args_digest recomputed from disclosed args |
| Same dispatched payload | effective_args_digest in pre-execution == verifier-recomputed from receipt |
| Same authorization decision | authorization_ref in pre-execution == authorization_ref in receipt |
A trail that passes the first three checks but fails the fourth proves that execution proceeded under a different approval than the one recorded in the pre-execution entry.¶
The same action_ref is computable from artifacts produced by independent systems using the same four-field derivation:¶
Any verifier holding one artifact can validate against another without trusting either system.¶
scope is a free-form non-empty string. Any value is valid as long as it is non-empty and consistent across all parties deriving the same action_ref.¶
RECOMMENDED convention (non-normative): namespace-prefix with the emitter identifier using <emitter>:<scope>, for example "algovoi:compliance_screen" or "presidio:x402.screen:clean-allow". Prefixing avoids collisions when trails from multiple emitters are verified or aggregated by a third party.¶
The scope anti-pattern: scope MUST NOT be a derived hash of the intent object. A common mistake is to hash the initial intent object and use that hash as the scope value. This breaks the primary verifiability property: any party holding the four preimage fields must be able to recompute action_ref independently, without retrieving any external record. With a hashed scope, a verifier cannot recompute action_ref from the intent tuple alone — they must also retrieve the commitment record.¶
Multi-value scope segments: when a scope segment encodes a set of values (e.g., entity types detected by a screening decision), implementations MUST sort those values lexicographically and join them with a comma and no spaces. This ensures byte-determinism across implementations that may produce values in non-stable detection order.¶
A conformance test suite with byte-verified vectors is maintained in [argentum-core].¶
The suite includes:¶
Each conformance directory includes verify.py and verify.mjs. All vectors are byte-identical across implementations. The stable tag for v1.0 is "action-ref-v1.0" in the argentum-core repository.¶
External conformance sets accepted under review:¶
action_ref is deterministic: the same four preimage field values always produce the same identifier. This is a design property — it enables cross-system correlation without operator trust. The implication is that action_ref alone does not prevent replay.¶
Replay protection requires the receipt to carry:¶
A verifier that checks action_ref alone (without authorization_ref and signature) cannot detect replay. This specification requires both fields for complete replay resistance.¶
If scope is not validated at emission time, an adversary can inject a scope string that differs from the actual intent. The action_ref will be a valid hash of the injected scope, not of the actual action. Verifiers SHOULD require that scope is provided by the executing agent, not derived or transformed by an intermediary system.¶
A non-conformant timestamp (wrong precision, wrong timezone suffix, epoch-ms instead of RFC 3339 string) produces a different digest. This can be used to generate action_refs that appear valid but cannot be independently recomputed by a conformant verifier. Implementations MUST validate timestamp format at emission time, not only at verification time.¶
The operator-independence property holds only if:¶
An emitter that uses a non-public agent_id (e.g., a UUID assigned by an internal sequencer and not disclosed) breaks the verifiability property: a verifier cannot recompute action_ref without retrieving the agent_id from the operator. Implementations MUST use stable, publicly disclosed agent identifiers.¶
action_ref is compatible with SCITT transparency logs [I-D.ietf-scitt-architecture] as an anchoring layer. A SCITT-enabled system can treat action_ref as the payload hash submitted to a Transparency Service: the resulting SCITT receipt provides a signed inclusion proof over the same content-addressed identifier defined in this specification. The on-chain anchor described in Section 6 is conceptually equivalent to a SCITT receipt — both bind a content-addressed identifier to an external, operator-independent timestamp — but the on-chain variant does not require hardware TEE endorsement or a dedicated Transparency Service deployment. Implementers operating within SCITT-enabled infrastructure MAY substitute a SCITT receipt for the on-chain anchor without changing the action_ref derivation algorithm or the receipt envelope structure defined in this document.¶
This document has no IANA actions.¶
All vectors are byte-verified in the conformance suite at <https://github.com/giskard09/argentum-core/tree/main/examples/conformance>.¶
Vector: nexus-oracle-signal (action-ref-v1-baseline)
agent_id = "nexus-agent-xa12.onrender.com"
action_type = "oracle.signal"
scope = "BTC"
timestamp = "2025-05-18T11:40:31.000Z"
JCS payload (UTF-8):
{"action_type":"oracle.signal","agent_id":"nexus-agent-xa12.on
render.com","scope":"BTC","timestamp":"2025-05-18T11:40:31.000Z"}
action_ref:
fdd7f810499f06be24355ca8e2bfb8c4b965cc80c838f41fa074683443d89f5a
¶
Vector: neg-b01-epoch-integer (recompute-drift-v1)
Same action as A.1, but timestamp hashed as epoch-ms integer
instead of RFC 3339 string. Produces a different digest.
Non-conformant preimage (epoch-ms as integer — DO NOT USE):
{"action_type":"oracle.signal","agent_id":"nexus-agent-xa12.on
render.com","scope":"BTC","timestamp":1747568431000}
A verifier recomputing from the RFC 3339 string will obtain
a different hash and correctly reject the receipt.
¶
Contributed by: AgentGraph (agentgraph-co/agentgraph, kenneives).¶
This conformance set anchors static analysis findings from an agent-ecosystem endpoint scan (35,689 endpoints; June 2026) to verifiable action_ref identifiers. It contains 4 byte-verified vectors covering three invariants:¶
All 4 vectors are byte-verified in the conformance directory at <https://github.com/agentgraph-co/agentgraph>. The set was contributed under AGT PR #21 (evidence-anchor-static-analysis-v0, merged 2026-06-24).¶
Systems that have adopted action_ref derivation or compatible primitives:¶
| System | agent_id mapping | action_type mapping | Notes |
|---|---|---|---|
| SafeAgent (azender1) | agent identifier | claim type | Joint spec argentum-core #7 |
| Graph Advocate (PaulieB14) | wallet address (EIP-55) | counterparty event type | counterparty-ref-v1, production |
| AgentOracle/AgentTrust (TKCollective) | issuer DID | oracle action type | Two issuers, cross-issuer property |
| CTEF ([CTEF]) | agent graph node ID | evaluation action | action_ref REQUIRED in v0.4 |
| presidio-x402 (vstantch) | screening agent ID | presidio:x402.screen | PII screening, composition |