



Network Working Group                                       J. Dembowski
Internet-Draft                                             20 April 2026
Intended status: Informational                                          
Expires: 22 October 2026


          Proof-of-Behavior Protocol for Autonomous AI Agents
            draft-dembowski-agentledger-proof-of-behavior-00

Abstract

   Autonomous AI agents execute actions — file writes, API calls, shell
   commands — on behalf of human principals.  No standard mechanism
   exists for a third party to verify that an agent acted within its
   declared behavioral rules, that policy enforcement occurred before
   execution (not after), or that the action log has not been tampered
   with after the fact.

   This document defines the Proof-of-Behavior (PoB) protocol: a
   minimal, language-agnostic standard for tamper-evident audit trails
   and pre-execution policy enforcement in AI agent systems.  The
   protocol specifies a signed receipt format, a hash-chain linking
   scheme, a policy gate contract, and a cross-agent reference
   mechanism.

Status of This Memo

   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 22 October 2026.

Copyright Notice

   Copyright (c) 2026 IETF Trust and the persons identified as the
   document authors.  All rights reserved.





Dembowski                Expires 22 October 2026                [Page 1]

Internet-Draft               AgentLedger PoB                  April 2026


   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.

Table of Contents

   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   2
     1.1.  Requirements Language . . . . . . . . . . . . . . . . . .   3
   2.  Terminology . . . . . . . . . . . . . . . . . . . . . . . . .   3
   3.  Protocol Overview . . . . . . . . . . . . . . . . . . . . . .   4
   4.  Receipt Format  . . . . . . . . . . . . . . . . . . . . . . .   4
     4.1.  Required Fields . . . . . . . . . . . . . . . . . . . . .   4
     4.2.  Action Object . . . . . . . . . . . . . . . . . . . . . .   5
     4.3.  Example Receipt . . . . . . . . . . . . . . . . . . . . .   6
   5.  Canonicalization  . . . . . . . . . . . . . . . . . . . . . .   6
   6.  Hash Chain  . . . . . . . . . . . . . . . . . . . . . . . . .   7
   7.  Signing . . . . . . . . . . . . . . . . . . . . . . . . . . .   7
   8.  Policy Gate . . . . . . . . . . . . . . . . . . . . . . . . .   8
   9.  Cross-Agent References  . . . . . . . . . . . . . . . . . . .   8
     9.1.  Cross-Agent Reference Object  . . . . . . . . . . . . . .   8
     9.2.  Resolution  . . . . . . . . . . . . . . . . . . . . . . .   9
   10. Checkpoint Hashes . . . . . . . . . . . . . . . . . . . . . .   9
   11. Storage . . . . . . . . . . . . . . . . . . . . . . . . . . .  10
   12. Key Persistence . . . . . . . . . . . . . . . . . . . . . . .  10
   13. Security Considerations . . . . . . . . . . . . . . . . . . .  10
     13.1.  Chain Rewrite  . . . . . . . . . . . . . . . . . . . . .  10
     13.2.  Key Compromise . . . . . . . . . . . . . . . . . . . . .  11
     13.3.  Same Trust Domain  . . . . . . . . . . . . . . . . . . .  11
     13.4.  Policy Bypass  . . . . . . . . . . . . . . . . . . . . .  11
   14. IANA Considerations . . . . . . . . . . . . . . . . . . . . .  11
   15. References  . . . . . . . . . . . . . . . . . . . . . . . . .  11
     15.1.  Normative References . . . . . . . . . . . . . . . . . .  11
     15.2.  Informative References . . . . . . . . . . . . . . . . .  11
   16. Normative References  . . . . . . . . . . . . . . . . . . . .  11
   Appendix A.  Receipt Schema Summary . . . . . . . . . . . . . . .  12
   Appendix B.  Reference Implementation . . . . . . . . . . . . . .  13
   Author's Address  . . . . . . . . . . . . . . . . . . . . . . . .  13

