Normative specification

KNOBE Protocol v1 Frozen

Version 1.0 Issued 2026-06-21 License: CC BY 4.0 Steward: David Kyle, UC Davis

This document is the normative specification for KNOBE Protocol v1. It defines what a conforming file must contain, how integrity is computed and verified, and what a conforming verifier must report. The white paper provides motivation and context; this document provides the contract.

§1Status and versioning

KNOBE Protocol v1.0 is frozen. The file format, required fields, canonical hash rule, and verification semantics defined here will not change in any v1.x release. Backward-compatible additions (new optional payload fields, new open-vocabulary values) may be issued as v1.x updates. Any change that would cause a currently valid KNOBE to fail verification under a conforming v1.x verifier constitutes a breaking change and requires a v2.0 declaration.

MUST A verifier claiming conformance with KNOBE v1 MUST apply the verification semantics of the spec_version value sealed in the file, not the version of the verifier itself. A v1.x verifier MUST NOT reinterpret a file sealed under v1.0 as failed.

The key words MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY are used as defined in RFC 2119.

§2File overview

A KNOBE is a single plain-text file, conventionally named with the suffix .knobe.md. It consists of three layers:

A file is valid at the protocol layer when its payload decodes, parses, contains the ten required fields, and its payload_hash matches the computed canonical hash. Validity does not imply truth, accuracy, or trustworthiness of the content.

§3File structure

3.1 YAML frontmatter

The file MUST begin with a YAML frontmatter block delimited by lines containing exactly ---. At minimum, spec_version MUST appear in the frontmatter. All other frontmatter fields are optional; they serve human scanners and are not part of the integrity-sealed record.

---
title: "Example KNOBE"
spec_version: "1.0"
---

3.2 Markdown body

The body MAY be any valid UTF-8 text. It is not validated by a conforming verifier except when an optional body_hash is present in the payload (see §6). A body is not required; a KNOBE with an empty body is valid.

3.3 Payload block

The payload block MUST appear after the body. Its delimiters are:

-----BEGIN KNOBE B64-----
{base64-encoded JSON}
-----END KNOBE B64-----

The content between the delimiters is standard Base64 (RFC 4648 §4) encoding of a UTF-8 JSON object. Line breaks within the Base64 block MUST be ignored by decoders. If multiple payload blocks are present, verifiers MUST use the last one to compute verification state, and MUST surface a warning to the receiver containing the total count of blocks and the index of the block evaluated (e.g., "evaluated block 2 of 2"). A conforming file SHOULD contain exactly one payload block; multiple blocks can occur legitimately (email quoting, archive concatenation, copy-paste) but can also indicate shadow-payload injection. The warning is interpretation, not just information: it tells the receiver that the file's structure is anomalous.

MUST The payload MUST be a JSON object (not an array or scalar). MUST be encoded as UTF-8. MUST NOT require a BOM.

§4Payload fields

4.1 Required fields

The following ten fields MUST be present in the payload. A payload missing any of them is invalid at the protocol layer regardless of whether its hash matches.

Required fields
FieldTypeNotes
spec_versionstringThe protocol version under which this file was sealed. "1.0" for this specification.
titlestringHuman-readable title of the knowledge object.
summarystringOne-paragraph description of the object's content and purpose.
content_typestringDeclared content category. See §8 for open vocabulary.
created_datestringISO 8601 date of original creation (YYYY-MM-DD).
licensestringDeclared license identifier (e.g. "CC BY 4.0").
privacy_levelstringDeclared privacy posture. See §8.
quarantine_statusstringDeclared trust posture. See §8. New/external KNOBEs SHOULD default to "quarantine".
attributionobjectMust contain a sources array with at least one entry. Each source entry SHOULD include author and contribution. AI contributors SHOULD carry "rights_bearing": false.
payload_hashstringSHA-256 hex digest of the canonical JSON payload (excluding this field). Format: exactly 64 lowercase hexadecimal characters. See §5.

4.2 Receiver-facing optional fields

