Skip to content

Releases: lc-json/specification

LC-JSON 1.0-rc.3

13 Jun 17:05
Immutable release. Only release title and notes can be modified.
v1.0-rc.3
306b974

Choose a tag to compare

LC-JSON 1.0-rc.3 Pre-release
Pre-release

LC-JSON (Learning Content JSON) is an open, Apache-2.0 format for structured learning content — full courses and standalone question sets — that any authoring tool, LMS, or validator can implement to read and write.

LC-JSON v1.0-rc.3 is the second publicly announced release candidate, and the last planned candidate before the 1.0 final release (targeted 2026-06-30). It is backwards-compatible with rc.2: every rc.2-valid document remains valid under rc.3. The earlier /1.0-rc.1/ and /1.0-rc.2/ schema sets stay served and frozen at their own URLs; rc.3 publishes at /1.0-rc.3/.

If you adopted rc.2, the move to rc.3 is low-cost: re-point your $schema URLs to /1.0-rc.3/ when convenient (or stay on rc.2 — it remains valid forever). The planned transition from rc.3 to 1.0 final is a pure URL rebase with no wire-format change.

Comment window: feedback is welcome through 2026-06-27. 1.0 final is planned for 2026-06-30 as a URL rebase of rc.3 — unless substantive feedback arrives that warrants a wire change, in which case it lands in a further candidate first. That date was announced with rc.2 on 2026-05-30 and has not moved.

What's new since rc.2

A localization and language model — LOCALIZATION.md. The specification now states explicitly how it represents language, separating three things that the single word "language" had been conflating:

  • language — the document's one delivery language (LC-JSON 1.x is single-language-per-document; translations are separate documents, not localized field bundles).
  • lang / dir on HTMLlanguage of parts: spans in a different language, for correct rendering and pronunciation (WCAG 3.1.2). Not translation.
  • supportLanguage — an optional pedagogical layer naming the learner's first language, for second-language teaching content.

Language tags are BCP 47: a bare ISO 639-1 code (en, es) is the common case, and region/script subtags (pt-BR, zh-Hant) are permitted — a consumer may act on only the primary subtag if it has no region-specific behavior.

The document also includes a short, candid note for implementers on screen-reader pronunciation: emitting lang is necessary but not sufficient for a span to be pronounced correctly — automatic language switching and installed voices vary across screen readers and live in the user's environment, outside the format's control. The format's job is to carry the affordance faithfully; lang is the floor, not optional.

A bigger conformance corpus. 64 cases (up from 38): a valid + invalid set for every implemented question type, a grading-combination matrix, referential-integrity cases, and document-wide globalId-uniqueness — now made explicit and enforced.

A clearer accessibility bargain. Two layers, stated plainly. Base conformance is preservation only: never strip alt, captions, <track>, lang/dir, or language metadata on read/write — and a small producer is never required to author them. The heavier bar — alt on every image, captions and transcripts on instructional speech-bearing video, transcripts on audio — is bound by the opt-in Accessibility Profile, for products (typically institutional, or with accessibility commitments) that claim it. Accessibility information is never silently dropped; the demanding part is opt-in.

One schema change (the reason rc.3 exists as a new immutable publication rather than an edit to rc.2): the prototype-era allowedFillerWords and prohibitExtraWordsBetweenChunks fields are removed from sentence-transformation.schema.json. They were optional and unused; documents carrying those optional fields still validate (consumers may ignore them, and producers should stop emitting them). Because a published /1.0-rc.2/ URL is immutable, this correction lands at /1.0-rc.3/.

Stable vs. still-moving

Stable — build against it now: the wire format, all 23 schemas, the two artifact types, the 12 implemented question types, the HTML safety profile, the accessibility profile, and the localization model. Schema URLs at /1.0-rc.3/ are immutable.

Try it

git clone https://github.com/lc-json/specification
cd specification
python tools/run_corpus.py        # 64/64 fixtures behave as expected
python tools/validate_course.py --course-path examples/course-minimal.json --strict

Feedback and issues: https://github.com/lc-json/specification/issues (bug-report and spec-change-proposal templates are provided).

LC-JSON 1.0-rc.2 — first announced release candidate