1.  Introduction

   AI agent frameworks (LangChain, AutoGen, CrewAI, and others) expose
   lifecycle hooks that allow external code to observe agent actions.
   These hooks are sufficient for logging but do not provide
   cryptographic guarantees.  A log written by the agent process being
   audited is not independently verifiable: the same software that
   produced the actions also produces the evidence.



Dembowski                Expires 22 October 2026                [Page 2]

Internet-Draft               AgentLedger PoB                  April 2026


   The Proof-of-Behavior protocol addresses three distinct problems:

   1.  *Tamper evidence*: Once an action is recorded, neither the agent
       nor its operator can modify or delete the record without
       detection.

   2.  *Pre-execution enforcement*: Policy decisions must be recorded
       before the action executes.  A DENIED record proves the agent was
       blocked; the absence of such a record proves the policy was not
       consulted.

   3.  *Cross-agent attribution*: In multi-agent systems, an
       orchestrator should be able to verify that a downstream agent
       completed a specific action under a specific policy, without
       trusting the downstream agent's in-process state.

1.1.  Requirements Language

   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].

2.  Terminology

   Receipt:  A signed JSON object recording a single agent action.
      Immutable once finalized.

   Chain:  An ordered, append-only sequence of receipts, each
      cryptographically linked to its predecessor.

   Policy Gate:  A pre-execution evaluation step that produces either an
      ALLOW or DENY verdict before any action is forwarded to the agent.

   DENIED Receipt:  A receipt with status "denied", written to the chain
      before the action is attempted.  Proves the policy gate ran and
      rejected the action.

   agent_id:  The raw bytes of the agent's Ed25519 public key, encoded
      as lowercase hexadecimal.  Serves as both identity and
      verification key.

   principal_id:  An opaque string identifying the human or
      organizational principal that authorized this agent's keypair.
      Format is binding-specific.

   policy_hash:  SHA-256 hash of the policy configuration, embedded in




Dembowski                Expires 22 October 2026                [Page 3]

Internet-Draft               AgentLedger PoB                  April 2026


      the signed receipt payload.  Ensures policy cannot be substituted
      without breaking signatures.

   prev_hash:  SHA-256 hash of the preceding receipt's canonical form
      (signature field excluded).  Null for the first receipt in a chain
      (genesis receipt).

3.  Protocol Overview

   The protocol operates in four phases for each agent action:

    ┌─────────────────────────────────────────────────────────┐
    │  1. POLICY EVALUATION (pre-execution)                   │
    │     PolicyGate.evaluate(action) → ALLOW | DENY          │
    │     If DENY: write DENIED receipt → raise error         │
    │     If ALLOW: continue to phase 2                       │
    ├─────────────────────────────────────────────────────────┤
    │  2. RECEIPT CREATION (pre-execution)                    │
    │     Build receipt with status=PENDING                   │
    │     prev_hash = SHA-256(previous receipt, no sig)       │
    │     policy_hash = SHA-256(policy config)                │
    ├─────────────────────────────────────────────────────────┤
    │  3. ACTION EXECUTION                                    │
    │     Forward action to agent/tool                        │
    │     Capture result or error                             │
    ├─────────────────────────────────────────────────────────┤
    │  4. RECEIPT FINALIZATION (post-execution)               │
    │     Set status = COMPLETED | FAILED                     │
    │     result_hash = SHA-256(result)                       │
    │     Sign receipt with Ed25519 private key               │
    │     Append to JSONL storage                             │
    └─────────────────────────────────────────────────────────┘

   The critical property of phase 1: the DENIED receipt is written to
   persistent storage and signed before the error is raised.  The agent
   process cannot proceed to phase 3 without passing phase 1, and cannot
   suppress the phase 1 record.

4.  Receipt Format

   A receipt is a JSON object [RFC8259] with the following top-level
   fields.

4.1.  Required Fields

   receipt_id (string):  A UUIDv4 string uniquely identifying this
      receipt.




Dembowski                Expires 22 October 2026                [Page 4]