These optional fields carry interpretive context written for the receiver: the next human or agent to encounter the object. They are not required for validity but are central to the protocol's purpose.

Receiver-facing optional fields
FieldNotes
fidelity_limitsHow far the object may be trusted as a representation of its source. Suggested sub-fields: represents, trust_as, do_not_infer (array).
use_conditionsOriginator-declared terms for downstream use. Suggested sub-fields: license, permitted (array), requested_preservations (array), consent_note.
accessibilityAdaptation lineage. Each entry SHOULD include adapted_from (source payload_hash), adaptation_type, adaptation_contributor, review_date.

4.3 Additional optional fields

Additional optional fields
FieldNotes
body_hashSHA-256 of the normalized body text. See §6.
parentsArray of objects linking to source KNOBEs by payload_hash. Each entry SHOULD include payload_hash, title, and relationship. Any payload_hash value MUST follow the format constraint in §4.1: exactly 64 lowercase hexadecimal characters.
transformation_historyArray of transformation receipts. Each entry SHOULD include date, who, strategy, notes.
identity_statusDeclared identity posture. See §8. "declared" means attribution is self-reported; "signed" is a forward placeholder for cryptographic signing in future tiers.
key_conceptsArray of {"name": "...", "definition": "..."} objects.
version_historyArray of {"version": "...", "date": "...", "notes": "..."} objects.
is_seedBoolean. true indicates this KNOBE is intended as a teaching or bootstrapping artifact.
languageBCP 47 language tag (e.g. "en").
tagsArray of lowercase strings.
subtitleString. Secondary title.
idString. Stable local identifier for this object.
canonical_urlString. Authoritative URL if published.
license_urlString. URL to the full license text.
build_recipesArray of instructions for constructing derivative KNOBEs. Informative only in v1; not normative.

MUST NOT Implementations MUST NOT fail verification because an unrecognized field is present. Unrecognized fields MUST be treated as opaque and preserved.

§5Canonical hash rule

The payload_hash is computed by applying the following algorithm to the payload object:

1.Decode the Base64 payload block to bytes and parse as UTF-8 JSON.
2.Remove the payload_hash field from the resulting object.
3.Serialize the object to canonical JSON:
· All object keys sorted alphabetically, recursively at every nesting depth.
· All JSON object keys and string values normalized to Unicode Normalization Form C (NFC) before serialization.
· No whitespace between tokens (separators "," and ":").
· Arrays preserved in insertion order; their elements are not reordered.
· All string content encoded as literal UTF-8; MUST NOT use \uXXXX escapes for characters that can be represented directly.
4.Encode the canonical JSON string as UTF-8 bytes.
5.Compute SHA-256 of those bytes. The hex digest is the payload_hash.

Interoperability constraints

Two constraints close cross-language canonicalization gaps that would otherwise allow conforming Python and JavaScript implementations to compute different hashes for visually-identical payloads.

MUST All numeric payload values MUST be represented as JSON strings (e.g., "week": "6", not "week": 6). This bypasses divergent JSON number serialization between host languages: json.dumps(1.0) in Python produces "1.0" while JSON.stringify(1.0) in JavaScript produces "1", which would yield different canonical hashes for identical-looking payloads. JSON true, false, and null are permitted scalar values; this restriction applies only to numeric values.

MUST All JSON object keys and string values in the payload MUST be normalized to Unicode Normalization Form C (NFC) before UTF-8 encoding and hashing. Without this, a precomposed character (e.g., é = U+00E9) and a decomposed equivalent (e.g., e + U+0301) would produce different byte sequences and different hashes despite identical visual representation. NFC is the default form produced by most platforms; the constraint is explicit so that implementations cannot silently diverge.

Reference implementations

Python 3:

import json, hashlib, unicodedata

def nfc(x):
    if isinstance(x, str): return unicodedata.normalize("NFC", x)
    if isinstance(x, dict): return {nfc(k): nfc(v) for k, v in x.items()}
    if isinstance(x, list): return [nfc(v) for v in x]
    return x

