Schema
How content files are structured: frontmatter fields and required body headings.
Every content file is Markdown with a YAML frontmatter block delimited by ---.
---
kind: lesson
id: L.00.001.01
# ... more fields ...
---
# Lesson title
## Procedure
...
## Assessment
...
The frontmatter is validated against JSON Schema in schema/. The kind field
selects which schema applies.
Kinds
kind |
File location | Purpose |
|---|---|---|
domain |
curriculum/standards/domains/*/domain.md |
A domain: strands + grade-level objectives. |
scope |
curriculum/k-12/grade-*/*/scope.md |
The year plan for a grade (≈180 days). |
unit |
curriculum/k-12/grade-*/*/units/*/unit.md |
A multi-lesson block. |
lesson |
curriculum/k-12/grade-*/*/units/*/lessons/*.md |
One day of instruction. |
agent |
agents/definitions/agents.yaml |
A curriculum-building agent definition. |
backlog |
agents/backlog/backlog.yaml |
The work backlog (list of items). |
Field reference by kind
lesson
| Field | Type | Required | Notes |
|---|---|---|---|
kind |
string | yes | must be lesson |
id |
string | yes | L.gg.nnn.nn |
title |
string | yes | |
grade |
integer | yes | 0 (K) – 12 |
unit |
string | yes | owning unit ID U.gg.nnn |
sequence_in_unit |
integer | no | position within the unit |
domain |
array | yes | one or more Dxx |
pillar |
array | no | one or more Px |
strand |
array | no | one or more Dxx.Sn |
objectives |
array | yes | one or more standard IDs |
essential_question |
string | no | |
key_vocabulary |
array | no | |
materials |
array | no | standard classroom supplies { name, quantity, notes } |
materials_low_tech |
array | no | no-cost/universal variant (paper, found objects, voice, body) |
materials_enriched |
array | no | lab/device/field-trip variant |
context_variants |
array | no | { context, note } for environment changes (forest vs lab, etc.) |
assets |
array | no | { path, alt, kind, source } — path must resolve to a real file |
duration_minutes |
integer | yes | |
summary |
string | no | |
cross_cutting_lenses |
array | no | from the allowed list |
assessment_type |
array | no | formative/summative/etc. |
status |
string | yes | draft | review | approved |
author |
string | no | |
last_updated |
string | no |
Recommended context_variants contexts: large-group (30+ learners), multi-age,
self-directed (no facilitator), level-grouped (by mastery, not age), and
outdoor-only. See docs/contexts.md.
unit
kind, id (U.gg.nnn), title, grade, domain, pillar, strand,
objectives, essential_questions, big_ideas, duration_weeks,
assessment_plan, status, author, last_updated.
scope
kind, grade, year_title, total_school_days (default 180), summary,
units (array of { unit_id, title, domain, pillar, start_day, end_day, lesson_count }), domain_weighting (map Dxx → days/percent), assessment_plan,
status.
Writing a scope
A grade page renders exactly two pieces of prose: summary as the lede paragraph at
the top of the page, and the body’s ## Year at a glance section as the overview
below the unit timeline. Both are read by parents, teachers, and curious visitors who
want to understand the year, not to audit every standard. Keep them short, distinct,
and non-overlapping.
| Piece | Target | Job |
|---|---|---|
summary |
60–110 words, 3–5 sentences | The page lede and the meta description. What the year is about and what the learner becomes. No unit list, no standard IDs, no enumeration. |
## Year at a glance |
350–650 words | The narrative arc: how the year builds on the prior grade, how the units cluster into two to four movements, and the pillar balance. |
Rules:
- Never recite the standards. Do not walk through objectives one by one, with or
without IDs, and do not string sentences together with “and … and … and”. Objective
text already lives in
curriculum/standards/domains/*/domain.mdand on each unit page’s objectives list. The scope names each unit once, in the form*Unit Title* (U.gg.nnn, Dxx)— both domains for a two-domain unit, as(U.gg.nnn, Dxx + Dyy)— and says what the unit is for. - Do not repeat
summaryin the body. The lede and the overview sit inches apart on the same page; restating one in the other doubles the wall of text for no gain. - Keep the closing pillar paragraph (roughly 80–140 words) — it is the one place the page states how P1–P4 are weighted in the year.
- Do not pad back up later. The year plan,
units,domain_weighting, andassessment_plancarry the detail.npm run validatewarns when a scope summary or body drifts past these targets.
Line-wrap body prose at ~88 characters, as elsewhere in the repository.
domain
kind, id (Dxx), title, pillar, description, rationale, strands
(array of { id, title, description }), grade_objectives (map grade → list of
{ id, text }), cross_cutting_lenses, status.
agent / backlog
See agents/README.md and the machine-readable agents/definitions/agents.yaml.
Required body headings
In addition to valid frontmatter, the Markdown body must include certain headings.
lessonrequires## Procedure,## Assessment,## Facilitator note, and## Connection(case-insensitive,##level), and is strongly encouraged to include## Summary,## Objectives,## Materials,## Preparation,## Differentiation,## Resources, and## Home connection.scoperequires# <Grade> Scope,## How to read this scope, and## Year at a glance.
The validator checks these. Content that fails frontmatter or heading checks will not pass CI.
Voice: learner-first
The ## Procedure is written to the learner (“you”), so a lesson works in a
classroom and for a self-directed learner. Teacher guidance lives in
## Facilitator note. See docs/facilitation.md.
Connection: anchor to real life
Every lesson’s ## Connection (2–3 sentences) ties the concept to everyday life,
written so it survives different lives:
- Concrete before abstract — a real, recognizable example before the abstraction.
- Faithful — the example illustrates the real concept, not a distorted cartoon.
- Varied — offer more than one context (city and farm, sea and mountain) or keep it explicitly adaptable. Life differs everywhere; avoid one default.