{
"id": "at.kotoba.lesson.pack",
"defs": {
"item": {
"type": "object",
"required": [
"glyph",
"romaji",
"type"
],
"properties": {
"row": {
"type": "string",
"description": "Gojuon row label, single kana only."
},
"meta": {
"type": "unknown",
"description": "Item-level open extension; UI ignores, round-trips."
},
"type": {
"type": "string",
"description": "Open. hiragana | katakana | kanji | word."
},
"gloss": {
"type": "string",
"description": "English meaning; recommended for words/kanji."
},
"glyph": {
"type": "string"
},
"romaji": {
"type": "string",
"description": "Expected reading; lowercase Hepburn, exact case-insensitive match."
},
"weight": {
"type": "integer",
"description": "Optional author priority override. Fixed-point ×10000 (e.g. 1.8 -> 18000); lexicons have no float type. App scales at the record edge (see README)."
},
"confusableWith": {
"type": "array",
"items": {
"type": "string"
},
"description": "ROMAJI (not glyphs) of same-script confusers; cold-start distractor seed."
}
},
"description": "A card. Core: glyph/romaji/type. `glyph` is 1+ chars (single kana, word, or kanji)."
},
"main": {
"key": "tid",
"type": "record",
"record": {
"type": "object",
"required": [
"title",
"items"
],
"properties": {
"meta": {
"type": "unknown",
"description": "Pack-level open extension; UI ignores, round-trips."
},
"items": {
"type": "array",
"items": {
"ref": "#item",
"type": "ref"
}
},
"phase": {
"type": "string",
"description": "Open. kana | vocab | grammar."
},
"title": {
"type": "string"
},
"script": {
"type": "array",
"items": {
"type": "string"
},
"description": "Declared scripts; drives chips + Focus. Derived from item types if omitted."
},
"defaults": {
"ref": "#defaults",
"type": "ref"
},
"createdAt": {
"type": "string",
"description": "ISO 8601. NOTE: the app currently stamps a date-only string (YYYY-MM-DD), not a datetime — left unformatted here pending reconciliation (see README)."
},
"rationale": {
"type": "string"
}
}
},
"description": "Lesson content the app drills. Append-only stack; latest = active. Free-form by design: a known core the UI reads + open `meta`/`defaults` round-tripped untouched (SPEC §3.1a). This record body IS the upload interchange shape (lessons/pack.schema.json)."
},
"defaults": {
"type": "object",
"properties": {
"tapToTypeBox": {
"type": "integer",
"maximum": 5,
"minimum": 1,
"description": "Leitner box at/above which a glyph may graduate tap -> type."
},
"katakanaMultiplier": {
"type": "integer",
"description": "Queue weight multiplier for katakana. Fixed-point ×10000 (e.g. 1.5 -> 15000); no float type."
}
},
"description": "Pack-level drill defaults (SPEC §4). Open additional keys round-trip via the pack `meta`."
}
},
"$type": "com.atproto.lexicon.schema",
"lexicon": 1
}