Skip to main content
This is the canonical Hawkings workflow. You hand us a brief; we hand you back a course with units, lessons, learning objectives, reading material, and activities. End-to-end it takes ~3 minutes of compute. The code below shows what to call and how to pace it.

What you’ll build

By the end of this guide you’ll have:
  • A Course with a generated syllabus.
  • A Cohort with all lessons materialised.
  • AI-generated reading content for each lesson.
  • A mix of activities (quizzes, flashcards, explainers) for each lesson.
  • An assignment with an AI rubric on the final lesson.

1. Create the course

import Hawkings from "@hawkings/sdk";

const hk = new Hawkings();

const course = await hk.courses.create({
  name: "Intro to Special Relativity",
  language: "en",
  hours: 12,                          // target total student hours
  description: "An undergraduate intro course covering frames, " +
               "the postulates, time dilation, length contraction, " +
               "and mass-energy equivalence.",
});

console.log(course.id);   // crs_01HX9...
$hk = new \Hawkings\Client();

$course = $hk->courses->create([
    'name' => 'Intro to Special Relativity',
    'language' => 'en',
    'hours' => 12,                       // target total student hours
    'description' => 'An undergraduate intro course covering frames, '
                   . 'the postulates, time dilation, length contraction, '
                   . 'and mass-energy equivalence.',
]);

echo $course->id;     // crs_01HX9...
courses.create() returns immediately. The course is status: "draft" until you generate or attach a syllabus.

2. Generate the syllabus

await hk.courses.generateSyllabus(course.id, {
  brief: course.description!,
  audience: "third-year physics undergrads",
  hours: 12,
  // Optional: pin a research artefact to ground the generation
  // research_id: "res_..."
});
$hk->courses->generateSyllabus($course->id, [
    'brief' => $course->description,
    'audience' => 'third-year physics undergrads',
    'hours' => 12,
    // Optional: pin a research artefact to ground the generation
    // 'research_id' => 'res_...',
]);
Wait for it to finish:
const ready = await hk.poll(
  () => hk.courses.retrieve(course.id, { expand: ["cohorts.lessons"] }),
  { until: c => c.status === "ready", interval_ms: 2000 },
);

console.log(ready.cohorts[0].lessons.map(l => l.name));
// [
//   "Reference frames and Galilean relativity",
//   "The postulates of special relativity",
//   "Time dilation",
//   "Length contraction",
//   ...
// ]
$ready = $hk->poll(
    fn () => $hk->courses->retrieve($course->id, ['expand' => ['cohorts.lessons']]),
    [
        'until' => fn ($c) => $c->status === 'ready',
        'interval_ms' => 2000,
    ],
);

print_r(array_map(fn ($l) => $l->name, $ready->cohorts[0]->lessons));
// [
//   "Reference frames and Galilean relativity",
//   "The postulates of special relativity",
//   "Time dilation",
//   "Length contraction",
//   ...
// ]
A default Cohort was created automatically. Lessons live on the cohort, not on the course — see Courses vs. Cohorts.

3. Generate reading content

For each lesson, ask the AI to write a long-form HTML reading:
const cohort = ready.cohorts[0];

await Promise.all(
  cohort.lessons.map(lesson =>
    hk.lessonContents.generate({ lesson_id: lesson.id }),
  ),
);

await hk.poll(
  () => hk.cohorts.lessonStatuses(cohort.id),
  { until: rows => rows.every(r => r.content_status === "ready") },
);
$cohort = $ready->cohorts[0];

foreach ($cohort->lessons as $lesson) {
    $hk->lessonContents->generate(['lesson_id' => $lesson->id]);
}

$hk->poll(
    fn () => $hk->cohorts->lessonStatuses($cohort->id),
    [
        'until' => fn ($rows) => array_reduce(
            $rows,
            fn ($acc, $r) => $acc && $r->content_status === 'ready',
            true,
        ),
    ],
);
If you’d rather generate everything at once instead of per-lesson:
await hk.lessonContents.generate({ cohort_id: cohort.id });
$hk->lessonContents->generate(['cohort_id' => $cohort->id]);
That’s a single call, fans out internally, and is what we recommend in production.

4. Generate activities

await hk.activities.generate({
  cohort_id: cohort.id,
  count: 5,
  types: ["explain", "quiz", "flashcard"],
});

await hk.poll(
  () => hk.cohorts.lessonStatuses(cohort.id),
  { until: rows => rows.every(r => r.activities_status === "ready") },
);
$hk->activities->generate([
    'cohort_id' => $cohort->id,
    'count' => 5,
    'types' => ['explain', 'quiz', 'flashcard'],
]);