Internet-Draft               AgentLedger PoB                  April 2026


   chain_id (string):  Equal to agent_id.  Identifies the chain this
      receipt belongs to.

   agent_id (string):  Lowercase hex encoding of the agent's Ed25519 raw
      public key (64 hex characters, 32 bytes).

   principal_id (string):  Opaque identifier for the authorizing
      principal.  Format is defined by the binding in use.

   timestamp (string):  ISO 8601 UTC timestamp of receipt creation
      (e.g., "2026-04-20T10:00:00.000000+00:00").

   prev_hash (string or null):  SHA-256 hex digest of the canonical form
      of the preceding receipt (signature excluded).  MUST be null for
      the first receipt in a chain.

   schema_version (string):  Protocol version.  This document defines
      version "0.1".

   action (object):  Describes the agent action.  See Section 4.2.

   signature (string):  Ed25519 signature over the canonical form of the
      receipt (signature field excluded), encoded as lowercase hex (128
      hex characters, 64 bytes).

4.2.  Action Object

   type (string):  One of: "tool_call", "llm_invoke", "decision",
      "cross_agent".

   framework (string):  The agent framework in use.  RECOMMENDED values:
      "langchain", "autogen", "crewai", "custom".

   tool_name (string or null):  Name of the tool invoked.  REQUIRED when
      type is "tool_call".

   status (string):  One of: "pending", "completed", "failed", "denied".

   payload_hash (string or null):  SHA-256 hex digest of the canonical
      JSON encoding of the action input.  MAY be null.

   result_hash (string or null):  SHA-256 hex digest of the canonical
      JSON encoding of the action result.  MUST be null when status is
      "pending" or "denied".

   error (string or null):  Human-readable error message.  SHOULD be set
      when status is "failed" or "denied".




Dembowski                Expires 22 October 2026                [Page 5]

Internet-Draft               AgentLedger PoB                  April 2026


   policy_hash (string or null):  SHA-256 hex digest of the policy
      configuration active at the time of evaluation.  MUST be set when
      a policy gate is in use.  Embedded in the signed payload.

4.3.  Example Receipt

   {
     "action": {
       "error": null,
       "framework": "langchain",
       "payload_hash": "e3b0c44298fc1c149afbf4c8996fb924...",
       "policy_hash": "3fa7188e44ea5c896b2a5d1068de1246...",
       "result_hash": "9f86d081884c7d659a2feaa0c55ad015...",
       "status": "completed",
       "tool_name": "web_search",
       "type": "tool_call"
     },
     "agent_id": "6c24573e8a4f2b9c...",
     "chain_id": "6c24573e8a4f2b9c...",
     "cross_agent_ref": null,
     "prev_hash": "a3f4b2c1d0e9...",
     "principal_id": "agent@example.com",
     "receipt_id": "550e8400-e29b-41d4-a716-446655440000",
     "schema_version": "0.1",
     "signature": "4a5b6c7d...",
     "timestamp": "2026-04-20T10:00:00.000000+00:00"
   }

5.  Canonicalization

   The canonical form of a receipt is used for both signing and hash
   computation.  It MUST be produced as follows:

   1.  Serialize the receipt as JSON.

   2.  Exclude the "signature" field entirely.

   3.  Sort all object keys lexicographically at every nesting level
       (recursive).

   4.  Emit with no insignificant whitespace (separators "," and ":").

   5.  Encode as UTF-8 bytes.

   This is equivalent to JCS (JSON Canonicalization Scheme) with
   recursive key sorting.





Dembowski                Expires 22 October 2026                [Page 6]

Internet-Draft               AgentLedger PoB                  April 2026


   Implementations MUST use this canonical form consistently.  Any
   deviation produces a different byte sequence and an invalid
   signature.

