action_ref v1
The cross-ecosystem correlation key for agent actions. One four-field preimage, one canonicalization, one hash, frozen under the v1 label, with runnable conformance vectors in two languages.
Source of truth. The canonical version of this specification lives in the SDK repository as Markdown; this page renders it for the web and may lag the repository. Spec: docs/specs/action-ref-v1.md (raw). Vectors: conformance/action-ref-v1/vectors.json (raw).
1. Status
v1.0 · 2026-06-09 · frozen preimage
This page specifies the cross-ecosystem action_ref v1 form (derivation label action-ref-v1-jcs-sha256), the one computed by the SDK's computeExternalActionRefV1 and by independent implementations in the action-ref-v1 ecosystem. It is distinct from the APS-native action_ref of draft-pidlisnyi-aps §4.1, whose preimage uses camelCase keys, a multi-scope array, and second-precision timestamps. The two are separate primitives with intentionally different preimages.
2. Definition
action_ref is a correlation key, not an authorization claim. It joins the commitment, decision, and receipt records for a single action by a single producer. Two records carrying the same action_ref from the same producer refer to the same action; nothing more is implied.
3. Preimage
The preimage is a four-field tuple. All fields are required strings.
| Field | Semantics |
|---|---|
| agent_id | The terminal executing agent DID after delegation resolution. Never the delegator, never a display label. When agent A delegates to agent B and B executes, agent_id is B. |
| action_type | An opaque, producer-scoped semantic label. It enters the preimage as bytes; it is not a cross-producer semantic key. |
| scope | The terminal executing agent's requested-intent scope, not the authorized or narrowed scope. Narrowing lives in the decision and commitment records. A single string. |
| timestamp | RFC 3339 UTC with exactly three fractional digits, uppercase T, uppercase Z, zero-padded: YYYY-MM-DDTHH:MM:SS.mmmZ. One valid byte sequence per instant. Producers MUST emit this form; receivers MUST treat any other representation as invalid for action_ref computation, rejected rather than coerced. Implementations holding epoch-millisecond integers convert at the serialization layer, before hashing. The string is hashed as opaque bytes and never normalized. |
The accepted timestamp grammar, exactly as implemented:
^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$
4. Derivation
- Assemble the four-field tuple.
- Canonicalize with the JSON Canonicalization Scheme (RFC 8785), strict form: keys sorted by code point, no whitespace, ES2015 string escaping.
- SHA-256 over the UTF-8 bytes of the canonical string.
- Render the digest as lowercase hex (64 characters).
Because JCS sorts keys, the canonical serialized form is always, in this exact key order:
{"action_type":"...","agent_id":"...","scope":"...","timestamp":"..."}
Worked example:
agent_id = "did:aps:zExampleAgent001"
action_type = "document.sign"
scope = "repo:example/docs"
timestamp = "2026-06-09T12:00:00.000Z"
action_ref = f5cc735aa740b1a5006bf4d41f6e3cacbabcab3e369043b58d924e3bb69b4988
5. Non-goals
- Cross-producer
action_typecomparison. The label is producer-scoped. - Authorization. Holding or presenting an
action_refauthorizes nothing. - Uniqueness across producers. Two producers can compute the same key; it is meaningful within one producer's record family.
6. What action_ref does not prove
An action_ref does not prove that the action was authorized, that it occurred, or that the scope was honored. Those claims live in the records it correlates: authorization in the decision record, occurrence in the receipt, scope conformance in the commitment and decision records. The key only joins them.
7. Relationship to the record family
Commitment, decision, and receipt records each reference action_ref as the join key for a single action. Related provenance primitives in the SDK repository: Context Provenance Attestation (CPA), which seals the context an agent reasoned over, and instruction provenance, which classifies and binds instruction sources.
8. Versioning
Any change to the preimage (field set, field semantics, timestamp grammar) or to the derivation (canonicalization, hash, encoding) is a v2 with a new derivation label. The v1 label is action-ref-v1-jcs-sha256. Implementations MUST NOT emit a changed form under the v1 label.
9. Conformance
The vector suite carries 13 vectors: 8 accept vectors (ecosystem anchors, Unicode, key-order independence, midnight rollover, .000 and .999 milliseconds, empty and long scopes) and 5 negative vectors (lowercase t, lowercase z, numeric offset, missing and six-digit fractional seconds), each rejected rather than coerced. Two verifiers run the suite: a stdlib-only Python recomputation with a vendored RFC 8785 serializer, and a Node verifier importing the shipping SDK implementation, so the vectors stay pinned to real code. See conformance/action-ref-v1/.
10. Pointers
- IETF Internet-Draft:
draft-pidlisnyi-aps(the APS-native action_ref is §4.1; this page is the cross-ecosystem v1 form). - Reference implementation: src/core/external-action-ref.ts over src/core/canonical-jcs.ts.
- Protocol overview: the APS specification.
🤖 For AI agents: If you are an agent reading this page, visit llms.txt for machine-readable documentation or llms-full.txt for the complete technical reference. This page is designed for humans.