$hk->poll(
    fn () => $hk->cohorts->lessonStatuses($cohort->id),
    [
        'until' => fn ($rows) => array_reduce(
            $rows,
            fn ($acc, $r) => $acc && $r->activities_status === 'ready',
            true,
        ),
    ],
);
Now every lesson has 5 activities.

5. Add an assignment to the final lesson

const lessons = (await hk.lessons.list({ cohort_id: cohort.id })).data;
const finalLesson = lessons.at(-1)!;

await hk.assignments.create({
  lesson_id: finalLesson.id,
  type: "essay",
  title: "Explain mass-energy equivalence in your own words",
  rubric: {
    criteria: [
      { name: "clarity", weight: 0.4 },
      { name: "physics accuracy", weight: 0.4 },
      { name: "use of sources", weight: 0.2 },
    ],
    scale: { min: 0, max: 10 },
  },
});
$lessons = $hk->lessons->list(['cohort_id' => $cohort->id])->data;
$finalLesson = end($lessons);

$hk->assignments->create([
    'lesson_id' => $finalLesson->id,
    'type' => 'essay',
    'title' => 'Explain mass-energy equivalence in your own words',
    'rubric' => [
        'criteria' => [
            ['name' => 'clarity', 'weight' => 0.4],
            ['name' => 'physics accuracy', 'weight' => 0.4],
            ['name' => 'use of sources', 'weight' => 0.2],
        ],
        'scale' => ['min' => 0, 'max' => 10],
    ],
]);

6. Verify

const final = await hk.courses.retrieve(course.id, {
  expand: [
    "cohorts.lessons.activities",
    "cohorts.lessons.content",
    "cohorts.lessons.assignment",
  ],
});

for (const lesson of final.cohorts[0].lessons) {
  console.log(lesson.name);
  console.log(`  content: ${lesson.content?.id ?? "—"}`);
  console.log(`  activities: ${lesson.activities.length}`);
  console.log(`  assignment: ${lesson.assignment?.title ?? "—"}`);
}
$final = $hk->courses->retrieve($course->id, [
    'expand' => [
        'cohorts.lessons.activities',
        'cohorts.lessons.content',
        'cohorts.lessons.assignment',
    ],
]);

foreach ($final->cohorts[0]->lessons as $lesson) {
    echo $lesson->name . "\n";
    echo '  content: ' . ($lesson->content->id ?? '—') . "\n";
    echo '  activities: ' . count($lesson->activities) . "\n";
    echo '  assignment: ' . ($lesson->assignment->title ?? '—') . "\n";
}
You’re done. Enrol students with cohorts.create({ student_emails }), or export to SCORM for an external LMS.

Same thing, in one go

For prototypes and demos:
const course = await hk.courses.create({
  name: "Intro to Special Relativity",
  language: "en",
  hours: 12,
});

await hk.courses.generateSyllabus(course.id, { brief: "...", hours: 12 });

const cohort = (await hk.courses.retrieve(course.id, { expand: ["cohorts"] }))
  .cohorts[0];

await hk.lessonContents.generate({ cohort_id: cohort.id });
await hk.activities.generate({ cohort_id: cohort.id, count: 5 });

await hk.poll(
  () => hk.cohorts.lessonStatuses(cohort.id),
  { until: rows => rows.every(r => r.content_status === "ready" && r.activities_status === "ready") },
);
$course = $hk->courses->create([
    'name' => 'Intro to Special Relativity',
    'language' => 'en',
    'hours' => 12,
]);

$hk->courses->generateSyllabus($course->id, ['brief' => '...', 'hours' => 12]);

$cohort = $hk->courses->retrieve($course->id, ['expand' => ['cohorts']])
    ->cohorts[0];

$hk->lessonContents->generate(['cohort_id' => $cohort->id]);
$hk->activities->generate(['cohort_id' => $cohort->id, 'count' => 5]);

$hk->poll(
    fn () => $hk->cohorts->lessonStatuses($cohort->id),
    [
        'until' => fn ($rows) => array_reduce(
            $rows,
            fn ($acc, $r) => $acc && $r->content_status === 'ready' && $r->activities_status === 'ready',
            true,
        ),
    ],
);

Cost & runtime

Roughly: a 12-hour course → ~10 lessons → ~$2.50 in AI costs and ~3 minutes wall-clock on shared infrastructure. See your dashboard for exact unit prices.

What’s next

Build an AI tutor

Add a per-lesson tutor chat.

Export to SCORM

Hand the course to any LMS.

Sync students from your LMS

Bring your existing roster.

Grade an open-ended answer

Wire AI grading + human review.