Course Builder Studio
Instructor-only, reachable from a course's row on the Courses list. An
instructor can manage any course in their tenant, not just ones they
authored - the Studio has no per-course ownership check, only the
tenant-wide can_manage_courses_in() role check.
This covers the structure-authoring side: modules, lessons, block types, and publishing. AI-assisted popovers (draft from a prompt, rephrase a selection, generate a diagram/code/questions) are covered in AI Course Builder; exam authoring is covered in Exams.
Layout
Three panes: a tree on the left (modules and lessons, drag-and-drop reorderable, plus any attached exams), a block editor in the center, and a properties panel on the right (course/module/lesson metadata, attached exams, and the Documents tab).
Block types
A lesson is a sequence of typed blocks, mixed freely:
- Text - a rich-text document (headings, lists, bold/italic). Older lessons may still store a plain string; both render fine.
- Video embed - a URL only, no file upload.
- Attachment - a URL and label, no file upload.
- Image - a real file upload.
- Vocabulary - a reference to a shared glossary term (see Vocabulary) by ID. The lesson always renders that term's current definition, not a frozen copy - editing the term later changes what every lesson referencing it shows.
- Matching - left/right pairs, with a "Check answers" self-check. In the Studio's own preview nothing is persisted, same as before; in the real learner-facing lesson, a member must connect every pair correctly before the lesson can be marked complete (see Learner experience, ADR-064).
- Diagram - a full Excalidraw scene, editable in place.
- Code - syntax-highlighted, with a language picker.
- MCQ / MAQ - inline comprehension-check questions, sharing their data shape with real Exam questions but never contributing to an aggregate score the way an exam does. In the Studio's own preview they're purely local, same as before; in the real learner-facing lesson, a member must answer correctly (graded server-side) before the lesson can be marked complete (see Learner experience, ADR-064).
Moving between the Studio and the AI assistant
When AI features are enabled for your workspace, the sparkle icon at the top right of the Studio's top bar opens that course's AI Assistant chat, and the chat's top bar has a Studio icon that brings you back. Any edit you made in the last moment before clicking away is saved first, so the assistant always sees your latest text.
Publishing
Publishing takes an immutable snapshot of the course's whole tree
(modules, lessons with their block content, and the exams published at
that moment) and points the course at it - that snapshot, not the
working copy, is what a member of a tenant with the "Learners read
published versions" flag on actually sees (see Feature
flags; with the
flag off, publishing still creates a version, but learners keep reading
the working copy directly, exactly as before this feature existed).
docs/ADR.md's ADR-074 has the full design.
The same Publish button (labeled Publish changes once a course is already published and has unpublished edits) opens a dialog with:
- An optional note describing what changed, shown in the version history below.
- The version history - every past version, newest first, the live one marked, each other one with a Restore button (with its own confirmation) that brings that version's modules and lessons back into the working copy exactly - ids preserved, so a learner's progress on a restored lesson still applies once it's published again. Restoring never publishes by itself.
- Discard unpublished changes - the same restore, applied to the current live version, for reverting everything back to what learners already see.
- Unpublish - learners lose access immediately; every version is kept, and republishing always creates a new version (never re-uses an old one), since learners saw the gap.
Publishing still does no content validation - a course with zero
modules and zero lessons can be published, and publishing an
already-published course with nothing changed is refused ("nothing to
publish") rather than creating an identical version. The AI chat's
publish request (propose_publish) works the same way the Delete
confirmations do: it only proposes, on a card the instructor confirms -
nothing is published by the assistant's own tool call.
Preview mode
A toggle in the Studio renders the course as a learner would see it,
with reordering and block-adding disabled while active. This previews
the working copy (what you're currently editing) - if a tenant has
"Learners read published versions"
turned on and this course has unpublished edits, this is not
necessarily what's live for learners right now (the Publishing
dialog's version history says so). The API itself can read the
published snapshot directly
(?view=published on the course/module/lesson routes, manager-only),
but the Studio has no UI for it yet - only the version history's own
note count and the Discard action tell you that something differs,
not a rendered side-by-side view of it.
Documents tab
Part of the properties panel - upload and manage the course's knowledge-base documents, and see each document's ingestion status. Covered in full in Knowledge base & Ask about this course. A separate list nearby shows lesson-content ingestion status (lesson text is indexed too, not just uploaded documents), tracked independently from document status - a lesson only ever shows stale/up to date relative to the course's last published version, not the working copy: editing without publishing never moves it off "up to date."