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

# Assignments & Submissions

> Gradable artefacts: rubrics, due dates, AI grading, human-in-the-loop.

An **Assignment** is something you grade. A **Submission** is a single
student's response to it. Submissions hold both the response and the
grade, because in our experience the two need to live next to each
other: AI grading, human grading, regrades, comments, files.

```
Assignment "Essay: explain Lorentz invariance"
  ├─ Submission (student A)  → grade 8.5 (AI), 9.0 (human override)
  ├─ Submission (student B)  → grade 6.5 (AI)
  └─ Submission (student C)  → grade 0   (not submitted yet)
```

## Creating an assignment

<CodeGroup>
  ```ts TypeScript theme={null}
  await hk.assignments.create({
    lesson_id: "lsn_123",
    type: "essay",
    title: "Explain Lorentz invariance in your own words",
    due_at: "2026-06-01T23:59:00Z",
    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}
  $hk->assignments->create([
      'lesson_id' => 'lsn_123',
      'type' => 'essay',
      'title' => 'Explain Lorentz invariance in your own words',
      'due_at' => '2026-06-01T23:59:00Z',
      '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>

You can also configure the AI grader explicitly:

<CodeGroup>
  ```ts TypeScript theme={null}
  await hk.assignments.configure(assignmentId, {
    ai_evaluator: { enabled: true, model: "claude-sonnet-4-6" },
    human_review: "required" | "optional" | "off",
  });
  ```

  ```php PHP theme={null}
  $hk->assignments->configure($assignmentId, [
      'ai_evaluator' => ['enabled' => true, 'model' => 'claude-sonnet-4-6'],
      'human_review' => 'required',     // 'required' | 'optional' | 'off'
  ]);
  ```
</CodeGroup>

## Submitting

A student submits with `submissions.create()`:

<CodeGroup>
  ```ts TypeScript theme={null}
  await hk.submissions.create({
    assignment_id: "asg_123",
    student_id: "usr_123",
    content: { text: "Lorentz invariance means that the laws of physics ..." },
  });
  ```

  ```php PHP theme={null}
  $hk->submissions->create([
      'assignment_id' => 'asg_123',
      'student_id' => 'usr_123',
      'content' => ['text' => 'Lorentz invariance means that the laws of physics ...'],
  ]);
  ```
</CodeGroup>

You can attach files via [multipart upload](/api-reference/submissions/create).

## Grading

Three flavours, in this order of trust:

### AI grading

<CodeGroup>
  ```ts TypeScript theme={null}
  await hk.submissions.gradeWithAi(submissionId);

  const sub = await hk.submissions.retrieve(submissionId);
  // sub.grade_ai             → 8.5
  // sub.grading_rationale    → markdown explanation, criterion-by-criterion
  ```

  ```php PHP theme={null}
  $hk->submissions->gradeWithAi($submissionId);

  $sub = $hk->submissions->retrieve($submissionId);
  // $sub->grade_ai             → 8.5
  // $sub->grading_rationale    → markdown explanation, criterion-by-criterion
  ```
</CodeGroup>

### Human override

<CodeGroup>
  ```ts TypeScript theme={null}
  await hk.submissions.update(submissionId, {
    grade_manual: 9.0,
    grader_comments: "Strong on conceptual clarity; missed the bit on simultaneity.",
  });
  ```

  ```php PHP theme={null}
  $hk->submissions->update($submissionId, [
      'grade_manual' => 9.0,
      'grader_comments' => 'Strong on conceptual clarity; missed the bit on simultaneity.',
  ]);
  ```
</CodeGroup>

The human grade always wins where present; AI grades stay attached for
audit.

### Bulk grading

When you want to grade an entire assignment at once (e.g. reading the
whole class' submissions overnight):

<CodeGroup>
  ```ts TypeScript theme={null}
  await hk.submissions.bulk({
    assignment_id: "asg_123",
    rows: classSubmissions.map(s => ({
      submission_id: s.id,
      grade_manual: s.draftScore,
      grader_comments: s.feedback,
    })),
  });
  ```

  ```php PHP theme={null}
  $hk->submissions->bulk([
      'assignment_id' => 'asg_123',
      'rows' => array_map(fn ($s) => [
          'submission_id' => $s->id,
          'grade_manual' => $s->draftScore,
          'grader_comments' => $s->feedback,
      ], $classSubmissions),
  ]);
  ```
</CodeGroup>

## Human-in-the-loop pattern

A common pattern: AI proposes, human decides.

<CodeGroup>
  ```ts TypeScript theme={null}
  // 1. AI grades all of them
  for (const sub of submissions) {
    await hk.submissions.gradeWithAi(sub.id);
  }

  // 2. Show teacher the AI grade + rationale; teacher confirms or edits
  //    in your UI

  // 3. Save with a manual grade (optional) and mark reviewed
  await hk.submissions.update(submissionId, {
    grade_manual: teacherDecision.score,
    grader_comments: teacherDecision.notes,
    human_review_status: "reviewed",
  });
  ```

  ```php PHP theme={null}
  // 1. AI grades all of them
  foreach ($submissions as $sub) {
      $hk->submissions->gradeWithAi($sub->id);
  }

  // 2. Show teacher the AI grade + rationale; teacher confirms or edits
  //    in your UI

  // 3. Save with a manual grade (optional) and mark reviewed
  $hk->submissions->update($submissionId, [
      'grade_manual' => $teacherDecision->score,
      'grader_comments' => $teacherDecision->notes,
      'human_review_status' => 'reviewed',
  ]);
  ```
</CodeGroup>

This is the workflow we recommend for everything other than purely
formative quizzes. It's fast, it's auditable, and it keeps a teacher
on the hook for the final mark.

## What `Submission` includes

```ts theme={null}
type Submission = {
  id: string;
  assignment_id: string;
  student_id: string;
  content: SubmissionContent;
  files: File[];

  grade_ai: number | null;
  grade_manual: number | null;
  grading_rationale: string | null;     // markdown, AI-generated
  grader_comments: string | null;       // markdown, human-written

  human_review_status: "pending" | "reviewed" | "off";
  ai_status: "pending" | "ready" | "error";
  evaluated_at: string | null;          // ISO 8601
  uploaded_at: string;                  // ISO 8601
};
```
