Reference · report format

The kolm signed report format

Every kolm evidence report is one JSON envelope, signed with Ed25519 over a canonical serialization of its fields. This page is the specification of that envelope: the exact field inventory the signature covers, the canonicalization rules, the detached counter-signals, and how anyone verifies a report with no kolm server in the path. It is written so that an independent implementation can be built from this page and the published verifiers alone.

Open format, Apache-2.0 Verifies offline, forever Changes versioned and logged below

Last reviewed 10 June 2026 · current shape: kolm-audit-report-1 / asr-report/0.1

01 / Intent and governance

Designed to outlive its issuer.

A piece of evidence is only durable if it can be checked without the issuer's help. So the format is built around one rule: verification must never require kolm to be reachable, or in business. The public key travels inside the report, the verifiers are published and inspectable, and the canonicalization is simple enough to reimplement from this page.

Open

Apache-2.0, published, reimplementable

The reference verifiers ship open source under Apache-2.0: the repository governs the whole tree, including the Python and Go SDKs. kolm publishes this spec and welcomes independent implementations; nothing in the format depends on kolm-only knowledge.

Offline

No server in the verification path

Tier-1 verification needs only the report itself: the envelope embeds the public key and the verifier rebuilds the signed bytes from the envelope's own fields. It runs in a browser, on an isolated box, or in CI, with no account and no network call.

Governed in the open

Versioned, logged, never silent

Every change to the envelope shape is versioned and recorded in the changelog at the bottom of this page. Additive fields are minor revisions; a breaking change would bump the major version and the schema string itself, so old verifiers fail loudly, never wrongly.

One mechanism, two artifacts. The same Ed25519 signature over canonical JSON that seals this signed report also seals the portable .kolm model the compiler builds from your live API calls. A model carries its recipe, evals and receipt; a report carries its findings and evidence digest. Both are bytes you own, both verify offline, and both check through the same path at /verify.

02 / The envelope

Every signed field, and what it means.

The envelope is a single JSON object. The Ed25519 signature covers every top-level field except the four detached blocks listed after this table. Field names below are the literal keys in the JSON.

FieldMeaning
schemaFixed type marker, "kolm-audit-report-1". Verifiers reject any other value before checking anything else.
report_versionThe envelope shape that produced the report. Currently "asr-report/0.1".
spec_versionThe audit spec the underlying run followed. Currently "asr-audit/0.1"; null on inputs that predate it.
report_idStable identifier with an asrr_ prefix, time-prefixed so ids sort roughly by issue time.
generated_atISO 8601 time the audit ran. The signature block's signed_at must equal it; verifiers fail a mismatch as a post-signing timestamp edit.
tier"scan" (the free Scan) or "report" (the paid Signed Readiness Report). Inside the signed bytes.
watermarkBoolean, true on the free Scan. Signed, so the watermark cannot be stripped without breaking the signature.
evidence_tierEvidence-quality grade { grade: "A"|"B"|"C", method, basis[] }, signed alongside the findings. See section 04.
subjectWhat was assessed: { name, source, records, events }.
summaryThe graduated readiness rollup: readiness_pct, findings by severity, tamper_evident, assessed controls, not-assessed controls with reasons, blocking count.
findingsFramework-mapped findings: severity, pillar, title, detail, ASR control, framework references, opaque evidence ids (never raw log bodies).
frameworksPer-framework coverage rollup: controls touched, finding counts, worst severity.
remediationPrioritized fix roadmap derived from the findings, worst first, each item carrying its framework references.
caveatsWhat the report does and does not claim, stated in plain terms. Findings map to frameworks a reviewer cites; the report is not a certification.
asr_checklistThe ASR control catalog the run assessed against (id, name, required evidence).
evidence_digest{ alg: "sha256", value, event_count }: binds the report to the exact input events analyzed, without carrying their possibly sensitive bodies.
passportThe agent identity passport: who acted, on which models and vendor surface, through what delegation graph, over which retrieval sources.
red_teamThe injection-resistance battery: score, per-status counts, and the probe table with opaque evidence ids.
contactThe single contact surface: dev@kolm.ai.
verify_urlWhere any holder can verify the report; defaults to https://kolm.ai/verify.

The four detached fields

Exactly four top-level fields are excluded from the signed bytes: signature_ed25519, timestamp_evidence, log_checkpoint, and co_signatures. The reason is structural, not a loophole: each one attests the envelope, so it cannot sit inside the bytes it attests. A signature cannot cover itself; a timestamp and a transparency-log entry are issued after signing and reference the sha256 of the signed canonical payload; each co-signature is itself an Ed25519 signature over that same payload. Because they bind to the signed digest, none of them can be re-pointed at a different report, and attaching or appending them never disturbs the primary signature.

