Specification

RunProof Specification v1

This is the formal specification for RunProof, the cryptographically verifiable receipt format for AI agent execution.

Abstract

RunProof is an open specification for creating verifiable receipts of AI agent execution. A RunProof artifact cryptographically proves:

  1. What happened — The ordered sequence of events
  2. Who produced it — The agent/runtime identity
  3. That it hasn’t been tampered with — Cryptographic signatures

This specification defines the format, verification rules, and guarantees provided by RunProof.


Status

FieldValue
Version2.1
StatusDraft
Schema URIhttps://substr8labs.com/schemas/runproof/v2.1
Reference Implementationsubstr8-core

1. Terminology

  • RunProof: A cryptographically signed artifact representing a single agent execution
  • Trace: The ordered sequence of events within an execution
  • Event: A single occurrence within the trace (tool call, node completion, etc.)
  • Hash Chain: Sequential hashing where each event references the previous hash
  • Merkle Root: The root hash of a Merkle tree built from all event hashes
  • Issuer: The entity that generated and signed the proof

2. Four Guarantees

A valid RunProof provides exactly four guarantees:

2.1 Event Order Integrity

Events occurred in the recorded sequence.

Each event contains a prev_hash field referencing the hash of the previous event. This creates a hash chain that proves ordering.

Event 1 → Event 2 → Event 3
   ↓         ↓         ↓
hash_1 ← prev_hash ← prev_hash

2.2 Event Set Integrity

No events have been added, removed, or modified.

The event_root field contains the Merkle root of all event hashes. Any modification to any event changes the root.

2.3 Proof Origin Authenticity

The proof was created by the claimed identity.

The signature field contains a cryptographic signature over the proof_hash. The signer’s public key is included in the identity section.

2.4 Portable Verification

Anyone can verify the proof without special access.

All information required for verification is contained within the proof itself. No external services are required for basic verification.


3. Schema Structure

3.1 Top-Level Fields

{
  "schema_version": "runproof/v2.1",
  "header": { ... },
  "identity": { ... },
  "claims": { ... },
  "lineage": { ... },
  "context": { ... },
  "trace": [ ... ],
  "outputs": { ... },
  "commitments": { ... },
  "anchors": { ... },
  "metadata": { ... }
}

3.2 Header

Run metadata and identification.

FieldTypeRequiredDescription
proof_idstringUnique proof identifier
run_idstringExecution identifier
agent_idstringAgent identifier
runtimestringExecution framework
started_atdatetimeRun start timestamp
ended_atdatetimeRun end timestamp
statusenumcompleted, failed, interrupted

3.3 Identity

Signer and policy information.

{
  "identity": {
    "signer": {
      "key_id": "key_xxx",
      "public_key": "ed25519:...",
      "issuer": {
        "name": "substr8",
        "version": "1.7.2",
        "runtime": "langgraph"
      }
    },
    "policy": {
      "capability_profile_id": "cap_xxx",
      "policy_hash": "sha256:..."
    }
  }
}

3.4 Claims (v2.1)

Optional contextual assertions.

{
  "claims": {
    "policy": "trading-agent-policy-v3",
    "model": "gpt-4.1",
    "environment": "prod-us-east",
    "compliance": ["sox-compliant", "pci-dss"],
    "intent_hash": "sha256:...",
    "custom": {}
  }
}
⚠️

Claims are assertions by the issuer — they are NOT cryptographically verified by the proof itself. External systems MAY verify claims against their own records.

3.5 Lineage (v2.1)

Chainable proof relationships.

{
  "lineage": {
    "parent": "sha256:abc123...",
    "root": "sha256:def456...",
    "depth": 3,
    "workflow_id": "wf_content_pipeline_001"
  }
}
FieldTypeDescription
parentstringSHA256 hash of parent RunProof
rootstringSHA256 hash of workflow root
depthintegerSteps from root (1 = is root)
workflow_idstringWorkflow grouping identifier

3.6 Trace

The execution trace is an array of ordered events.