30 May 16:17
Immutable release. Only release title and notes can be modified.
v1.0-rc.2
6d92758

Choose a tag to compare

LC-JSON v1.0-rc.2

Prepared: 2026-05-30 · Status: Public release candidate (pre-release), the first formally announced prerelease
Specification: https://lc-json.org · Repository: https://github.com/lc-json/specification
Schemas: https://lc-json.org/1.0-rc.2/ · License: Apache 2.0

This is the first publicly announced release candidate of LC-JSON (Learning Content JSON), an open specification for portable learning content, built around a simple premise:

Educational content should remain readable, structured, reusable, and under the control of the people who create it.

LC-JSON defines a JSON interchange format for courses, units, lessons, instructional content, exercises, quizzes, questions, learning objectives, and accessibility metadata — designed to move cleanly between authoring tools, learning-management systems, and delivery platforms rather than being locked inside any one of them.

LC-JSON is a content-layer format — complementary to, not competing with, the established LMS interop standards: LTI (tool launch and grade passback), OneRoster (rosters), xAPI (activity records), SCORM (runtime delivery). The RATIONALE.md document in the specification covers the full landscape and what LC-JSON is not.


What LC-JSON looks like

A minimal QuestionSet — one of the two artifact types (the other is a hierarchical Course):

{
  "$schema": "https://lc-json.org/1.0-rc.2/question-set.schema.json",
  "documentType": "questionSet",
  "specVersion": "1.0",
  "title": "Geography — Capitals",
  "language": "en",
  "questions": [
    {
      "type": "shortAnswer",
      "globalId": "550e8400-e29b-41d4-a716-446655440001",
      "prompt": "What is the capital of France?",
      "acceptedAnswers": ["Paris"],
      "points": 1.0,
      "hint": "The city sits on the River Seine in northern France and has been the nation's political and cultural center for over a thousand years.",
      "feedback": {
        "correct": "Correct — Paris. Founded as the Roman town of Lutetia on the Île de la Cité, it has been France's capital since the late 10th century and is today the country's largest city and its cultural and economic heart.",
        "incorrect": "Not quite — the answer is Paris, home to the Eiffel Tower, the Louvre, and Notre-Dame. As the line from the film Sabrina goes, 'Paris is always a good idea.'"
      }
    }
  ]
}

The hint and feedback blocks are optional — shown here to illustrate what a fully-authored question carries. Omitted optional fields fall back to sensible defaults: caseSensitivefalse (so Paris, paris, and PARIS all match), and difficulty5.0. Empty-optional fields like title and tags are simply left out rather than written as "" or [] — keeping documents legible and diffs clean.

shortAnswer is used here deliberately: it is a real-content type whose prompt legitimately is the question, so a single short headline reads cleanly. For fuller worked documents — a complete course, unit, lesson, and the exercise/quiz item shapes — see the spec's examples/ tree: course-minimal.json, unit-minimal.json, lesson-minimal.json, 11-exercise-item.json, 12a-graded-quiz-item.json, 12b-ungraded-quiz-item.json, and sample-course-with-questions.json at https://github.com/lc-json/specification/tree/main/examples.

A Course wraps these same question shapes inside exercise/quiz items, lessons, and units — identical document envelope, hierarchical body.


Changes from the internal rc.1 candidate

  • prompt: minLength 10; non-authoritative for the eight symbolic question types.
    • prompt stays required on every question. An empty string "" is valid.
    • For the four real-content types (true/false, multiple choice, short answer, essay) prompt is the question and remains authoritative; the reference validator flags an empty prompt on these as an ERROR.
    • For the eight symbolic types (gap-fill family, sentence transformation, matching, ordering, placement) the structured fields carry the question's meaning; prompt MAY be empty or MAY carry a brief producer-derived readable summary. Consumers MUST NOT rely on a symbolic prompt's content for scoring, rendering, equality, or deduplication.
  • Reserved/unknown-type preservation language. NORMATIVE.md §6.2 and §6.4 now require preservation of every member, value, and nested structure across read/write cycles, replacing the earlier "verbatim" / "byte-equivalent" wording. Key order within JSON objects is producer-discretion per RFC 8259 §4 (SHOULD for authoring ergonomics, not MUST for consumers).
  • TrueFalseQuestion correctAnswer import normalization. Explicitly labelled in question-types-reference.md as a pre-1.0 lenient migration affordance, not conforming behavior. The schema requires a JSON boolean; conforming producers MUST emit a JSON boolean; conforming consumers in strict mode MUST reject non-boolean values per §5.1.