6.  Hash Chain

   Each receipt's prev_hash links it to its predecessor:

   prev_hash[n] = SHA-256( canonical_form( receipt[n-1] ) )

   where canonical_form excludes the signature field.

   The genesis receipt (first in chain) MUST have prev_hash = null.

   Verification of the chain proceeds from genesis to tip:

   1.  Assert receipt[0].prev_hash == null.

   2.  For i = 1..N: assert receipt[i].prev_hash == SHA-
       256(canonical_form(receipt[i-1])).

   3.  For each receipt: verify Ed25519 signature over
       canonical_form(receipt[i]).

   A verifier that observes a valid chain at time T can store the
   (receipt_id, hash) pair and later detect any rewrite of the chain
   history, even if the verifier has no access to the signing key.

7.  Signing

   Each receipt MUST be signed using Ed25519 [RFC8032] as follows:

   1.  Produce the canonical form of the receipt (signature field
       excluded).

   2.  Sign the UTF-8 bytes using the agent's Ed25519 private key.

   3.  Encode the 64-byte signature as lowercase hexadecimal.

   4.  Set receipt.signature to this value.

   The verifying party uses the agent_id field (which encodes the
   Ed25519 public key) to verify each signature independently.

   Agent identity MUST be established before any receipt is written.
   The Ed25519 keypair MUST be generated fresh for each agent instance
   unless a persistence mechanism is in use (see Section 12).




Dembowski                Expires 22 October 2026                [Page 7]

Internet-Draft               AgentLedger PoB                  April 2026


8.  Policy Gate

   The policy gate is an external component that evaluates each action
   before execution.  It operates as follows:

result = policy.evaluate(action_type, tool_name, payload)

if result.verdict == DENY:
    write_denied_receipt(action_type, tool_name, result.reason, policy_hash)
    raise PolicyViolationError
else:
    # proceed to execution

   The DENIED receipt MUST be written to persistent storage before
   PolicyViolationError is raised.  Implementations MUST NOT proceed to
   execution if the DENIED receipt write fails.

   The policy_hash field in every receipt (ALLOW and DENY) MUST contain
   the SHA-256 hash of the policy configuration.  This ensures that an
   auditor can verify not only that the policy ran, but that the
   specific policy configuration active at the time matches any
   externally stored policy definition.

   The external observer pattern is RECOMMENDED: the policy gate and
   receipt chain SHOULD be constructed outside the agent process and
   injected via callback registration.  This places the enforcement
   logic in a different trust domain from the agent being audited.

9.  Cross-Agent References

   When agents collaborate, handoffs SHOULD be recorded as cross-agent
   receipts.  A cross-agent receipt references a specific receipt in
   another agent's chain.

9.1.  Cross-Agent Reference Object

   {
     "target_agent_id": "273170e7...",
     "ref_receipt_id": "550e8400-...",
     "status": "pending"
   }

   target_agent_id:  The agent_id (Ed25519 public key hex) of the
      referenced agent.

   ref_receipt_id:  The receipt_id of the specific receipt being
      referenced.




Dembowski                Expires 22 October 2026                [Page 8]

Internet-Draft               AgentLedger PoB                  April 2026


   status:  One of: "pending", "confirmed".

9.2.  Resolution

   To resolve a cross-agent reference, the verifying agent:

   1.  Locates the referenced agent's chain (by target_agent_id).

   2.  Finds the receipt with the matching receipt_id.

   3.  Verifies the Ed25519 signature on that receipt using
       target_agent_id as the public key.

   4.  Confirms the receipt status is "completed".

   Signature verification in step 3 is REQUIRED.  A cross-agent
   reference that resolves without signature verification provides no
   tamper-evidence guarantee for the referenced chain.

10.  Checkpoint Hashes

   For long-running chains, implementations MAY write periodic
   checkpoint records to enable efficient partial verification.

   A checkpoint record is NOT a receipt.  It MUST include:

   *  "checkpoint": true

   *  "at_receipt_id": receipt_id of the last receipt in the batch

   *  "receipt_count": number of receipts covered

   *  "cumulative_hash": SHA-256 of the concatenated canonical forms of
      all receipts from genesis through at_receipt_id

   *  "signature": Ed25519 signature over the checkpoint record
      (signature field excluded)

   Partial verification from a checkpoint proceeds by:

   1.  Verifying the checkpoint's cumulative_hash against the covered
       receipts.

   2.  Verifying the chain tail (receipts after the checkpoint)
       independently.






