Language-agnostic reference for the EPI container format, cryptographic protocol, and verification model. Anyone may implement .epi producers and consumers.
Read the full specification as a Markdown file
Formal JSON Schema (draft 2020-12) for all core formats
Conformance vectors from real .epi containers
The EPI format defines a portable, self-contained, cryptographically sealed container for AI agent execution evidence. A .epi file is a polyglot — valid HTML for browser-based forensic inspection AND a binary envelope carrying a ZIP payload — enabling zero-install verification by regulators, auditors, and courts.
Reference Implementation: epi-recorder (Python, MIT). This specification is an open standard. The .epi file format carries no intellectual property restrictions.
A .epi file begins with a 128-byte binary header, followed by an HTML viewer and ZIP payload.
| Offset | Size | Field | Value / Description |
|---|---|---|---|
| 0 | 4 | magic | 0x3C 0x21 0x2D 0x2D (ASCII <!--) |
| 4 | 1 | version | 0x02 (envelope format version) |
| 5 | 1 | format | 0x01 (ZIP v1 payload format) |
| 6 | 2 | flags | Reserved. MUST be 0x0000 |
| 8 | 8 | payload_length | ZIP payload byte length, excluding the viewer gap (little-endian uint64) |
| 16 | 16 | payload_uuid | UUID v4 (16 raw bytes); MUST equal manifest.workflow_id |
| 32 | 8 | created_at | Unix epoch microseconds (little-endian uint64) |
| 40 | 32 | payload_sha256 | SHA-256 of ZIP payload bytes only (32 raw bytes) |
| 72 | 32 | viewer_sha256 | SHA-256 of the outer viewer HTML. Verified against the signed file_manifest["viewer.html"]; all-zero means a legacy artifact whose display layer is not covered |
| 104 | 24 | reserved | Reserved. MUST be zero |
<!-- EPI_ZIP_PAYLOAD_START -->
Bytes between header and marker = embedded viewer. Bytes after marker = ZIP payload.
| Container | MIME |
|---|---|
| Envelope v2 (polyglot) | No single MIME identifies the polyglot; canonical evidence identifier application/vnd.epi+zip |
Legacy EPI1 / bare ZIP | application/vnd.epi+zip |
| SCITT payload | application/vnd.epi.manifest+hash |
Read the first 4 bytes:
0x3C 0x21 0x2D 0x2D (<!--) → envelope-v2; locate the ZIP via <!-- EPI_ZIP_PAYLOAD_START -->.0x45 0x50 0x49 0x31 (EPI1) → legacy EPI1; probe at least the first 64 bytes for PK\x03\x04 and treat the preceding bytes as header.0x50 0x4B 0x03 0x04 (PK\x03\x04) → bare ZIP (what epi migrate --legacy-zip writes)..epi file.| File | Purpose | Schema |
|---|---|---|
mimetype | First entry, stored uncompressed. Contains application/vnd.epi+zip | Plain text |
manifest.json | Signed manifest — root of trust | JSON Schema |
steps.jsonl | Immutable execution timeline (NDJSON) | JSON Schema |
environment.json | Runtime environment snapshot | JSON Schema |
analysis.json | 9-pass deterministic fault analysis | JSON Schema |
policy.json | Governance rulebook | JSON Schema |
viewer.html | Self-contained browser forensic viewer | N/A |
VERIFY.txt | Offline verification instructions for auditors | Plain text |
| File | Purpose |
|---|---|
review.json | Human review addendum (NOT in file_manifest) |
review_index.json | Multi-reviewer index |
policy_evaluation.json | Policy rule evaluation results |
stdout.log | Captured stdout |
stderr.log | Captured stderr |
artifacts/scitt/statement.cbor | SCITT COSE_Sign1 |
artifacts/scitt/receipt.cbor | SCITT Merkle receipt |
artifacts/sbom/ | CycloneDX SBOM |
artifacts/agt_export.json | AGT export |
Root of trust. Every file's SHA-256 hash is recorded in file_manifest.
| Field | Type | Description |
|---|---|---|
spec_version | string | EPI version that sealed the file (e.g. "4.6.3") |
workflow_id | UUID | Unique execution identifier (auto-generated UUID v4) |
created_at | datetime | UTC ISO 8601 (auto-set to current time): YYYY-MM-DDTHH:MM:SSZ |
file_manifest | object | File paths mapped to 64-char hex SHA-256 hashes |
| Field | Type | Description |
|---|---|---|
cli_command | string | CLI invocation |
public_key | string | 64-char hex Ed25519 (32 raw bytes) |
signature | string | ed25519:<key_id>:<sig_hex> |
container_format | string | "legacy-zip" or "envelope-v2" |
analysis_status | string | "complete", "skipped", "error" |
goal | string | Workflow objective |
metrics | object | Key-value metrics |
source | object | {integration, framework, agent} |
total_steps | integer | Total recorded steps |
tags | array | Categorization tags |
governance | object | DID, SCITT, trust score |
trust | object | Cryptographic verification state |
policy | object | Policy evaluation outcome |
Three canonicalizations exist, selected by the manifest's spec_version:
spec_version | Canonicalization |
|---|---|
1.x | CBOR (RFC 8949, canonical encoding) |
through 4.4.0 | Sorted-key compact JSON |
4.4.1 and later | JCS (RFC 8785) |
For JCS manifests and steps:
signature for manifests. governance and trust remain part of the signed preimage.YYYY-MM-DDTHH:MM:SSZ.Conformance: Two implementations computing the canonical hash of identical data MUST produce identical hex strings. See EPI-SPEC.md §5.1 for the normative rules and test vectors.
signature only)SHA-256(hex_public_key)[:16]ed25519:<key_id>:<128-hex-sig>Key ID is cryptographically bound to the public key — prevents key substitution attacks.
: into 3 partsed25519SHA-256(hex_public_key)[:16]Each step in steps.jsonl contains prev_hash:
prev_hash is null or the genesis marker "CHAIN_START" (sealers write "CHAIN_START")prev_hash is the 64-character canonical hash of step N-1 (not a hash of that digest)Append-only, hash-linked timeline. Any insertion, deletion, or reorder breaks the chain.
NDJSON: one JSON object per line.
| Field | Type | Required | Description |
|---|---|---|---|
index | integer | Yes | Monotonically increasing, 0-indexed |
kind | string | Yes | Step type identifier |
timestamp | datetime | Auto | UTC ISO 8601 (auto-populated) |
content | object | Auto | Step-specific payload (defaults to empty object) |
prev_hash | string|null | Auto | SHA-256 of previous step (auto-computed) |
trace_id | string | No | W3C trace identifier |
span_id | string | No | W3C span identifier |
governance | object | No | Step-level governance |
source_type | string | No | "user"|"tool"|"reasoning"|"system" |
8 checks, in order (the last is optional):
file_manifest entries match SHA-256; no extra filesprev_hash links intact; indices monotonic; timestamps non-decreasingtotal_steps matches line countmimetype = application/vnd.epi+zip| Level | Integrity | Signature | Identity | Meaning |
|---|---|---|---|---|
| HIGH | Pass | Valid | Known (org-pinned) | Signer key pinned out of band; claim-ready |
| MEDIUM | Pass | Valid | Local | Sealer key is on this machine, not an org pin |
| MEDIUM | Pass | Valid | Unknown | SCITT transparency verified |
| LOW | Pass | Valid | Unknown | Valid signature, identity not verified |
| LOW | Pass | None | — | Unsigned artifact: integrity only, no authenticity |
| NONE | Fail | — | — | Integrity or signature verification failed; do not trust |
| FAIL | Pass | Valid | Mismatch | Claimed identity does not match the signing key |
| INVALID | Pass | Valid | Revoked | The signing key has been revoked |
| Threat | Mitigation |
|---|---|
| Post-seal tampering | SHA-256 file manifest + Ed25519 signature |
| Evidence replay | Unique workflow_id + created_at |
| Secret leakage | HMAC-SHA256 redaction |
| Signature spoofing | Key ID bound to public key |
| Step manipulation | prev_hash chain |
| File injection | Integrity rejects extras |
| Visual deception | viewer.html in file_manifest |
| Key compromise | Revocation files in trust registry |
EPI is a post-execution evidence system. It records what happened — it does not prevent unauthorized access at runtime. For enforcement, use EPI_ENFORCE=1. File-level encryption is not specified; implementers MAY layer on top.
An implementation is conformant if:
.epi files passing the verification procedure (§7)prev_hash chains| Resource | Location |
|---|---|
| Manifest Schema | manifest.schema.json |
| Step Schema | step.schema.json |
| Environment Schema | environment.schema.json |
| Analysis Schema | analysis.schema.json |
| Policy Schema | policy.schema.json |
| Test Vectors | test-vectors.json |
.epi file format carries no intellectual property restrictions. Anyone may implement producers and consumers conforming to this specification. Contributions via GitHub Issues.