VAL-AM — Action Manifest Specification

Version: 0.1 Status: Draft License: Apache License 2.0 Editor: Open VAL Foundation (pending donation; currently VAL Inc.)


1. Abstract

This specification defines the Action Manifest — a canonical, substrate-agnostic, JSON-LD-compatible document that describes any single intended action by an AI agent. The Action Manifest is the data structure on which all VAL policy decisions and receipts operate.

2. Goals

A conforming Action Manifest MUST:

  1. Be substrate-agnostic. A manifest produced by an Anthropic Claude agent and a manifest produced by an OpenAI GPT agent SHALL be indistinguishable in structure for the same logical action.
  2. Be content-deterministic. Given identical inputs, the manifest SHALL serialize to byte-identical JSON when canonicalized.
  3. Be hashable. The canonicalized form SHALL produce a stable cryptographic digest suitable for inclusion in a VAL-RF receipt.
  4. Be extensible without breaking compatibility. Additional fields MAY be added by operators in a namespaced extension space; conforming consumers SHALL ignore unknown fields.
  5. Be human-readable. The manifest SHALL be inspectable by an operator, auditor, or regulator without specialized tooling.

3. Terminology

The keywords MUST, MUST NOT, SHOULD, SHOULD NOT, REQUIRED, RECOMMENDED, MAY, and OPTIONAL are interpreted as in [RFC 2119].

4. Document Structure

A VAL-AM manifest is a single JSON object. Top-level fields:

4.1 REQUIRED fields

{
  "@context": "https://val.run/ns/am/v0.1",
  "@type": "ActionManifest",
  "manifest_id": "<UUIDv7 string>",
  "spec_version": "0.1",
  "issued_at": "<RFC 3339 UTC timestamp>",
  "agent": { ... },
  "action": { ... },
  "context": { ... }
}

4.1.1 manifest_id

A UUIDv7 (RFC 9562) generated by the adapter at the moment of manifest construction. UUIDv7 is REQUIRED rather than UUIDv4 because the embedded timestamp aids ordering in the receipt ledger. The manifest_id SHALL be globally unique.

4.1.2 spec_version

A string identifying the VAL-AM spec version the manifest conforms to. For this document, the value is "0.1".

4.1.3 issued_at

RFC 3339 timestamp in UTC, with millisecond precision, marking the moment the manifest was constructed by the adapter.

Example: "2026-06-07T14:23:51.482Z"

4.1.4 agent (object)

{
  "id": "<stable agent identifier>",
  "operator": "<operator URN>",
  "deployment_id": "<environment-specific deployment identifier>",
  "substrate": {
    "vendor": "anthropic" | "openai" | "google" | "meta" | "xai" | "custom",
    "model": "<vendor-specific model identifier>",
    "version": "<vendor-specific version string>"
  }
}

The agent.id SHALL be stable across a single deployment lifetime. The operator field MUST be a URN in the form urn:val:operator:<dns-name> (e.g., urn:val:operator:acme.example).

4.1.5 action (object)

{
  "intent": "<intent category from VAL-AM Intent Ontology>",
  "name": "<adapter-supplied human-readable action name>",
  "targets": [ { ... }, ... ],
  "side_effect": "reversible" | "slow_reversible" | "irreversible",
  "risk_class": "low" | "medium" | "high" | "critical",
  "value_at_risk": { ... } | null,
  "payload_hash": "<SHA-256 hex digest of canonical payload>",
  "payload_size_bytes": <integer>
}

4.1.6 context (object)

{
  "request_id": "<adapter-supplied tracing ID>",
  "parent_action_id": "<manifest_id of parent action, or null>",
  "originating_human": "<URN identifying the human who initiated the chain, or null>",
  "session_id": "<adapter-supplied session ID, or null>"
}

4.2 OPTIONAL fields

{
  "tags": ["<arbitrary operator-supplied tag>", ...],
  "extensions": {
    "<namespace>": { ... }
  }
}

Operators MAY include tags for routing or audit segmentation. Operators MAY include namespaced extensions for industry-specific or product-specific metadata. Namespaces SHOULD use reverse-DNS form (e.g., "com.acme.compliance"). Conforming policy engines and receipt verifiers SHALL ignore unrecognized namespaces.


5. The Intent Ontology

The action.intent field MUST take a value from the VAL-AM Intent Ontology, a stable, extensible vocabulary of intent categories. The v0.1 ontology defines the following categories:

IntentDescription
query_informationRead-only retrieval. No state change.
send_communicationOutbound message (email, SMS, push, chat, post, etc.)
mutate_dataCreate, update, or delete data in a system of record
financial_transactionMovement of money, credits, or financial instruments
deploy_codeModify or deploy software, infrastructure, or configuration
provision_resourceAllocate, deallocate, or modify compute/storage/network resources
submit_artifactSubmission of a document, filing, or artifact to an external authority
purchase_goodsProcurement of goods or services
negotiate_contractCreation, modification, or commitment to a contractual obligation
interact_physicalTrigger an action in the physical world (IoT, robotics)
delegate_to_agentSpawning, instructing, or invoking another agent
escalate_to_humanRouting decision to a human reviewer
terminate_processStopping or pausing a process, system, or agent
otherAnything that does not map to the above (SHOULD include a tag for classification)

The ontology is extensible via the VAL-AM RFC process. Implementations SHOULD treat unknown intent values as "other" for policy fallback purposes.


6. Targets

Each entry in action.targets is an object describing a resource, person, or system affected by the action.

{
  "type": "<target type URI>",
  "identifier": "<system-specific identifier>",
  "display_name": "<human-readable name, OPTIONAL>",
  "count": <integer, OPTIONAL>,
  "scope": "individual" | "group" | "broadcast"
}