{
  "trace": [
    {
      "seq": 1,
      "event_id": "evt_xxx",
      "type": "run_started",
      "timestamp": "2026-03-11T08:00:00Z",
      "prev_hash": null,
      "payload_hash": "sha256:...",
      "payload": { "agent_id": "..." },
      "entry_hash": "sha256:..."
    }
  ]
}

Event Types

TypeDescription
run_startedExecution began
run_completedExecution finished successfully
run_failedExecution failed
node_startedGraph node began
node_completedGraph node finished
tool_call_startedTool invocation began
tool_call_completedTool returned result
decision_madeRouting/branching decision
human_review_requestedPaused for human input
customFramework-specific event

3.7 Commitments

Cryptographic integrity data.

{
  "commitments": {
    "event_root": "sha256:...",
    "proof_hash": "sha256:...",
    "signature": {
      "algorithm": "ed25519",
      "value": "base64:..."
    }
  }
}

4. Verification Algorithm

To verify a RunProof:

Step 1: Linear Integrity (Hash Chain)

for i, event in enumerate(proof.trace):
    if i == 0:
        assert event.prev_hash is None
    else:
        assert event.prev_hash == proof.trace[i-1].entry_hash

Step 2: Set Integrity (Merkle Root)

hashes = [event.entry_hash for event in proof.trace]
computed_root = compute_merkle_root(hashes)
assert computed_root == proof.commitments.event_root

Step 3: Authenticity (Signature)

public_key = parse_public_key(proof.identity.signer.public_key)
message = proof.commitments.proof_hash
signature = decode_base64(proof.commitments.signature.value)
assert verify_signature(public_key, message, signature)

Step 4: Lineage Validation (Optional)

If lineage.parent is set:

if proof.lineage and proof.lineage.parent:
    parent_proof = fetch_proof(proof.lineage.parent)
    assert parent_proof is not None
    # Optionally: verify parent is valid

5. Hash Computation

5.1 Event Entry Hash

def compute_entry_hash(event):
    canonical = json.dumps({
        "seq": event.seq,
        "event_id": event.event_id,
        "type": event.type,
        "timestamp": event.timestamp.isoformat(),
        "prev_hash": event.prev_hash,
        "payload_hash": event.payload_hash
    }, sort_keys=True, separators=(',', ':'))
    return "sha256:" + sha256(canonical.encode()).hexdigest()

5.2 Merkle Root

def compute_merkle_root(hashes):
    if len(hashes) == 0:
        return "sha256:" + sha256(b"").hexdigest()
    if len(hashes) == 1:
        return hashes[0]
    
    # Pad to even length
    if len(hashes) % 2 == 1:
        hashes.append(hashes[-1])
    
    # Build tree
    while len(hashes) > 1:
        next_level = []
        for i in range(0, len(hashes), 2):
            combined = hashes[i] + hashes[i+1]
            next_level.append("sha256:" + sha256(combined.encode()).hexdigest())
        hashes = next_level
    
    return hashes[0]

5.3 Proof Hash

def compute_proof_hash(proof):
    # Exclude signature from hash computation
    canonical = json.dumps({
        "schema_version": proof.schema_version,
        "header": proof.header.dict(),
        "identity": proof.identity.dict(),
        "claims": proof.claims.dict() if proof.claims else None,
        "lineage": proof.lineage.dict() if proof.lineage else None,
        "context": proof.context.dict(),
        "outputs": proof.outputs.dict(),
        "event_root": proof.commitments.event_root,
        "anchors": proof.anchors.dict(),
        "metadata": proof.metadata.dict()
    }, sort_keys=True, separators=(',', ':'))
    return "sha256:" + sha256(canonical.encode()).hexdigest()

6. Signature Algorithms

AlgorithmKey FormatSignature Format
ed25519ed25519:<hex>Base64
ecdsa-p256ecdsa-p256:<hex>Base64 (DER)

7. Extensibility

7.1 Custom Event Types

Frameworks MAY define custom event types using type: "custom" with a payload.event_type field:

{
  "type": "custom",
  "payload": {
    "event_type": "langgraph.conditional_edge",
    "edge_name": "should_continue"
  }
}

7.2 Custom Claims

The claims.custom field accepts arbitrary key-value pairs:

{
  "claims": {
    "custom": {
      "department": "engineering",
      "cost_center": "CC-4521",
      "request_id": "req_xxx"
    }
  }
}

7.3 Future Reserved Fields

The following fields are reserved for future specification versions:

  • attestations[] — Third-party verification signatures
  • segments[] — Segmented Merkle trees for large traces
  • intent — Full Intent primitive integration
  • acceptance — Acceptance primitive integration

8. Implementations

Reference Implementation

CLI

  • Package: substr8
  • Commands: proof verify, proof inspect

Verification UI


9. Security Considerations

9.1 Key Management

Implementations SHOULD:

  • Generate ephemeral keys per-run for isolation
  • Support external key management systems
  • Rotate keys regularly

9.2 Replay Protection

The proof_id and run_id fields provide uniqueness. Implementations SHOULD reject duplicate proof submissions to registries.

9.3 Time Verification

Timestamps are self-reported by the issuer. For high-assurance use cases, implementations SHOULD anchor proofs to external timestamping services.


10. IANA Considerations

This specification does not require any IANA registrations.


11. References


Appendix A: Full Example

{
  "schema_version": "runproof/v2.1",
  "header": {
    "proof_id": "proof_ccfe7c4abd014eab",
    "run_id": "run_ade859b400e24d09",
    "agent_id": "research/web-researcher",
    "runtime": "langgraph",
    "runtime_version": "0.2.99",
    "started_at": "2026-03-11T08:00:00Z",
    "ended_at": "2026-03-11T08:00:05Z",
    "status": "completed"
  },
  "identity": {
    "signer": {
      "key_id": "key_ephemeral_001",
      "public_key": "ed25519:09f2cb092ea8af1c...",
      "issuer": {
        "name": "substr8",
        "version": "1.7.2",
        "runtime": "langgraph",
        "runtime_version": "0.2.99"
      }
    }
  },
  "claims": {
    "policy": "research-agent-policy-v1",
    "model": "claude-3.5-sonnet",
    "environment": "production"
  },
  "lineage": {
    "depth": 1
  },
  "context": {
    "trigger_type": "api",
    "input_hash": "sha256:44136fa355b3678a...",
    "model": {
      "provider": "anthropic",
      "model_id": "claude-3.5-sonnet"
    },
    "tools_available": ["web_search", "read_url"]
  },
  "trace": [
    {
      "seq": 1,
      "event_id": "evt_001",
      "type": "run_started",
      "timestamp": "2026-03-11T08:00:00Z",
      "prev_hash": null,
      "payload_hash": "sha256:32369c6fb02a87a7...",
      "entry_hash": "sha256:559fe8cee19b9f11..."
    },
    {
      "seq": 2,
      "event_id": "evt_002",
      "type": "tool_call_completed",
      "timestamp": "2026-03-11T08:00:02Z",
      "prev_hash": "sha256:559fe8cee19b9f11...",
      "payload_hash": "sha256:81da3e81ebd668c8...",
      "payload": {
        "tool": "web_search",
        "result_hash": "sha256:abc123..."
      },
      "entry_hash": "sha256:a0facd669dc2461d..."
    },
    {
      "seq": 3,
      "event_id": "evt_003",
      "type": "run_completed",
      "timestamp": "2026-03-11T08:00:05Z",
      "prev_hash": "sha256:a0facd669dc2461d...",
      "payload_hash": "sha256:d0765f73cd5d1df3...",
      "entry_hash": "sha256:113c59eb2ed53352..."
    }
  ],
  "outputs": {
    "result_hash": "sha256:50ac1f82766b184e...",
    "result_redaction_mode": "hashed"
  },
  "commitments": {
    "event_root": "sha256:ba56701f663b204d...",
    "proof_hash": "sha256:a65b14e11a1a96a4...",
    "signature": {
      "algorithm": "ed25519",
      "value": "/i4PA/caaCadEtQt..."
    }
  },
  "anchors": {},
  "metadata": {
    "tags": ["research", "web"],
    "custom": {
      "sdk_version": "substr8-langgraph/0.1.0"
    }
  }
}

Changelog

VersionDateChanges
v2.12026-03-11Added claims, lineage, expanded issuer
v2.02026-03-09Initial release