> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hawkings.education/llms.txt
> Use this file to discover all available pages before exploring further.

# Generate a course from a syllabus

> From a paragraph of text to a fully-structured, ready-to-teach course.

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

<CodeGroup>
  ```ts TypeScript theme={null}
  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...
  ```

  ```php PHP theme={null}
  $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...
  ```
</CodeGroup>

`courses.create()` returns immediately. The course is `status: "draft"`
until you generate or attach a syllabus.

## 2. Generate the syllabus

<CodeGroup>
  ```ts TypeScript theme={null}
  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_..."
  });
  ```

  ```php PHP theme={null}
  $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_...',
  ]);
  ```
</CodeGroup>

Wait for it to finish:

<CodeGroup>
  ```ts TypeScript theme={null}
  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",
  //   ...
  // ]
  ```

  ```php PHP theme={null}
  $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",
  //   ...
  // ]
  ```
</CodeGroup>

A default `Cohort` was created automatically. Lessons live on the
cohort, not on the course — see [Courses vs. Cohorts](/concepts/courses-vs-cohorts).

## 3. Generate reading content

For each lesson, ask the AI to write a long-form HTML reading:

<CodeGroup>
  ```ts TypeScript theme={null}
  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") },
  );
  ```

  ```php PHP theme={null}
  $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,
          ),
      ],
  );
  ```
</CodeGroup>

If you'd rather generate everything at once instead of per-lesson:

<CodeGroup>
  ```ts TypeScript theme={null}
  await hk.lessonContents.generate({ cohort_id: cohort.id });
  ```

  ```php PHP theme={null}
  $hk->lessonContents->generate(['cohort_id' => $cohort->id]);
  ```
</CodeGroup>

That's a single call, fans out internally, and is what we recommend in
production.

## 4. Generate activities

<CodeGroup>
  ```ts TypeScript theme={null}
  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") },
  );
  ```

  ```php PHP theme={null}
  $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,
          ),
      ],
  );
  ```
</CodeGroup>

Now every lesson has 5 activities.

## 5. Add an assignment to the final lesson

<CodeGroup>
  ```ts TypeScript theme={null}
  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 },
    },
  });
  ```

  ```php PHP theme={null}
  $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],
      ],
  ]);
  ```
</CodeGroup>

## 6. Verify

<CodeGroup>
  ```ts TypeScript theme={null}
  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 ?? "—"}`);
  }
  ```

  ```php PHP theme={null}
  $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";
  }
  ```
</CodeGroup>

You're done. Enrol students with `cohorts.create({ student_emails })`,
or [export to SCORM](/guides/export-to-scorm) for an external LMS.

## Same thing, in one go

For prototypes and demos:

<CodeGroup>
  ```ts TypeScript theme={null}
  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") },
  );
  ```

  ```php PHP theme={null}
  $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,
          ),
      ],
  );
  ```
</CodeGroup>

## 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

<CardGroup cols={2}>
  <Card title="Build an AI tutor" icon="comments" href="/guides/build-an-ai-tutor">
    Add a per-lesson tutor chat.
  </Card>

  <Card title="Export to SCORM" icon="box-archive" href="/guides/export-to-scorm">
    Hand the course to any LMS.
  </Card>

  <Card title="Sync students from your LMS" icon="users" href="/guides/sync-students-from-your-lms">
    Bring your existing roster.
  </Card>

  <Card title="Grade an open-ended answer" icon="square-check" href="/guides/grade-an-open-ended-answer">
    Wire AI grading + human review.
  </Card>
</CardGroup>