obj = {k: v for k, v in payload.items() if k != "payload_hash"}
obj = nfc(obj)
canon = json.dumps(obj, sort_keys=True, separators=(",", ":"), ensure_ascii=False)
payload_hash = hashlib.sha256(canon.encode("utf-8")).hexdigest()

JavaScript:

function nfc(x) {
  if (typeof x === "string") return x.normalize("NFC");
  if (Array.isArray(x)) return x.map(nfc);
  if (x !== null && typeof x === "object") {
    const out = {};
    for (const k of Object.keys(x)) out[k.normalize("NFC")] = nfc(x[k]);
    return out;
  }
  return x;
}
function canonicalize(obj) {
  if (obj === null || typeof obj !== "object") return JSON.stringify(obj);
  if (Array.isArray(obj)) return "[" + obj.map(canonicalize).join(",") + "]";
  const keys = Object.keys(obj).sort();
  const pairs = keys.map(k => JSON.stringify(k) + ":" + canonicalize(obj[k]));
  return "{" + pairs.join(",") + "}";
}
// Strip payload_hash at top level only, normalize, then canonicalize.
const { payload_hash, ...rest } = payload;
const canon = canonicalize(nfc(rest));
// Then SHA-256 canon as UTF-8 bytes.

MUST Implementations MUST produce identical hex digests for identical payloads regardless of host language or platform. This written specification is normative. The Python reference implementation in lens.py is canonical for resolving serialization ambiguity under §5 only; it does not override explicit normative text elsewhere in this specification.

§6Body hash (optional)

The optional body_hash payload field seals the markdown body at the time the KNOBE is created. When present, a conforming verifier checks it and reports accordingly (see §7). A mismatch does not cause a failed result; it produces verified-body-modified.

Body normalization

The body is extracted as the text immediately following the second line containing exactly --- (the closing delimiter of the YAML frontmatter), down to the -----BEGIN KNOBE B64----- marker. This rule is explicit because markdown bodies frequently contain --- as a horizontal rule; counting --- lines rather than searching for the first match prevents misidentifying a body horizontal rule as the frontmatter terminator. If a verifier cannot locate two --- lines before the -----BEGIN KNOBE B64----- marker, it MUST report unreadable rather than attempt body hash computation. Before hashing, apply the following normalization in order:

1.Strip leading and trailing whitespace from the entire body string.
2.Replace all CRLF (\r\n) and lone CR (\r) sequences with LF (\n).
3.Strip U+0020 (space) and U+0009 (tab) from the end of each line. MUST NOT strip other whitespace characters.
4.No Unicode normalization is applied.
5.Encode the result as UTF-8 and compute SHA-256.

MUST When multiple payload blocks are present in a file (see §3.3), body extraction is ambiguous: the body could plausibly be extracted down to the first BEGIN marker or down to the last. Conforming verifiers MUST NOT attempt body verification in this case. The body_verified output MUST be reported as omitted regardless of whether the evaluated payload block contains a body_hash field. The multi-block warning required by §3.3 communicates the structural anomaly; body verification semantics are not preserved across that anomaly.

§7Verification states

A conforming verifier MUST report exactly one of the following four states.

Verification states
StateConditionsMeaning
verified Payload decodes and parses. All required fields present. payload_hash matches computed hash. body_hash absent or matching. The sealed payload record is intact. If a body hash was present, the body is also intact.
verified-body-modified Payload hash matches. body_hash is present and does not match the normalized body. The structured payload record is intact. The markdown body has changed since sealing. This is not automatically a sign of tampering; bodies are often legitimately edited. Inspect before relying.
failed Payload decodes and parses, but the computed canonical hash does not match payload_hash. The structured record has been altered since sealing.
unreadable No payload block found, or the block cannot be decoded or parsed as JSON. The file does not contain a verifiable KNOBE payload.

MUST A verifier MUST NOT report failed solely because body_hash is present and does not match. Body-hash mismatch always yields verified-body-modified, never failed.

