Canonical format, version 1. A writer carries more responsibility than a reader: it must
preserve keys it does not understand, keep unknown parts untouched, and stamp the format
envelope on everything it writes.
The parsed course
A reader loads the files into one in-memoryCourse value, then hands it to a
binding resolver.
Building a reader
- Read
project.json. Reject an unknownformat; branch onformatVersion. - Load collections and their
recordFiles, then assets, then lessons and their part files (see Project layout). - Build the
Courseand a resolver. - Render lessons part by part; grade exercises with their
evaluation.
ProjectReader contract, for example,
returns an explicit failure rather than throwing:
- Manifest missing: fails as
unavailable. - A referenced file is malformed JSON: fails as
unavailable. - Manifest with no collections: succeeds with an empty list.
missing
resolution, not a crash.
Building a writer
A creator app reads, edits, and writes back. Two things make writes safe: Write back to the same file. Parsing retains the source path of every entity, so an edit updates the exact file it came from rather than rewriting the whole project.literal
snapshot. Detaching presentation from a record does not copy binary media.
Validate before writing: check that every binding resolves, that required fields are
present, and that referenced records and assets exist. The Studio repo validates its fixture
in CI with pnpm check:example; do the same against your own courses.
Versioning and stability
Every file carriesformat and formatVersion; today "asakiri-course" and 1. Gate on
both, refuse a higher version, and migrate a lower one. See
Versioning and migration.
A writer has three obligations beyond a reader:
1
Stamp the envelope
Write
format and formatVersion on every file you create or rewrite.2
Preserve what you did not parse
Read the existing file, merge your changes over it, and write the result. Unknown keys,
unknown part types, and translations for locales you are not showing must survive the
round trip. Studio never rewrites the body file of a part it could not parse.
3
Write atomically
Write to a temporary file and rename, so a crash cannot leave a half-written record.
- schema-template format and custom-field constraints;
- packaging rules for a distributable course.
Not specified yet
Some things a real learner app needs are intentionally not in the course format, because they are product decisions that have not been made. Building them today means inventing your own model that a future Asakiri spec may not match:- Learner state: progress, completion, and per-item history.
- Review scheduling: any spaced-repetition or practice-ordering rules.
- Packaging and distribution: how a course is bundled and delivered to a learner app.