Dembowski                Expires 22 October 2026                [Page 9]

Internet-Draft               AgentLedger PoB                  April 2026


11.  Storage

   Implementations SHOULD store receipts in newline-delimited JSON
   (JSONL) format: one JSON object per line, UTF-8 encoded, LF line
   endings.

   Checkpoint records are interleaved with receipts in the same file.  A
   parser MUST distinguish receipts from checkpoints by the presence of
   "checkpoint": true.

   Storage MUST be append-only during normal operation.  Implementations
   SHOULD use OS-level file locking or equivalent to prevent concurrent
   writes.

12.  Key Persistence

   Agent keypairs SHOULD be persisted across restarts to maintain a
   continuous chain.  Implementations SHOULD:

   1.  Store the Ed25519 private key in a file with permissions 0400
       (owner read-only).

   2.  Store the public identity (agent_id, principal_id,
       binding_signature) separately with permissions 0600.

   3.  Verify that the loaded keypair matches the chain's agent_id
       before resuming.

   A chain whose agent_id does not match the loaded keypair MUST NOT be
   extended.

13.  Security Considerations

13.1.  Chain Rewrite

   An attacker with write access to the JSONL file can rewrite the
   entire chain history with freshly computed hashes and re-signed
   receipts, provided they control the signing key.  Mitigations:

   *  External checkpointing: publish SHA-256(checkpoint) to an append-
      only external log at session boundaries.  Any rewrite diverges
      from the published value.

   *  Bilateral co-signing: a separate signing service (in a different
      trust domain from the agent) co-signs each receipt.  A rewrite
      requires compromising both keys.





Dembowski                Expires 22 October 2026               [Page 10]

Internet-Draft               AgentLedger PoB                  April 2026


   *  On-chain anchoring: commit checkpoint hashes to a public
      blockchain.

13.2.  Key Compromise

   A compromised private key allows an attacker to forge receipts that
   appear valid.  Mitigations include key revocation registries and
   hardware security modules for key storage.  These are out of scope
   for this document.

13.3.  Same Trust Domain

   The in-memory verify() operation uses the same keypair that signed
   the receipts.  This proves internal consistency but does not protect
   against an attacker who has already replaced the in-memory chain
   state.  Verifiers MUST use verify_from_disk() with the expected
   public key, not in-process verify().

13.4.  Policy Bypass

   The policy gate can be bypassed if the agent constructs a
   ReceiptChain instance without a policy, or calls finalize_last()
   directly without a preceding append().  Implementations SHOULD
   restrict access to the ReceiptChain constructor and enforce that
   policy is set at chain construction time.

14.  IANA Considerations

   This document has no IANA actions.

15.  References

15.1.  Normative References

15.2.  Informative References

16.  Normative References

   [RFC8259]  Bray, T., Ed., "The JavaScript Object Notation (JSON) Data
              Interchange Format", STD 90, RFC 8259,
              DOI 10.17487/RFC8259, December 2017,
              <https://www.rfc-editor.org/info/rfc8259>.

   [RFC8032]  Josefsson, S. and I. Liusvaara, "Edwards-Curve Digital
              Signature Algorithm (EdDSA)", RFC 8032,
              DOI 10.17487/RFC8032, January 2017,
              <https://www.rfc-editor.org/info/rfc8032>.




Dembowski                Expires 22 October 2026               [Page 11]

Internet-Draft               AgentLedger PoB                  April 2026


   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119,
              DOI 10.17487/RFC2119, March 1997,
              <https://www.rfc-editor.org/info/rfc2119>.

   [RFC8174]  Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
              2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
              May 2017, <https://www.rfc-editor.org/info/rfc8174>.