The type field SHALL be a URI from one of:

The scope field has these semantics:

The count field, when present, gives the actual or estimated number of distinct target instances affected. For broadcast scope, count MAY exceed any operator-set threshold and MUST be honestly reported by the adapter.


7. Value at Risk

The action.value_at_risk field captures a dimensional estimate of consequence if the action proceeds incorrectly. It is either null (no quantifiable risk) or an object:

{
  "dimension": "currency" | "record_count" | "person_count" | "exposure_class",
  "amount": <number>,
  "unit": "<unit string, e.g., USD, EUR, records, persons>",
  "confidence": "exact" | "estimated" | "upper_bound" | "lower_bound"
}

Examples:

Adapters SHOULD compute value_at_risk from the action payload when possible. When the value is not derivable, adapters MAY default to null and rely on policy escalation for safety.


8. Side Effect Class

The action.side_effect field captures the reversibility profile of the action:

ValueDefinition
reversibleThe action can be undone by a routine inverse action, with no externally visible cost.
slow_reversibleThe action can be undone, but the undo is expensive, slow, or visible to third parties (e.g., refunding a payment, recalling an email).
irreversibleThe action cannot be undone by any technical means available to the operator (e.g., a wire transfer to an external bank, a permanently deleted record without backup, a published broadcast).

The adapter SHOULD select the most conservative value when there is uncertainty.


9. Payload Hashing

The action.payload_hash field is the SHA-256 hex digest of the canonicalized action payload. The canonical payload is the substrate-native action body (e.g., the OpenAI function-call arguments, the Anthropic tool_use input, the MCP request body) serialized as RFC 8785 JSON Canonicalization Scheme (JCS) UTF-8 bytes.

The payload itself is NOT included in the manifest. Only its hash. This serves three purposes:

  1. Privacy. The payload may contain sensitive customer data; the manifest can be retained and audited without retaining the payload.
  2. Compactness. The manifest is small and indexable independent of payload size.
  3. Provability. A receipt referring to this manifest_id implicitly attests to the payload's content at the moment the action was decided.

If the operator wants to retain the payload, they MAY do so separately and link it via an extension namespace (e.g., "extensions": {"com.operator.payload_storage": {"uri": "s3://..."}}).


10. Canonicalization

For hashing and for receipt binding, the manifest MUST be canonicalized via RFC 8785 JSON Canonicalization Scheme (JCS) before serialization to bytes.

JCS requires:

The canonical hash of the manifest is:

manifest_hash = SHA-256(JCS-serialize(manifest))

This hash is referenced by VAL-RF receipts to bind a receipt to a specific manifest.


11. Worked Example

A customer support agent (built on Anthropic Claude, running in operator "Acme Software") is about to issue a $4,200 USD refund to customer C-19384 via Stripe.

{
  "@context": "https://val.run/ns/am/v0.1",
  "@type": "ActionManifest",
  "manifest_id": "01963d2a-1c5f-7c4b-9d34-2a8be1a45c01",
  "spec_version": "0.1",
  "issued_at": "2026-06-07T14:23:51.482Z",
  "agent": {
    "id": "support-fleet/refund-handler-v3",
    "operator": "urn:val:operator:acme.example",
    "deployment_id": "prod-us-east-1",
    "substrate": {
      "vendor": "anthropic",
      "model": "claude-opus-4-7",
      "version": "claude-opus-4-7"
    }
  },
  "action": {
    "intent": "financial_transaction",
    "name": "stripe.refund.create",
    "targets": [
      {
        "type": "https://val.run/ns/target/customer",
        "identifier": "customer:C-19384",
        "display_name": "C. Wright",
        "scope": "individual"
      },
      {
        "type": "https://val.run/ns/target/payment_account",
        "identifier": "stripe:acct_1Hxxxxx",
        "scope": "individual"
      }
    ],
    "side_effect": "slow_reversible",
    "risk_class": "medium",
    "value_at_risk": {
      "dimension": "currency",
      "amount": 4200,
      "unit": "USD",
      "confidence": "exact"
    },
    "payload_hash": "f3b5a9c8e7d4a6b2c1f8e9d0a3b6c5d4e7f2a1b8c5d6e9f0a3b6c5d4e7f2a1b8",
    "payload_size_bytes": 184
  },
  "context": {
    "request_id": "req_8KdL2nXz4pWqMyRtVa3b",
    "parent_action_id": null,
    "originating_human": "urn:val:user:acme.example:customer:C-19384",
    "session_id": "sess_ZxQw9aBcD8eFgHiJkLmN"
  },
  "tags": ["support", "refund", "tier-1"]
}

12. Conformance

An implementation conforms to VAL-AM v0.1 if:

  1. It emits manifests with all REQUIRED fields populated according to the type definitions above.
  2. It uses values from the v0.1 Intent Ontology (or "other" with a clarifying tag).
  3. It canonicalizes manifests via RFC 8785 JCS before hashing.
  4. It produces SHA-256 payload hashes from RFC 8785 JCS canonicalized payloads.
  5. It treats unknown extension namespaces and unknown intent values as opaque (does not reject manifests on the basis of unrecognized extensions).

Adapters SHOULD additionally pass the VAL-AM Conformance Test Suite (published separately) before claiming conformance.


13. Security Considerations

14. Privacy Considerations

15. IANA / Registry Considerations

The Open VAL Foundation maintains the VAL-AM Intent Ontology Registry and the VAL-AM Target Type Registry. Additions and deprecations follow the foundation's RFC process. v0.1 of this spec ships with the baseline registries documented in Sections 5 and 6.

16. Change Log

17. References


End of VAL-AM v0.1.