MUST A verified or verified-body-modified result proves integrity of the sealed payload. It does not prove the content is accurate, the attribution is honest, the consent was obtained, or the object is appropriate for any use. Verifiers SHOULD communicate this distinction to users.

Two-layered verification

KNOBE verification is two-layered. The primary status output reports sealed payload integrity. The secondary body_verified output reports whether the human-readable markdown body was sealed and, if so, whether it still matches. The two layers are reported independently so that receivers can tell what was actually checked. A result of status: verified · body_verified: omitted is not contradictory: it means the payload is intact and no body integrity claim was sealed by the author.

MUST In addition to the verification state, verifiers MUST report a body_verified output with one of three values: yes (body_hash was present and matched), modified (body_hash was present and did not match), or omitted (no body_hash was sealed in the payload). A bare verified result without this output is ambiguous: it does not tell the receiver whether the body was actually checked. Omitted body hashes are the receiver's signal that body integrity was never sealed by the author; an adversary could rewrite the markdown body without detection in this case.

MUST The body_verified output is constrained by the primary verification state:

  • When status is verified, body_verified may be yes or omitted; it MUST NOT be modified.
  • When status is verified-body-modified, body_verified MUST be modified.
  • When status is failed or unreadable, body_verified MUST be omitted, because a compromised or unreadable payload cannot provide a trustworthy body_hash field to check against. The verifier MUST NOT evaluate the body against a hash extracted from an untrusted payload.

Conformance, distinct from integrity

The four verification states report integrity: whether the sealed payload is byte-identical to what was hashed at sealing. They do not, by themselves, report conformance: whether the payload structure and field values satisfy the schema and constraints in this specification. A file can have a hash that matches its payload (integrity is verified) and still violate the spec: for example, created_date: "yesterday" instead of an ISO date, or a numeric value where the spec requires a string, or a malformed parent hash.

Verifiers MUST report conformance as a separate dimension from integrity. This preserves the four-state integrity model while allowing schema validation to be reported honestly without collapsing the two layers.

MUST In addition to status and body_verified, verifiers MUST report a conformance output with one of three values:

  • valid: All required fields are present, all field formats and types match the schema, all open-vocabulary values are syntactically well-formed, and no normative MUSTs are violated.
  • warnings: All required fields are present and the file is usable, but the verifier detected non-fatal issues (e.g., custom vocabulary values without namespace prefixes, fields with unrecognized but well-formed values, soft-spec deviations).
  • invalid: The verifier detected one or more violations of normative MUSTs (e.g., missing required field, malformed payload_hash, numeric value in payload, malformed created_date, malformed parent hash). The file may still verify cryptographically, but does not conform to this specification.

MUST When conformance is warnings or invalid, verifiers MUST surface a list of the specific issues detected. The list format is implementation-defined; the requirement is that issues are individually identifiable to the receiver, not aggregated into an opaque count.

The independence of status and conformance is deliberate. A file with status: verified · conformance: invalid tells the receiver: the sealed bytes are intact, but the author or sealing tool did not follow the spec. The protocol does not silently collapse this into failed, which would conflate cryptographic tampering with schema noncompliance.

Quarantine semantics

Verification state is independent of quarantine_status. A KNOBE may be verified and still carry quarantine_status: "quarantine". Verification tells the receiver whether the payload is intact; it does not authorize use. Implementations SHOULD treat any external or newly received KNOBE as quarantined regardless of its declared status until a human or governed system reviews it.

§8Open vocabularies

The following fields use open vocabularies. The values listed here are canonical and recommended. Implementations MAY define additional values. Verifiers MUST NOT fail a file because an unrecognized vocabulary value is present.

SHOULD Custom vocabulary values SHOULD use a recognizable namespace or prefix convention (e.g., ucdavis:irb-cleared, ext-trusted-by-foundation) to distinguish them from canonical spec values. Verifiers and UI implementations SHOULD render canonical and custom vocabulary values distinguishably to mitigate UI spoofing: a value like quarantine_status: "trusted-by-IRB" may otherwise be mistaken by a casual reader for an authoritative protocol-level designation when it is in fact self-declared.