signature_ed25519the primary signature block a signature cannot cover itself
timestamp_evidenceRFC 3161 token over the signed digest issued after signing
log_checkpointtransparency-log inclusion of the signed digest issued at signing time
co_signaturesindependent attestations over the same canonical bytes appended later
SIGNED ENVELOPE / EXPLODED ANATOMYlive
SIGNATURE COVERS THESE BYTES model + subject schema, report_version, subject, passport recipe + scope tier, watermark, caveats, asr_checklist evals + findings summary, findings, frameworks, red_team receipt of inputs evidence_digest (sha256 over the analyzed events) Ed25519 signature over canonical JSON of the body kolm-ed25519-v1 DETACHED, ATTEST FROM OUTSIDE timestamp_evidence log_checkpoint co_signatures + signature_ed25519
SIGNED BYTES four layers + sha256 receipt Ed25519-sealed
Read it top to bottom: the four signed layers (model and subject, recipe and scope, evals and findings, and a sha256 receipt of the inputs) are the bytes the Ed25519 signature covers. The four detached fields sit outside those bytes because each one attests the envelope, and a signature cannot cover itself.
03 / Canonicalization

The exact bytes the signature covers.

kolm canonical JSON is recursive key-sorted JSON with no insignificant whitespace, signed over its UTF-8 bytes. It is deliberately not RFC 8785 (JCS). The difference is simplicity: the entire algorithm is one short recursive function a reviewer can read in a single sitting and reimplement without a dependency, and the awkward edges below are pinned by cross-implementation fixtures rather than by a long standard.

  • Key order. Object keys sort by UTF-16 code unit, JavaScript's default sort. For supplementary-plane characters this differs from raw UTF-8 byte order, and every implementation reproduces it.
  • Whitespace. None. {"a":1,"b":[2,3]}, never pretty-printed.
  • Numbers. ECMAScript number-to-string: shortest round-trip digits, exponent notation only at the JSON.stringify thresholds. Non-finite values serialize to null.
  • Strings. ECMAScript JSON quoting (JSON.stringify): the quote, the backslash, C0 control characters, and unpaired surrogates are escaped; every other code point passes through unescaped.
  • Dropped values. undefined members are dropped, matching JSON.stringify. null is preserved: it is a value, not an absent key.
  • Exclusions. The four detached fields above are removed before serialization. Everything else, present or future, is covered.

Four implementations are locked byte-for-byte: the Node signer (src/attestation-report-builder.js), the browser verifier (kolm-audit-verify.js), the Python SDK, and the Go SDK. Each SDK's test suite asserts byte-exact equality against the reference output, including the number-formatting and key-order edges.

algorithmrecursive key-sorted JSON
whitespacenone
encodingUTF-8 bytes
key_sortUTF-16 code unit
rfc_8785_jcsnot used deliberate
excludedsignature_ed25519, timestamp_evidence, log_checkpoint, co_signatures
implementationsNode · browser · Python · Go byte-exact fixtures
04 / Signature and tiers

One signature, two trust tiers, three evidence grades.

The signature is Ed25519 (RFC 8032) over the canonical bytes. The block that carries it records spec: "kolm-ed25519-v1", alg, the PEM public_key, its key_fingerprint, the signature, and signed_at. Verification then answers three separate questions, and the format keeps them separate.

Tier 1 · integrity

Is this byte-for-byte what was signed?

Rebuild the canonical payload from the envelope itself, verify the Ed25519 signature with the embedded public key, and confirm signed_at equals the signed generated_at. Fully offline. A single altered byte fails it.

Tier 2 · issuer provenance

Is the embedded key a kolm key?

Tier 1 alone would accept a forgery re-signed with the attacker's own key. Tier 2 checks the key against the published keyring (kolm-issuers.json) or the live GET /v1/audit/issuer-key. Key lifecycle is public: live, rotated (history stays verifiable), or revoked. A revoked key forces trusted:false.

Evidence tiers · A / B / C

How strong was the input evidence?

A separate axis from authenticity, graded inside the signed payload. A: events captured by the kolm gateway at runtime. B: vendor-supplied logs with a verified hash chain. C: vendor logs accepted as provided. A report built from as-provided logs cannot be upgraded to gateway-captured without breaking the signature.

Envelopes issued before tiered evidence carry no evidence_tier field. They verify unchanged, and renderers show them as "Evidence tier: not graded (issued before tiered evidence)". No grade is ever invented.

