What a cohort is.
One cohort per course.
Every course owns exactly one cohort. The cohort is created automatically the moment the course is created (the wizard does this in a single transaction; see 02 / Create a course with the wizard). A course never has zero cohorts; a cohort never belongs to two courses.
This is the most important rule in this whole guide because it shapes every other surface:
- To run two sections of the same course, you clone the course — each clone gets its own cohort.
- To move a student between sections, you remove them from one cohort and add them to the other.
- To archive a class, you archive the course; the cohort goes with it.
Enrolled vs pending.
Two kinds of people live in a cohort:
Enrolled
A user with a real Studio account who has been added to the cohort. They appear in the roster with their name (if set) and email. Database-wise they have a row in the cohort_memberships table linking their users.id to the cohort.
Pending
An email that has been pre-authorized for the cohort but has not signed in yet. They appear in the roster with a yellow Pending sign-up chip and the note “Will be added on first sign-in.” Database-wise they have a row in the allowed_emails table with the cohort’s ID in the initialCohortId column.
Pending students are automatically promoted to enrolled the first time they sign in: Auth.js consumes the whitelist row, creates a real users entry, and the cohort-membership row is inserted in the same transaction. From the teacher’s point of view, the pending row simply changes from yellow to white.
Why both
Most students don’t have Studio accounts when you first add them — they’re just emails on a registrar export. The pending mechanism lets you set up the entire roster (and send invite emails — see 06 / Send invite emails) before anyone has signed in. As students sign in, they automatically slot into the right cohort with the right role.
Students, teachers, TAs.
Each membership has a roleInCohort field. Two values: student (default) or teacher. Teachers in a cohort have read-access to other students’ progress reports and can post per-student comments. Use the teacher role for TAs, co-instructors, or grad assistants.
Note that roleInCohort is independent of the user’s platform-level role (the role column on users, set by an admin: admin / dev / teacher / student / user). A platform student can be a teacher in a particular cohort if you assign them that way; the cohort role wins inside the cohort context.
Draft, active, archived.
Cohorts mirror their course’s lifecycle. The default status is draft on creation. Publishing the course doesn’t flip the cohort to active automatically — it’s a separate field, mostly informational. Use it as a small tag visible in the dashboard:
draft— pre-launch. You’re still building the roster and curriculum.active— class is in session. Students are working through lessons.archived— class has ended. New enrollments and edits should stop.
Archived cohorts can’t be edited from the cohort panel. Active and draft both allow full editing.
The cohort panel.
You manage everything cohort-related from one panel: the Cohort block on the course detail page at /teacher/courses. Click any course in the sidebar; the cohort block sits below the lessons block. It shows:
- A header row: count, breakdown (X enrolled · Y pending sign-up), and three buttons — Send invites (N), Import CSV, + Add student.
- The roster as a vertical list. Enrolled members render with name + email + role chip; pending members render with a mail-icon avatar + yellow
Pending sign-upchip + per-row Send and Trash icons.
If a course doesn’t have a cohort yet (rare — only happens for very old courses created before the 1:1 model), the panel auto-creates one the first time you open it. You don’t need to ask an admin.
Add students, send invites.
The two next pages cover the workflows you’ll use most:
- 05 / Add students — single email or CSV bulk import.
- 06 / Send invite emails — bulk magic-link invitations and the cooldown.