Modular Curriculum Format (MCF) 1.1
Status
This document defines Modular Curriculum Format (MCF) 1.1. MCF is an open, human-readable source format for portable educational content. It standardizes authored educational intent, not a learning platform, user interface, learner record, or compiler output.
The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, NOT RECOMMENDED, MAY, and OPTIONAL in this document indicate requirement levels.
MCF 1.1 is the current specification. The normative MCF 1.0 text, schemas, and compatibility fixtures are retained in versioned repository paths.
1. Design goals
MCF 1.1 has six goals:
- provide a stable, internally consistent MCF 1.1 source contract;
- make parsing and validation deterministic across independent implementations;
- support portable courses, modules, lessons, question banks, and asset collections;
- represent richer pedagogy, assessment, accessibility, localization, and reuse;
- define safe interchange and extension boundaries; and
- keep delivery, storage, accounts, analytics, and visual presentation outside the format.
2. Versions and compatibility
An MCF 1.1 package declares:
mcf: "1.1"
A conforming MCF 1.1 implementation MUST also read and validate packages
declaring mcf: "1.0" according to the MCF 1.0 specification and schemas. It
MUST NOT apply 1.1-only required fields or reinterpret 1.0 source using
conflicting 1.1 rules. Diagnostics SHOULD use the current error-code catalog
where an equivalent code exists.
A writer MAY preserve or emit MCF 1.0 only when explicitly requested. It MUST NOT silently change a package's declared version. Migrating source from 1.0 to 1.1 is a deliberate writer operation whose result MUST validate as 1.1.
MCF version strings are exact. A reader that does not support a declared version
MUST report MCF_VERSION_UNSUPPORTED; it MUST NOT guess that a different version
has equivalent semantics.
Additive changes may occur in a later 1.x version. Removing or reinterpreting existing valid source requires a new major version.
3. Package model
Every distributable unit is a package with a root manifest.yaml. The kind
field identifies its entry model:
course: an ordered collection of chapters;module: an ordered collection of lessons;lesson: one standalone.mcflesson;question_bank: a reusable YAML question collection; orasset_collection: a reusable collection of declared assets.
For mcf: "1.1", kind defaults to course when omitted.
3.1 Course package
course/
|-- manifest.yaml
|-- chapters/
| `-- chapter-id/
| |-- chapter.yaml
| `-- lessons/
| `-- lesson.mcf
`-- assets/
manifest.yaml, chapters/, and at least one declared lesson are required.
assets/ is optional. Ordering comes only from YAML declarations.
3.2 Module package
module/
|-- manifest.yaml
|-- lessons/
| `-- lesson.mcf
`-- assets/
A module manifest contains an ordered non-empty lessons list. Each item has a
source path relative to the package root.
3.3 Lesson package
lesson/
|-- manifest.yaml
|-- lesson.mcf
`-- assets/
A lesson manifest has an entry path identifying one .mcf file.
3.4 Question-bank package
bank/
|-- manifest.yaml
|-- questions.yaml
`-- assets/
A question-bank manifest has an entry path identifying a question-bank YAML
file as defined in Section 18.
3.5 Asset-collection package
An asset-collection manifest declares one or more assets and has no content entry. It is intended for licensed, attributed, reusable media.
3.6 Package identity
Every package has an id. The pair (id, version) identifies a published
package version. Authors SHOULD use a stable, globally controlled ID such as a
reverse-domain identifier when packages will be distributed broadly:
id: org.example.calculus-i
version: "1.1.0"
MCF does not operate a global package registry. Implementations MUST NOT assume that a short ID is globally unique.
4. YAML profile
MCF YAML documents and fenced YAML objects use the YAML 1.2 data model restricted to JSON-compatible values:
- mapping keys MUST be strings;
- duplicate mapping keys are invalid;
- custom tags, anchors, aliases, and merge keys are invalid;
- non-finite numbers are invalid;
- timestamps have no special MCF meaning and SHOULD be quoted strings;
- source MUST be UTF-8 without a byte-order mark; and
- readers MUST NOT execute or instantiate language-specific YAML objects.
Unknown core fields are invalid unless they occur inside an extensions value.
Schemas define where null is allowed; otherwise a field MUST be omitted rather
than set to null.
4.1 Rich-content scalar serialization
YAML decoding occurs before Markdown and TeX processing. A writer MUST serialize
a rich-content string so that its decoded YAML value exactly equals the intended
Markdown/TeX source. Writers SHOULD use a single-quoted scalar for single-line
rich content containing TeX backslashes, and SHOULD use a literal block scalar,
preferably |- when a trailing newline is not intended, for multiline or
display-math rich content:
explanation: '$12\times 12 = 144$.'
explanation: |-
$$
\sqrt{x^2}=|x|
$$
An equivalent double-quoted scalar is possible when every intended literal TeX backslash is YAML-escaped:
explanation: "$12\\times 12 = 144$."
The following is a valid YAML scalar, but is a pitfall:
explanation: "$12\times 12 = 144$."
It decodes \t as a tab and therefore does not contain the intended \times
TeX command. Similar failure modes affect \frac, \sqrt, and \% in
double-quoted scalars. A reader MUST pass the decoded scalar value into the
rich-content pipeline without reconstructing, repairing, or inferring lost
source escapes. Plain scalars may work, but SHOULD NOT be recommended for
arbitrary rich content because YAML punctuation can change their interpretation.
5. Identifiers, paths, and references
5.1 Identifiers
Local identifiers MUST match:
[a-z][a-z0-9._-]*
Chapter and lesson IDs are unique within a course. Activity and question IDs are unique within a lesson. Option, matching-item, ordering-item, rubric, criterion, and level IDs are unique within their containing object. Asset IDs are unique within the package.
IDs SHOULD remain stable when titles or file names change.
5.2 Paths
Package paths:
- use forward slashes;
- are relative, never absolute;
- MUST NOT begin with a Windows drive prefix such as
C:/; - MUST NOT contain an empty segment,
.segment, or..segment; - MUST NOT contain a backslash or NUL;
- are resolved case-sensitively; and
- MUST resolve to a regular file or declared directory within the package.
A missing referenced local file makes the package invalid. URL references are allowed only where the relevant field permits them.
5.3 Package references
A relationship or dependency may identify a package by id, optional version,
and optional href. An href may be a safe package-relative archive path
satisfying Section 5.2 or an absolute https URL. Other URI schemes and
arbitrary non-path strings are invalid. Network resolution is not required for
source validation unless explicitly requested by the user.
6. Common metadata
The following optional metadata fields may occur on packages, chapters, lessons, and activities unless a schema narrows their use:
description: "A first course in calculus."
authors:
- "Example Author"
license: CC-BY-4.0
subjects:
- mathematics
- calculus
keywords:
- derivatives
- rates of change
level:
label: undergraduate
identifier: first-year
estimated_duration: PT45M
prerequisites:
- statement: "Understand functions and algebra."
learning_outcomes:
- id: derivative-definition
statement: "Explain a derivative as an instantaneous rate of change."
framework:
name: "Example Mathematics Framework"
identifier: "CALC.DERIVATIVE.1"
uri: https://example.org/outcomes/CALC.DERIVATIVE.1
subjects and keywords are non-empty lists of non-empty strings. level is
either a non-empty string or an object containing a human-readable label and
optional identifier and uri.
estimated_duration is an ISO 8601 duration string. Calendar years and months
SHOULD NOT be used because their elapsed length is context dependent.
A prerequisite is an object with a required statement and optional
identifier, uri, and package.
A learning outcome has a required statement, an optional local id, and an
optional framework. A framework has a required name and optional
identifier and uri. MCF does not define a universal subject, level, or
curriculum vocabulary.
7. Relationships, dependencies, and localization
A manifest MAY declare relationships:
relationships:
- type: translation_of
package: org.example.calculus-i
version: "1.1.0"
language: en-CA
href: dependencies/calculus-i-en.mcf.zip
Core relationship types are:
translation_of;has_translation;is_version_of;has_version;derived_from;requires; andsupplements.
package is required. version, language, and href are optional.
Language values MUST be well-formed BCP 47 language tags under RFC 5646,
including its grandfathered forms, extension structure, and private-use form.
Underscore-separated locale identifiers are not language tags. Schema-aware
validators MUST implement the bcp47 format as grammar validation rather than
substituting a loose locale regular expression. Readers MUST compare language
tags case-insensitively and SHOULD preserve author casing. A translated package
SHOULD preserve stable IDs for semantically corresponding content. Translation
does not imply byte-for-byte structural identity.
Dependencies use requires. A package validator MUST report unresolved required
dependencies when validation is performed in a closed package set. It MAY report
them as unavailable rather than invalid during offline validation of one package.
8. Assets, attribution, and accessibility
A package MAY declare assets:
assets:
- id: velocity-video
source: assets/video/velocity.mp4
media_type: video/mp4
title: "Velocity demonstration"
description: "A cart accelerates along a measured track."
creator: "Example Laboratory"
license: CC-BY-4.0
attribution_url: https://example.org/velocity
integrity: sha256-BASE64_VALUE
language: en
captions:
- source: assets/captions/velocity-en.vtt
language: en
kind: captions
transcript:
source: assets/transcripts/velocity.md
language: en
audio_description:
source: assets/audio/velocity-description.mp3
language: en
Required asset fields are id and source. media_type SHOULD be an IANA media
type. integrity, when present, uses Subresource Integrity syntax and MUST match
the packaged bytes.
Caption entries require source, language, and kind. Core kinds are
captions, subtitles, and descriptions. Transcript and audio-description
objects require source and MAY declare language.
An alternates entry identifies another packaged rendition of the same
educational asset. It requires source and purpose; optional fields are
language, media_type, and description. Core purposes are
accessible_alternative, low_bandwidth, print, and transcoded. An
alternate is not a translation relationship between packages.
Every local file referenced by an asset record MUST exist. Asset records do not replace Markdown alternative text. An informative image MUST still have useful alt text at each use site; decorative images use empty alt text.
Rich content may refer to a declared asset as asset:ASSET_ID or use a relative
file path. A declared asset enables attribution and alternatives to travel with
the source.
9. Course, chapter, and lesson structures
9.1 Course manifest
mcf: "1.1"
kind: course
id: intro-physics
title: "Introduction to Physics"
language: en
version: "1.1.0"
chapters:
- source: chapters/motion
Required course fields are mcf, id, title, language, and chapters.
kind defaults to course. Each chapter item contains a source directory
under chapters/.
9.2 Chapter
id: motion
title: "Motion"
description: "Distance, velocity, and acceleration."
lessons:
- lessons/01-introduction.mcf
- lessons/02-velocity.mcf
Required fields are id, title, and a non-empty ordered lessons list.
Lesson paths are relative to the chapter directory.
9.3 Lesson
A .mcf lesson is UTF-8 Markdown with YAML frontmatter followed by one or more
activities:
---
id: velocity
title: "Velocity"
---
:::mcf-activity
type: notes
id: velocity-notes
title: "Understanding velocity"
:::
Velocity is displacement over time.
:::mcf-end
Required frontmatter fields are id and title. Common metadata, rubrics,
completion, relationships, and extensions are optional.
10. Lesson lexical grammar
The following grammar is normative together with the rules below:
lesson = frontmatter, separation, activity,
{ separation, activity }, trailing ;
frontmatter = delimiter, newline, yaml-lines, delimiter, newline ;
activity = activity-open, newline, activity-yaml,
header-close, newline, activity-body, activity-end ;
activity-open = ":::mcf-activity" ;
header-close = ":::" ;
activity-end = ":::mcf-end" ;
delimiter = "---" ;
separation = { blank-line | comment } ;
trailing = { blank-line | comment } ;
newline = LF ;
Additional rules:
- Lines are normalized from CRLF to LF before parsing. Lone CR is invalid.
- The first line MUST be
---; leading content and UTF-8 BOMs are invalid. - Delimiter and container-marker lines have no leading or trailing characters.
- The frontmatter closes at the next exact
---line. - The activity header closes at the next exact
:::line. - The activity body ends at the next exact
:::mcf-endline that is not inside a fenced code block. - CommonMark fenced-code rules determine whether a marker is inside a fence.
- Activities cannot nest.
- Outside frontmatter and activities, only blank lines and complete HTML comments are permitted. Comments do not carry MCF semantics.
- An unterminated frontmatter, activity header, code fence, or activity is invalid.
- A literal marker at the start of a body line MUST be placed in a fenced code block or written using a character reference or other semantically equivalent Markdown representation.
The YAML portions are interpreted using Section 4. Rich-content parsing begins
only after structural containers and mcf-question fences have been identified.
11. Activities
MCF 1.1 activity types are:
notes: instructional content;practice: formative work;assessment: evaluative work; andassignment: work intended for learner submission.
Every activity requires type and id; title and common metadata are optional.
Practice and assessment activities MAY define:
randomize: true
question_pool_size: 5
question_pool_size is a positive integer no greater than the number of
questions in the activity. Randomization changes delivery order, never authored
identity or answer semantics.
Assessment activities MAY define passing_score from 0 through 1.
Assignment activities require:
submission:
modes: [text, file]
Core submission modes are text, file, and url. Optional fields are
minimum_files, maximum_files, accepted_media_types, and
maximum_file_size. A maximum size is a positive integer byte count.
An assignment MAY reference a rubric ID and SHOULD set evaluation: manual.
submission and an activity-level rubric are valid only on assignment.
When both file limits occur, minimum_files MUST NOT exceed maximum_files.
MCF defines expected submission shape, not upload transport, storage, identity, deadlines, or gradebook behavior.
12. Rich content and media
Rich content uses CommonMark-compatible Markdown. Readers MUST support paragraphs, headings, emphasis, lists, links, block quotes, fenced code, and images. Readers SHOULD support GitHub-style tables.
Math uses $...$ inline and $$...$$ for display math. Math is identified from
rich-content source before Markdown transformations are applied to the contents
of the math span. The contents of a recognized inline or display math span are
opaque TeX source for Markdown purposes. Readers MUST NOT remove or reinterpret
TeX backslashes inside recognized math spans. Readers MUST preserve the original
TeX payload even if they cannot render it; see Section 4.1 for YAML scalar
serialization guidance.
Images use Markdown:


Audio and video use:
@[audio](../../../assets/audio/example.mp3 "Example")
@[video](../../../assets/video/example.mp4 "Example")
@[video](asset:velocity-video "Velocity demonstration")
@[video](youtube:VIDEO_ID "Online video")
The media target is a relative path, declared asset reference, or registered
provider reference. MCF 1.1 registers only youtube:VIDEO_ID. Unknown provider
schemes require an extension.
Raw HTML is untrusted rich content. A reader MAY sanitize or omit it and MUST NOT execute scripts merely because they occur in MCF source. Writers SHOULD prefer portable Markdown.
Media may occur wherever rich content is allowed, including prompts, option text, hints, explanations, feedback, rubric descriptions, and assignment instructions.
13. Question objects
Questions occur in mcf-question fenced blocks:
```mcf-question
id: q1
type: multiple_choice
prompt: "Which quantity includes direction?"
options:
- id: speed
text: "Speed"
- id: velocity
text: "Velocity"
feedback: "Correct: velocity is a vector."
answer: velocity
hint: "Think about vectors."
explanation: "Velocity includes magnitude and direction."
points: 1
required: true
evaluation: automatic
```
The fence content is one YAML mapping. Common required fields are id, type,
and prompt.
Common optional fields:
hint;explanation;points, a non-negative number defaulting to1;required, a boolean defaulting totrue;evaluation;learning_outcomes, a list of local outcome IDs; andextensions.
prompt, hint, explanation, option text, and feedback are rich-content
strings. A block scalar is recommended for multiline content.
Evaluation modes are:
automatic: evaluated from an objective answer;manual: evaluated by a person or external process;completion: evaluated only against response-completion requirements; andungraded: collected without correctness or completion evaluation.
Default evaluation is automatic for objective types, manual for essay,
ungraded for open_response, and manual for assignment submissions.
13.1 Evaluation matrix
Question evaluation modes are normative:
| Question type | Permitted modes | Default |
|---|---|---|
multiple_choice |
automatic |
automatic |
multiple_select |
automatic |
automatic |
true_false |
automatic |
automatic |
numeric |
automatic |
automatic |
short_answer |
automatic |
automatic |
matching |
automatic |
automatic |
ordering |
automatic |
automatic |
essay |
manual, completion |
manual |
open_response without completion fields |
ungraded |
ungraded |
open_response with completion fields |
completion |
completion |
An essay referencing a rubric MUST use manual. An explicit mode that conflicts
with this matrix is invalid.
Activity evaluation modes are:
| Activity type | Permitted modes | Default |
|---|---|---|
notes |
ungraded |
ungraded |
practice |
automatic, manual, completion, ungraded |
derived |
assessment |
automatic, manual, completion |
derived |
assignment |
manual, completion, ungraded |
manual |
For practice and assessment, an omitted mode is derived after question
resolution: manual if any required question is manual; otherwise completion
if any required question is completion-based; otherwise automatic. An
activity explicitly marked ungraded has no score.
14. Question types
14.1 Multiple choice
multiple_choice requires at least two options and answer, which is one option
ID. Option IDs are unique. An option requires id and text and MAY include
feedback.
A multiple-choice option MAY define weight from 0 through 1. When any option
has a weight, every option MUST have one and the answer option MUST have weight
1. Selecting an option awards weight * points. Without weights, the answer
option awards all points and every other option awards zero. Weights are not
valid on multiple-select options, whose partial-credit algorithm is defined
below.
14.2 Multiple select
multiple_select requires at least two options and a non-empty, duplicate-free
answer list containing option IDs. Answer order is insignificant.
scoring is exact or partial, defaulting to exact. Exact scoring awards
all points only when selected IDs equal answer IDs.
Partial scoring is:
max(0, correct_selected / correct_total
- incorrect_selected / incorrect_total) * points
When there are no incorrect options, the second fraction is zero. A reader MUST not round the result except for display.
14.3 True/false
true_false requires a boolean answer.
14.4 Numeric
numeric requires a numeric answer. It MAY define:
unit: m/s
tolerance:
absolute: 0.1
relative: 0.01
As a shorthand, tolerance MAY be a non-negative number and means absolute
tolerance.
A response is correct when either enabled test succeeds:
absolute: abs(response - answer) <= absolute
relative: abs(response - answer) <= relative * abs(answer)
If both are present, satisfying either is sufficient. When the answer is zero, relative tolerance alone is invalid. Default absolute tolerance is zero.
unit is a trimmed, case-sensitive expected label. MCF 1.1 does not define unit
conversion. A reader MUST NOT treat a numerically equal response with a
different supplied unit as correct unless an extension defines conversion.
14.5 Short answer
short_answer requires exactly one of:
answer: "MCF"
or:
answers:
- "MCF"
- "Modular Curriculum Format"
An answer matches when it matches any accepted answer after normalization:
normalization:
trim: true
case_sensitive: false
collapse_whitespace: false
unicode: NFC
Defaults are: trim is true, case sensitivity is false, whitespace collapsing is
false, and Unicode normalization is NFC. Allowed Unicode values are NFC,
NFD, NFKC, NFKD, and none.
14.6 Essay
essay represents manually evaluated extended writing. It MUST NOT define an
objective answer. It MAY reference a rubric and MAY define completion
requirements from Section 14.7. Default evaluation is manual.
14.7 Open response
open_response represents a reflection, survey response, prediction, journal
entry, or other response without an objectively correct answer. It MUST NOT
define an answer or rubric.
It MAY define:
minimum_words;minimum_sentences;keywords; andminimum_keywords.
These are completion conditions only. If any condition is present, evaluation
defaults to completion; otherwise it defaults to ungraded.
For both essay and open_response, word, sentence, and keyword counting MUST
follow the conformance algorithm:
- normalize text to Unicode NFC;
- replace Markdown syntax characters with spaces while retaining text;
- split words at Unicode whitespace and punctuation;
- discard empty tokens;
- compare keywords using Unicode case folding; and
- count a sentence when a non-empty run ends in
.,!, or?.
Implementations MAY display richer language-aware estimates but conformance results use this algorithm.
14.8 Matching
matching requires at least two premises, at least two responses, and an
answer mapping from every premise ID to one response ID:
type: matching
prompt: "Match each term."
premises:
- id: velocity
text: "Velocity"
responses:
- id: vector
text: "Magnitude and direction"
answer:
velocity: vector
scoring: partial
reuse_responses: false
Premise and response IDs are unique within their respective lists.
reuse_responses defaults to false. When false, answer response IDs cannot
repeat. Exact scoring requires every pair to match. Partial scoring awards
correct_pairs / total_pairs * points.
14.9 Ordering
ordering requires at least two items and an answer list containing every item
ID exactly once:
type: ordering
prompt: "Order the steps."
items:
- id: simplify
text: "Simplify."
- id: limit
text: "Take the limit."
answer: [simplify, limit]
scoring: partial
Exact scoring requires the complete order. Partial scoring awards
correct_positions / total_items * points.
15. Feedback and scoring
hint is guidance available before correctness is known. explanation explains
the authored answer or evaluation intent. Option or item feedback is associated
with that response.
Implementations choose when feedback is displayed, but MUST preserve its association and MUST NOT present feedback attached to an unselected option as though the learner selected it.
Points are authored weights, not gradebook records. An activity score is:
sum(question earned points) / sum(question available points)
Questions with points: 0 do not affect the denominator. An activity with zero
available points has no numeric score. Manual or pending evaluations prevent a
final activity score unless the implementation clearly reports a provisional
score.
16. Rubrics
Rubrics may be declared in a package manifest or lesson frontmatter:
rubrics:
- id: mathematical-explanation
title: "Mathematical explanation"
criteria:
- id: correctness
description: "The mathematics is correct."
levels:
- id: complete
description: "Correct and fully justified."
points: 4
- id: partial
description: "Mostly correct."
points: 2
- id: insufficient
description: "Substantial errors."
points: 0
A rubric requires id, title, and at least one criterion. A criterion requires
id, description, and at least two levels. A level requires id,
description, and non-negative points.
Within one criterion, level points MUST be unique. A rubric score is the sum of the selected level points, at most one level per criterion. MCF defines the rubric and calculation, not reviewer identity, comments, moderation, or storage.
A question or assignment refers to a rubric by local ID. Every reference MUST resolve in the nearest lesson scope or package scope; lesson rubrics shadow package rubrics with the same ID.
17. Completion rules
Completion rules express author intent, never learner state. In MCF 1.1 they MAY occur only in lesson frontmatter, so every activity and question reference is resolved within that lesson:
completion:
all:
- activity: introduction-notes
requirement: viewed
- activity: derivative-practice
requirement: attempted
- activity: derivative-assessment
requirement: passed
minimum_score: 0.7
A completion expression contains exactly one of all or any, each a non-empty
list of conditions. Nested expressions are allowed to a maximum depth of eight.
A condition identifies one lesson-local activity or question and one
requirement:
viewed;attempted;answered;submitted;passed; ormanually_marked_complete.
minimum_score is from 0 through 1 and is allowed only with passed. The target
ID MUST resolve within the containing lesson. Package- and chapter-level
completion expressions are not defined in MCF 1.1.
The format does not define event collection, learner identity, progress storage, unlocking, deadlines, overrides, or synchronization.
18. Question banks
A question-bank entry is a YAML mapping:
id: calculus-basics
title: "Calculus basics"
questions:
- id: limit-001
type: numeric
prompt: "Evaluate the limit."
answer: 2
Required fields are id, title, and a non-empty questions list. Questions
use the same objects as mcf-question fences.
An activity can reference bank questions:
```mcf-question-ref
bank: org.example.calculus-basics
question: limit-001
```
bank identifies a declared requires relationship or a question-bank package
available in the package set. question is the stable bank-local ID.
References are resolved before randomization. Readers MUST preserve the bank and question identities in normalized models and diagnostics. An unresolved reference is invalid during closed-set validation.
19. Extensions
MCF 1.1 supports namespaced extensions without allowing them to redefine core meaning:
extensions:
org.example.geogebra:
required: false
data:
source: assets/constructions/triangle.ggb
Extension keys MUST be lowercase reverse-domain names with at least three
dot-separated segments. An extension value requires required and data.
A reader:
- MUST preserve unknown extensions when performing a lossless round trip;
- MAY ignore an unknown extension with
required: falseafter reporting an informational diagnostic; - MUST stop semantic processing of the containing object and report
MCF_EXTENSION_REQUIRED_UNSUPPORTEDfor an unknown required extension; and - MUST NOT allow an extension to change validation or meaning of core fields.
Executable extension content remains subject to the security rules.
20. Capability declarations
An implementation MAY publish a capability document:
mcf_capabilities: "1.1"
implementation:
name: Example Reader
version: "2.0.0"
mcf_versions: ["1.0", "1.1"]
conformance:
- validator
- reader
package_kinds:
- course
- module
- lesson
question_types:
- multiple_choice
- numeric
- open_response
features:
- archive
- accessibility_assets
extensions:
- org.example.geogebra
A capability declaration reports support; it does not change package validity. Advertising a conformance class asserts support for all mandatory behavior of that class and version. Partial implementations MUST list concrete capabilities and MUST NOT claim full conformance.
Because 1.0 reading and validation are mandatory for every conforming MCF 1.1
implementation, a capability document claiming any conformance class MUST list
both "1.0" and "1.1" in mcf_versions.
21. Archive convention
The standard archive suffix is .mcf.zip. The ZIP root contains
manifest.yaml directly.
Archive entries:
- use UTF-8 names and forward slashes;
- MUST satisfy Section 5 paths;
- MUST NOT be absolute, duplicated, encrypted, symlinks, hard links, devices, sockets, or other special files;
- MUST NOT escape the extraction root after normalization;
- MUST have matching local-header and central-directory names; and
- MUST be rejected if their declared or actual expansion exceeds an implementation's documented resource limits.
Readers MUST validate paths before extraction. Implementations SHOULD process archives without writing untrusted entries to disk and SHOULD document limits for entry count, individual size, total expanded size, and compression ratio.
For deterministic conformance testing, the canonical package-reader profile
rejects an archive exceeding any of: 4,096 entries, 64 MiB for one expanded
entry, 512 MiB total expanded bytes, or a 200:1 per-entry compression ratio.
Implementations MAY enforce stricter limits. If a trusted deployment explicitly
raises a limit, it MUST still recognize the canonical over-limit fixture and be
able to report MCF_ARCHIVE_LIMIT_EXCEEDED when tested with the canonical
profile.
Archive entry order has no semantic meaning. Source ordering remains declarative.
22. Security and trust
Valid MCF source is not automatically trusted content.
Readers and compilers:
- MUST prevent package-root escape;
- MUST NOT execute raw HTML scripts, embedded code, SVG scripts, or extensions by default;
- MUST treat
javascript:,data:text/html,file:, and equivalent active URI schemes as unsafe; - MUST sanitize generated HTML;
- MUST require an explicit user or administrator policy before fetching remote resources;
- MUST bound YAML nesting, archive expansion, file sizes, and parser work; and
- SHOULD verify declared integrity before using an asset.
An implementation MAY reject content according to a stricter security policy. It MUST distinguish a source-invalid diagnostic from a policy rejection.
23. Validation and error reporting
A valid MCF 1.1 package has:
- valid YAML under Section 4;
- the required layout and fields for its package kind;
- resolvable and safe local paths;
- valid BCP 47 languages and declared metadata;
- valid lesson grammar;
- supported core activity and question types;
- unique, well-formed IDs;
- valid type-specific answers and scoring;
- resolved local rubrics, completion targets, assets, and closed-set references;
- valid extension declarations; and
- a manifest whose declared order is preserved.
Diagnostics have:
code: MCF_QUESTION_DUPLICATE_OPTION_ID
severity: error
message: "Option ID 'a' occurs more than once."
file: chapters/test/lessons/test.mcf
line: 14
column: 3
object_id: q1
code and severity are portable. Message wording and source location precision
are implementation-specific. Core error codes are defined in
conformance/error-codes.yaml.
Severity values are error, warning, and info. A package is invalid when one
or more error diagnostics are produced.
24. Conformance classes
24.1 Validator
A conforming validator MUST parse every core package kind, apply every normative validation rule, and emit applicable standard error codes. It need not render content.
24.2 Reader
A conforming reader MUST perform validator behavior, preserve ordering and identity, expose all core semantic fields, and avoid silently discarding unsupported required content.
24.3 Writer
A conforming writer MUST produce valid source, stable non-conflicting IDs, deterministic ordering, declared dependencies, and lossless preservation of unknown optional extensions when editing existing content.
24.4 Package reader
A conforming package reader MUST safely process directory and .mcf.zip
packages, enforce Section 21, and provide identical source semantics for both.
24.5 Full implementation
A full implementation satisfies validator, reader, writer, and package-reader requirements. Rendering, compilation, or learner-state support is not required for full format conformance.
25. Canonical conformance materials
The repository's fixtures/valid, fixtures/invalid, schemas, error catalog,
and suite manifest are normative conformance materials. When prose, schema, and
fixture behavior appear to conflict, implementations MUST report the conflict;
the normative specification text controls until the repository is corrected.
Schemas validate data shape. Rules involving file resolution, uniqueness across files, Markdown structure, scoring, security policy, or reference graphs require semantic validation.
26. Out of scope
MCF 1.1 does not define:
- generated HTML, CSS, JavaScript, or compiler output;
- visual themes or interaction design;
- learner accounts or identity;
- stored responses, progress, attempts, or grades;
- classrooms, rosters, gradebooks, or institutional roles;
- deadlines assigned to particular learners or cohorts;
- analytics, recommendations, notifications, or payments;
- certificates or badges;
- synchronization or cloud storage;
- AI tutor behavior;
- code execution or laboratory simulation runtimes; or
- accessibility conformance of a particular rendered application.
MCF carries portable author intent. Implementations control delivery and operations.