Status: Informative. Pseudocode patterns to help independent implementations of MDA validators, verifiers, and consumers converge on identical observable behavior. Nothing in this section adds normative requirements; every requirement referenced here is normatively defined in §02–§10 and §13.
MDA v1.0 is a contract, not a reference implementation. The reference TypeScript CLI under apps/cli/ is one of many valid implementations; third-party validators, verifiers, and runtime consumers are equally welcome. Independent implementations naturally diverge on:
- The order of validation steps (schema first, integrity first, signatures first?)
- Where to fail fast vs accumulate errors
- Which checks are mandatory vs optional
- How to layer custom project-specific validation (e.g. a project-defined Zod or pydantic schema sitting on top of MDA's structural rules)
The pseudocode below is the recommended canonical loader algorithm. Implementations that follow it produce the same accept/reject decision for any given file, with the same error category, in every step where MDA defines the behavior. Implementations MAY deviate (e.g. parallelize independent checks, fail-fast vs collect-errors) provided the final decision matches.
function loadMdaArtifact(file_bytes, target, target_schema, options):
# `target` carries metadata about the destination format:
# - target.mode : "source" (.mda) | "output" (.md)
# - target.allowsBodyOnly : true for AGENTS.md per §06-targets/agents-md
# (frontmatter-free is conformant); false elsewhere
# - target.isMultiFile : true for MCP-SERVER.md per §06-targets/mcp-server-md
# === Stage A: Extract (no I/O, no crypto) ===
# §02-1.1 normative algorithm. Returns frontmatter_str = "" (empty string,
# per §02-1.1 step 4) when the file has no opening "---\n" fence; the body
# then carries the entire file. Raises `unterminated-frontmatter` when an
# opening fence has no matching closing fence, or `invalid-encoding` when
# bytes are not valid UTF-8.
frontmatter_str, body_str = extractFrontmatter(file_bytes)
# Frontmatter-free body-only path (§06-targets/agents-md).
# AGENTS.md MAY ship without a YAML frontmatter block at all; in that case
# there is nothing to YAML-parse, nothing to schema-check, and nothing to
# canonicalize beyond the body itself.
if frontmatter_str == "":
if not target.allowsBodyOnly:
REJECT "missing-required-frontmatter"
return {frontmatter: {}, body: body_str}
# YAML parse
frontmatter = parseYaml(frontmatter_str)
if parse failed:
REJECT "frontmatter-yaml-parse-error"
# === Stage B: Structural validation ===
# §02 source-permissive or output-strict schema, depending on target.
# `target_schema` is selected by the caller from `schemas/`:
# target.mode == "source" → frontmatter-source.schema.json
# target.mode == "output" → frontmatter-<target>.schema.json
schemaErrors = validateAgainstJsonSchema(frontmatter, target_schema)
if schemaErrors:
REJECT "schema-violation", details=schemaErrors
# §02-3.1: ISO 8601 fields MUST be quoted strings (caught by schema:type:string)
# §02-3.2: version MUST be a quoted SemVer string (caught by schema)
# §02-3.3: requires keys MUST be kebab-case (caught by schema patternProperties)
# === Stage C: Cross-field semantic checks ===
# §09-2: signatures[].payload-digest MUST equal integrity.digest
if frontmatter.signatures and frontmatter.integrity:
for sig in frontmatter.signatures:
if sig.payload-digest != frontmatter.integrity.digest:
REJECT "signature-digest-mismatch"
elif frontmatter.signatures and not frontmatter.integrity:
REJECT "signatures-without-integrity"
# === Stage D: Integrity verification (optional unless required by profile) ===
# `trusted-runtime` is the production profile from §13. It makes integrity
# and signatures fail-closed requirements instead of best-effort checks.
trusted_runtime = options.profile == "trusted-runtime"
require_integrity = trusted_runtime or options.requireIntegrity
require_signatures = trusted_runtime or options.requireSignatures
integrity_verified = false
if require_integrity and not frontmatter.integrity:
REJECT "missing-required-integrity"
# `integrity` MAY appear without `signatures[]`; the verifier still checks it.
if (options.verifyIntegrity or require_integrity or options.verifySignatures) and frontmatter.integrity:
# §08-3 canonicalization. The helper MUST:
# 1. Strip top-level `integrity` and `signatures[]` from `frontmatter`
# (§08-3.1) before serializing; it does NOT mutate the caller's copy.
# 2. JCS-canonicalize the stripped frontmatter (§08-3.2).
# 3. Normalize and append the body bytes (§08-3.3).
# 4. For multi-file targets, append the §08-3.4 boundary and the next
# file's canonical bytes; pass the sibling files via the helper.
canonical_bytes = canonicalizeArtifact(
frontmatter,
body_str,
multiFileSiblings = target.isMultiFile ? options.siblingFiles : None
)
computed_digest = hash(canonical_bytes, frontmatter.integrity.algorithm)
expected = parseDigest(frontmatter.integrity.digest)
if computed_digest != expected.hex:
REJECT "integrity-mismatch"
integrity_verified = true
# === Stage E: Signature verification (optional unless required by profile) ===
if require_signatures and (not frontmatter.signatures or len(frontmatter.signatures) == 0):
REJECT "missing-required-signature"
if require_signatures and not validateTrustPolicy(options.trustPolicy):
REJECT "trust-policy-violation"
if (options.verifySignatures or require_signatures) and frontmatter.signatures:
# Signatures prove who signed the declared digest. They do not prove the
# current artifact bytes still match that digest. A verifier that treats
# signatures as a trust gate MUST verify integrity first (§13-2).
if not integrity_verified:
REJECT "missing-required-integrity"
trusted_signer_identities = set()
candidate_errors = []
for sig in frontmatter.signatures:
# §09-3.1 PAE envelope reconstruction. When sig.payload-type is
# absent the verifier MUST use the default `application/vnd.mda.integrity+json`
# (§09-2). The payload bytes are the JCS form of the (un-stripped)
# `integrity` object exactly as it appears in the frontmatter.
payload_type = sig.payload-type or "application/vnd.mda.integrity+json"
pae = constructDssePae(
payload-type = payload_type,
payload-bytes = jcsCanonicalize(frontmatter.integrity)
)
if sig.signer starts with "sigstore-oidc:":
# §09-4.2 verification flow
rekor_entry = fetchRekorEntry(
options.trustPolicy.rekor.url,
sig.rekor-log-id,
sig.rekor-log-index
)
if rekor_entry == null:
candidate_errors.add("rekor-inclusion-failure")
continue
if rekor_entry.kind != "dsse-v0.0.1":
candidate_errors.add("rekor-entry-type-mismatch")
continue
if not verifyRekorInclusion(rekor_entry, options.rekorRoots):
candidate_errors.add("rekor-inclusion-failure")
continue
cert = extractFulcioCert(rekor_entry)
if not verifyFulcioChain(cert, options.sigstoreRoot):
candidate_errors.add("fulcio-chain-failure")
continue
if not verifyEcdsaOrEd25519(pae, sig.signature, cert.publicKey):
candidate_errors.add("signature-verification-failure")
continue
if trustPolicyMatches(
options.trustPolicy,
type = "sigstore-oidc",
issuer = cert.oidcIssuer,
subject = cert.oidcSubject
):
trusted_signer_identities.add(
"sigstore-oidc:" + cert.oidcIssuer + "\n" + cert.oidcSubject
)
elif sig.signer starts with "did-web:":
# §09-5.2 verification flow
domain = parseDidWebDomain(sig.signer)
if domain == null:
REJECT "unknown-signer-method"
if not options.didWebVerifier:
REJECT "trust-policy-violation"
if options.trustPolicy and not trustPolicyMatches(
options.trustPolicy,
type = "did-web",
domain = domain
):
continue
keys = options.didWebVerifier.fetchKeys(domain)
key = lookupKeyById(keys, sig.key-id)
if not verifyEcdsaOrEd25519(pae, sig.signature, key.public-key):
candidate_errors.add("signature-verification-failure")
continue
if trustPolicyMatches(
options.trustPolicy,
type = "did-web",
domain = domain
):
trusted_signer_identities.add("did-web:" + domain)
else:
REJECT "unknown-signer-method"
min_signatures = options.trustPolicy?.minSignatures or options.minSignatures or 1
if require_signatures and len(trusted_signer_identities) == 0:
if len(candidate_errors) > 0:
REJECT candidate_errors[0]
REJECT "no-trusted-signature"
if require_signatures and len(trusted_signer_identities) < min_signatures:
REJECT "insufficient-trusted-signatures"
# === Stage F: Capability requirements (optional, gated by options) ===
# The `requires` block lives in different locations in source vs output mode:
# source mode → frontmatter.requires (top-level, §02-2 source)
# output mode → frontmatter.metadata.mda.requires (lifted, §02-2 output)
requires_block = (
frontmatter.requires
if target.mode == "source"
else frontmatter.metadata?.mda?.requires
)
if options.enforceRequires and requires_block:
# §10-4 consumer behavior
for key, value in requires_block:
if isStandardKey(key):
if not satisfies(key, value, options.environment):
REJECT "requires-not-satisfied", key=key
# unknown keys: silently OK (§10-4)
# === Stage G: Project-specific validation (out of scope for MDA) ===
# E.g. Zod / pydantic schema for metadata.<vendor>.* substructures.
# MDA does not constrain this layer.
if options.projectSchema:
projectErrors = options.projectSchema.validate(frontmatter)
if projectErrors:
REJECT "project-schema-violation"
return {frontmatter, body: body_str}
For interoperable error reporting between MDA tools and downstream observability, the following error categories are RECOMMENDED. Implementations MAY add their own categories; consumers SHOULD recognize at least these.
| Category | Meaning | Spec section |
|---|---|---|
frontmatter-yaml-parse-error |
YAML syntax invalid | §02-1.1 |
unterminated-frontmatter |
Opening --- without matching closing fence |
§02-1.1 step 5 |
invalid-encoding |
Non-UTF-8 bytes | §02-1.1 step 2 |
missing-required-frontmatter |
Target requires frontmatter but file has none (e.g. SKILL.md, MCP-SERVER.md). AGENTS.md is the only Tier-1/Tier-2 target that admits a body-only file. | §02, §06-targets/* |
schema-violation |
JSON Schema 2020-12 validation failed | §02 |
signature-digest-mismatch |
payload-digest != integrity.digest |
§09-2 |
signatures-without-integrity |
signatures[] present without integrity |
§09-2 |
integrity-mismatch |
Computed digest != declared digest | §08-4 |
rekor-entry-type-mismatch |
Sigstore Rekor entry not dsse-v0.0.1 |
§09-4.2 |
rekor-inclusion-failure |
Rekor entry missing or inclusion proof did not verify against the configured log root | §09-4.2 |
fulcio-chain-failure |
Fulcio certificate chain did not verify to the configured Sigstore root | §09-4.2 |
signature-verification-failure |
Cryptographic signature did not verify on the PAE envelope | §09-4.2, §09-5.2 |
missing-required-integrity |
The selected verifier profile requires integrity, but the artifact does not declare it or has not successfully verified it before signature trust decisions. |
§13 |
missing-required-signature |
The selected verifier profile requires at least one signature, but signatures[] is absent or empty. |
§13 |
insufficient-trusted-signatures |
Fewer than the configured minSignatures distinct signer identities verified and matched the trust policy. |
§13 |
no-trusted-signature |
Signatures verified cryptographically, but none matched the configured trust policy. | §13 |
trust-policy-violation |
Trust policy file is malformed, unsupported, or impossible to satisfy. | §13 |
unknown-signer-method |
signer prefix is neither sigstore-oidc: nor did-web: |
§09-2 |
requires-not-satisfied |
Standard requires key cannot be honored |
§10-4 |
project-schema-violation |
Vendor / project-specific schema (non-MDA) | out of scope |
Real-world consumers often combine MDA's structural rules with their own runtime schema (e.g. Zod for TypeScript, pydantic for Python) over metadata.<vendor>.* substructures. The recommended layering:
- MDA structural validation (Stages B + C above) — the universal interop floor.
- Project schema validation (Stage G) — runtime types specific to the consumer's domain (e.g. an LLM-config preset's
model/provider/temperatureshape undermetadata.<vendor>.*).
The two layers do not overlap: MDA enforces top-level structure and reserved fields; the project schema enforces vendor-namespace contents that MDA intentionally does not parse (§04-5.1). Implementations MUST NOT use a project schema to override MDA structural rules (e.g. a project schema MUST NOT permit unevaluatedProperties: true on a target output).
Many consumers will read MDA artifacts without performing integrity or signature verification (e.g. a SKILL.md loader that just wants name and description). Such consumers MUST still:
- Apply §02-1.1 frontmatter extraction
- Apply target-schema validation (Stage B)
- Apply §09-2 cross-field check IF they observe both
integrityandsignatures[](a consumer that sees a mismatch and silently loads anyway is misleading)
They MAY skip Stages D, E, F, G. They SHOULD document which stages they apply.
Consumers that skip Stage D or Stage E are not running the §13
trusted-runtime profile and MUST NOT present the loaded artifact as trusted
signed configuration.
A consumer that wants tamper detection without identity attestation MAY perform Stage D (integrity verification) without performing Stage E (signatures[] verification). The two stages are independent: integrity MAY appear without signatures[], and a verifier that does so still benefits from §08 reproducibility. The reverse is not permitted: §09-2 forbids signatures[] without integrity, and Stage C catches it before any cryptographic work.
The following implementations follow this guide:
apps/cli/— TypeScript reference CLI (npm@markdown-ai/cli). Architecture spec atapps/cli/IMPL-SPEC.md.
Third-party implementations are encouraged. Implementations that pass the conformance suite (§07) and follow the algorithm above SHOULD be listed in REGISTRY.md under "Reference implementations" once a follow-up registry section is added.