Appendix A.  Receipt Schema Summary

   The following table summarizes all receipt fields.

   +===================+=======+===========+===========================+
   |Field              |Type   |Required   | Description               |
   +===================+=======+===========+===========================+
   |receipt_id         |string |REQUIRED   | Unique receipt identifier |
   |                   |(UUID) |           |                           |
   +-------------------+-------+-----------+---------------------------+
   |chain_id           |string |REQUIRED   | Equal to agent_id         |
   |                   |(hex)  |           |                           |
   +-------------------+-------+-----------+---------------------------+
   |agent_id           |string |REQUIRED   | Ed25519 public key, 64    |
   |                   |(hex)  |           | hex chars                 |
   +-------------------+-------+-----------+---------------------------+
   |principal_id       |string |REQUIRED   | Authorizing principal     |
   |                   |       |           | identifier                |
   +-------------------+-------+-----------+---------------------------+
   |timestamp          |string |REQUIRED   | UTC creation time         |
   |                   |(ISO   |           |                           |
   |                   |8601)  |           |                           |
   +-------------------+-------+-----------+---------------------------+
   |prev_hash          |string |REQUIRED   | SHA-256 of previous       |
   |                   |(hex)  |           | receipt                   |
   |                   |or     |           |                           |
   |                   |null   |           |                           |
   +-------------------+-------+-----------+---------------------------+
   |schema_version     |string |REQUIRED   | Protocol version ("0.1")  |
   +-------------------+-------+-----------+---------------------------+
   |action.type        |string |REQUIRED   | Action type               |
   |                   |(enum) |           |                           |
   +-------------------+-------+-----------+---------------------------+
   |action.framework   |string |REQUIRED   | Agent framework           |
   +-------------------+-------+-----------+---------------------------+
   |action.tool_name   |string |CONDITIONAL| Required for tool_call    |
   |                   |or     |           |                           |
   |                   |null   |           |                           |
   +-------------------+-------+-----------+---------------------------+



Dembowski                Expires 22 October 2026               [Page 12]

Internet-Draft               AgentLedger PoB                  April 2026


   |action.status      |string |REQUIRED   | pending/completed/failed/ |
   |                   |(enum) |           | denied                    |
   +-------------------+-------+-----------+---------------------------+
   |action.payload_hash|string |OPTIONAL   | SHA-256 of input          |
   |                   |(hex)  |           |                           |
   |                   |or     |           |                           |
   |                   |null   |           |                           |
   +-------------------+-------+-----------+---------------------------+
   |action.result_hash |string |OPTIONAL   | SHA-256 of output         |
   |                   |(hex)  |           |                           |
   |                   |or     |           |                           |
   |                   |null   |           |                           |
   +-------------------+-------+-----------+---------------------------+
   |action.error       |string |OPTIONAL   | Error description         |
   |                   |or     |           |                           |
   |                   |null   |           |                           |
   +-------------------+-------+-----------+---------------------------+
   |action.policy_hash |string |RECOMMENDED| SHA-256 of policy config  |
   |                   |(hex)  |           |                           |
   |                   |or     |           |                           |
   |                   |null   |           |                           |
   +-------------------+-------+-----------+---------------------------+
   |signature          |string |REQUIRED   | Ed25519 signature, 128    |
   |                   |(hex)  |           | hex chars                 |
   +-------------------+-------+-----------+---------------------------+

                                  Table 1

Appendix B.  Reference Implementation

   A reference implementation in Python (MIT licensed) is available at:
   https://github.com/dembovvski/agentledger

   The implementation covers: AgentIdentityImpl (Ed25519),
   ReceiptChainImpl (JSONL storage, checkpoint hashes), DenylistPolicy/
   AllowlistPolicy/ CompositePolicy, integrations for LangChain/AutoGen/
   CrewAI, CLI verifier.

Author's Address

   Jakub Dembowski
   Email: dembowski@proton.me









Dembowski                Expires 22 October 2026               [Page 13]