content_type

original · synthesis · adaptation · compression · annotation · seed · collection · translation

quarantine_status

quarantine (default for new/external) · trusted · rejected

quarantine_status is a declared sender-side or originator-side trust posture. Receivers MUST NOT treat quarantine_status: "trusted" as local authorization unless it is established by their own review process or a governed trust registry. A malicious author can declare any value here; the field communicates the originator's posture, not a receiver's clearance.

privacy_level

public · internal · sensitive · restricted

privacy_level is declarative. It does not override law, policy, consent, IRB conditions, FERPA, HIPAA, or institutional classification. A file may declare public and still contain regulated content; the field records the originator's posture, not legal or institutional authorization. Downstream systems with privacy obligations MUST apply their own classification policy regardless of the declared value.

identity_status

declared (self-reported; default in v1) · signed (placeholder for future cryptographic signing)

accessibility.adaptation_type

caption · simplification · alt-text · translation · multimodal

parents.relationship

adaptation_of · compression_of · synthesis_input · derived_from · responds_to · supersedes

§9Versioning semantics

The spec_version field in the sealed payload records the protocol version under which the file was sealed. Verification semantics follow the sealed version, not the verifier version.

§10Conformance

A conforming KNOBE file MUST:

  • Be valid UTF-8 plain text.
  • Begin with a YAML frontmatter block including spec_version.
  • Contain a Base64 JSON payload block with the BEGIN/END markers specified in §3.3.
  • Include all ten required payload fields (§4.1).
  • Have a payload_hash that matches the canonical hash computed by the algorithm in §5.
  • Have an attribution.sources array with at least one entry.

A conforming verifier MUST:

  • Report exactly one of the four states defined in §7.
  • Apply the canonical hash algorithm defined in §5 exactly as specified.
  • Apply verification semantics of the spec_version sealed in the file.
  • Not fail a file for containing unrecognized payload fields.
  • Not report failed solely on the basis of a body_hash mismatch.
  • Communicate that a verified result proves integrity, not truth.

The reference verifier lens.py is the canonical implementation for resolving serialization ambiguity under §5. This written specification remains normative in all other respects. Test vectors for all four states are available in the test-vectors/ directory. An implementation that produces the expected state for all nine conformance vectors is considered conforming.

§11Limits

This specification defines a format and a verification algorithm. It does not provide:

Integrity, not truth

KNOBE uses standard SHA-256 hashing. There is no cryptographic novelty here, and no claim that a hash can solve trust. The hash proves one narrow thing: the sealed payload has not changed since sealing. It does not prove the content is true, the author is who they say, attribution is honest, consent was obtained, or the object is safe to use. A liar can seal a lie; the seal then proves only that the lie has not changed.

This limit is a design principle, not a flaw to hide. It marks a distinction the rest of the protocol depends on:

control infrastructure

Decides for you

Blocks, permits, denies, enforces, locks, or fails closed. The system makes the call.

responsibility infrastructure

Informs your decision

Makes the relevant conditions visible so a human or institution can decide what to do next. KNOBE is this kind.

The recommended posture is quarantine-first: treat external objects as untrusted until reviewed, even if they verify. Full semantics are in §11 above and the threat model.

For implementers

v1 file semantics are frozen. Everything needed to build a compatible verifier or tool is in this specification, the test vectors (nine files, known results), the reference verifier, and the source repository. Reproduce the nine test vectors and your implementation is canonically compatible with KNOBE Protocol v1.

For agent builders

Agent harness engineering governs execution policy, tool permissions, memory, and observability: the conditions around the agent. KNOBE comes at the problem from the other side, engineering what the object carries through any system rather than the system itself. Harness infrastructure governs the conditions around the agent. KNOBE governs the conditions carried by the artifact. If the artifact arrives stripped, no harness can reconstruct what was never carried.