Backward compatibility: every document valid under the rc.1 schemas remains valid under rc.2. The prompt change is a non-breaking widening (minLength: 1 → 0 only relaxes the constraint; object shape unchanged). The preservation-language and TF-normalization changes tighten normative-prose precision; no schema changes, no wire-format changes.


What's in this release candidate

  • Two artifact types: Course (course → units → lessons → items) and QuestionSet (flat list of questions)
  • Five item types: content, exercise, quiz, contentsequence, signpost
  • 12 question types with full per-type schemas — gap-fill, multiple choice, true/false, the cloze family, short answer, essay, matching, ordering, placement, sentence transformation; 7 further types reserved for a future minor version
  • Learning objectives, metadata, and portable identifiers throughout the hierarchy
  • Accessibility metadata preservation built into base conformance
  • 23 JSON Schemas (Draft 7), a conformance test corpus, a reference validator, and worked examples

Try it

Every document declares its schema by URL, so any JSON Schema (Draft 7) validator works:

pip install jsonschema
python tools/validate_course.py --course-path your-document.json

A document is conforming LC-JSON if it validates against the published schemas at its declared $schema URL and satisfies the producer/consumer requirements in NORMATIVE.md. A 38-fixture conformance corpus (13 valid, 25 invalid) plus the reference validator define the bright line.


What's stable, what may still change

Stable — safe to build against:

  • The document envelope ($schema, documentType, specVersion) and flat-root shape
  • The two artifact types and five item types
  • The 12 question-type shapes and their canonical camelCase discriminators
  • The /1.0-rc.2/ schema URLs — immutable for the life of the specification

May still be refined before v1.0 final (target: 2026-06-30):

  • Additional conformance fixtures and validation-tooling coverage
  • Accessibility-profile deepening
  • Minor cleanup of optional fields
  • Documentation clarifications

No breaking changes to the wire format are expected. The /1.0/ URL space is reserved for the final release and will be a deliberate re-publication — a document pinned to /1.0-rc.2/ continues to validate against rc.2 indefinitely. The earlier internal /1.0-rc.1/ schema set remains served and frozen but was never publicly announced.


Areas still under discussion

Deferred to keep the foundational interchange model stable first: accessibility conformance profiles, packaging and distribution conventions, interactive-activity extensions, analytics and feedback metadata, and rich-media embedding conventions.

Two prompt-specific items are explicitly deferred, with no change to the rc.2 contract beyond minLength: 0:

  • Future treatment of prompt for symbolic types — whether a later version makes it optional/omittable rather than required-with-empty — left for post-1.0 review once there is real-world implementation experience.
  • prompt rules for the 7 reserved question types — deferred to v1.1, when those types are implemented and gain per-type schemas. Under rc.2 an empty prompt on a reserved type is permitted (no domain rule fires).

A separate design question — surfaced during the rc.2 cycle but not changed in this release — concerns grading semantics for unsupported question types:

  • Grading semantics for unsupported question types. §6.2 currently keeps an unsupported question's possible points in the item's total while setting earned points to 0 — the item maximum is not silently reduced. This preserves grade comparability across consumers but means a learner whose consumer cannot render a question has no path to those points (and the item percentage absorbs the gap). Open question for future versions: should consumers continue to leave unsupported items quietly non-performing — possibly under-counting against the author/instructor's grading intent — or should they apply maximum fairness to learners by preemptively setting the unsupported question's possible points to 0? Feedback from implementers and instructional designers welcome via issues on the spec repository.

Two further questions surfaced during the rc.2 review and are explicitly deferred:

  • Strict RFC 4122 UUID validation. The schema regex currently checks UUID shape only (8-4-4-4-12 hex), not RFC 4122 version or variant bits. The prose was aligned in rc.2 to reflect shape-only enforcement ("RFC 4122 UUID, any version; shape-only vali...
Read more