05 / Counter-signals

Independent evidence that the signature is not alone.

Beyond the primary signature, the format carries four counter-signals. Each is optional, each binds to the signed report digest, and none of them can flip a failing verification to passing: they add confidence, never substitute for it.

log_checkpoint

Transparency-log inclusion

At signing time, the sha256 of the signed canonical payload is appended to kolm's public, append-only Ed25519/Merkle transparency log. The checkpoint records origin, tree_size, root_hash, leaf_hash, and seq, and a holder fetches an inclusion proof from GET /v1/transparency-log/proof/<seq> against the published signed tree head. Anchoring is best-effort: a log failure omits the field rather than blocking the report.

timestamp_evidence

RFC 3161 trusted timestamp

An RFC 3161 token over the signed report digest (the message_imprint), proving the report existed no later than the time authority's clock, independent of kolm's. Status "timestamped" carries token_b64 and the TSA URL; status "offline" means this additive evidence is absent. Verifiers report it; the verdict stays with the signature.

co_signatures

Named co-signers (Reviewed Attestation)

A named reviewer attests the same canonical bytes the issuer signed: co_signatures is excluded from the canonical payload, so the bytes are identical whether zero or N co-signatures are attached, and a co-signer can never invalidate the issuer's signature. Each entry records name, role, and a full Ed25519 block, so it verifies offline with no extra schema. The co-signer key is deliberately independent of the issuer key.

key revocation

Public key lifecycle

Every issuer key has a public status: live, rotated, or revoked, served by GET /v1/audit/issuer-key/<fingerprint>/status. Rotated keys remain valid for the reports they signed; a revoked key forces trusted:false with reason issuer_key_revoked across the verify endpoint, the browser verifier, and the SDK keyrings.

06 / Verifying a report

Three offline verifiers, one shared byte stream.

Each path below rebuilds the same canonical bytes and checks the same signature. Use whichever fits the environment; they agree by construction and by test.

Browser

kolm.ai/verify

Paste or drop the report JSON at /verify. The check runs locally in your browser's WebCrypto; the page works with the network disconnected. The verifier source is one inspectable file: kolm-audit-verify.js.

Python SDK

kolm.verify_report

from kolm import verify_report
result = verify_report(report)
result.ok  # tier1 AND tier2

Zero network. result.tier1_signature and result.tier2_issuer expose the two tiers; act on result.ok, never on tier 1 alone.

Go SDK

kolm.VerifyReport

v, err := kolm.VerifyReport(
  reportJSON, kolm.DefaultKeyring())
// act only when v.Trusted()

Standard library only, zero third-party dependencies. v.Trusted() is tier 1 and tier 2 together.

Fetching the artifact: a shareable Trust link serves the bare signed envelope at GET /v1/trust/<slug>?format=json, ready to feed any of the verifiers above. A server-side convenience, POST /v1/audit/report/verify, returns the same two-tier verdict plus the revocation check; prefer the offline paths, which require no trust in the server.

07 / Versioning and changelog

Additive by default, loud when breaking.

Three identifiers version the format. schema is the hard gate: "kolm-audit-report-1" today, and a breaking change would mint a new value so old verifiers reject it explicitly. Within a schema, report_version (currently "asr-report/0.1") and spec_version (currently "asr-audit/0.1") move with semver discipline: additive fields are minor revisions.

Additive fields never break old verifiers, because canonicalization is generic: the signed bytes are rebuilt by key-sorting whatever fields the envelope carries, never from a fixed field list. A verifier written against envelope v1 verifies an envelope carrying fields it has never heard of, byte for byte.

DateVersionChange
2026-06-10 asr-report/0.1 Added evidence_tier (grade A/B/C, method, basis) inside the signed payload. Additive: earlier envelopes verify unchanged and render as "Evidence tier: not graded (issued before tiered evidence)".
2026-06 asr-report/0.1 Envelope v1 under schema kolm-audit-report-1: the signed field inventory above, tier and watermark inside the signed bytes, evidence_digest, passport and red_team blocks, and the four detached fields (signature, RFC 3161 timestamp, transparency-log checkpoint, co-signatures).

Questions about the format, or building an independent implementation? dev@kolm.ai

Read the bytes, not the brochure.

Verify a signed report or a .kolm model in your own browser, then go own the AI you're renting: capture, compile, and carry out an artifact that verifies through this exact format.

Ed25519-signed Offline-verifiable Sample report

Caveats: Scope is contractual. Permission posture, redaction and audit-trail integrity are assessed. Injection is tested and reported, not warranted.