Skip to main content
Vendor skill for Use case 05: Training. Skill ID: vendor-scorm-course-builder Use when a Partner Enablement lead, Partner Manager, or Channel Ops user wants to build a partner training course end to end with AI: author the content from the vendor’s own knowledge sources (docs, Notion, Confluence, Drive, website), apply the vendor’s branding, package it as SCORM, and publish it to Introw over MCP - with a certificate, due date, passing score, and auto-enrollment - or update an existing course’s settings or replace its package in place. Trigger phrases include “build a course for our partners”, “create a partner training course”, “make a SCORM course”, “turn these docs into a course”, “publish this course to Introw”, “update the course content”, “replace the SCORM package”. Built for: Partner Enablement Manager · Partner Program Manager · Channel Ops Workflow: Topic + the vendor’s own knowledge sources → outline (confirmed) → branded, visual, self-contained HTML course → SCORM 1.2 zip → upload via create_scorm_upload (or a hosted https URL) → upsert_course over MCP → verify live with list_courses → iterate with in-place package replacement
SKILL.md
---
name: vendor-scorm-course-builder
description: Use when a Partner Enablement lead, Partner Manager, or Channel Ops user wants to build a partner training course end to end with AI - author the content from the vendor's own knowledge sources (docs, Notion, Confluence, Drive, website), apply the vendor's branding, package it as SCORM, and publish it to Introw over MCP for partners to take, with a certificate, due date, passing score, and auto-enrollment - or update an existing course's settings or replace its package in place. Trigger phrases include "build a course for our partners", "create a partner training course", "make a SCORM course", "turn these docs into a course", "publish this course to Introw", "update the course content", "replace the SCORM package".
---

# Agentic SCORM Course Builder (Vendor)

**Audience**: Vendor, **claude.ai Introw** MCP.
**Use case**: 05, Training.

## When to use this skill

Use when the user wants to create partner training in Introw without authoring inside Introw: build the course content here (from their knowledge sources, in their branding), produce a SCORM package, and create or update the course in Introw over MCP so partners take it from their partner hub - enrollment, scoring, certificates, and CRM sync handled by Introw.

**Sample prompts that fire this skill:**
- "help me build a course for our b2b partners"
- "turn our onboarding docs into a partner course"
- "make a SCORM course on our new pricing and publish it to Introw"
- "create a certification course for resellers"
- "update the course - I fixed chapter 3"
- "replace the SCORM package on the enablement course"

## Why this matters

The split of responsibilities is the point: the AI tool owns content generation (fast, flexible, disposable), Introw owns what must stay centralized - partners take the course from the hub they already use with no separate LMS login, enrollment and scoring are tracked per learner, certificates are issued automatically on passing, and completion syncs to the CRM. One `upsert_course` call bridges the two. Iteration is cheap: re-export and replace the package in place - same course, same link, enrollments and completions intact.

## The four MCP tools

| Tool | Kind | What it does |
| --- | --- | --- |
| `Introw:list_courses` | read-only | List courses with settings + SCORM import status. Source of `courseId`. `scormStatus` is "processing" until the package is live, then "ready". `scormPackageVersion` changes on every successful import/replacement - watch it to confirm a replacement went live. |
| `Introw:list_certificates` | read-only | List the org's certificates (id, name, validity) - pick a `certificateId` to link. Certificates are designed in the Introw UI; this skill only links them. |
| `Introw:create_scorm_upload` | mutation | Returns a presigned `uploadUrl` (30-minute expiry, writes exactly one org-scoped object), an `uploadPageUrl` (drag-and-drop page for the same slot, for environments that cannot PUT a file), and the `scormFileKey` to pass to `upsert_course`. Nothing imports until `upsert_course` is called with the key. |
| `Introw:upsert_course` | mutation | Omit `courseId` = create (requires `name` + the zip as `scormFileKey` or `scormFileUrl`). Provide `courseId` = update; only the fields you pass change. Fields: `name`, `description`, `thumbnailUrl` (3:1 banner, any hosted https image URL, stored as-is), `dueDate` (`{isRelative: true, amount, unit}` or `{isRelative: false, date}`), `minimumPassingScore` (0-100), `autoEnrollmentEnabled`, `certificateId` (null unlinks), `lmsMode` (create-only; `SCORM_RUNTIME` default runs the package as-is, `NATIVE` converts it into editable Introw modules), `scormFileKey` (from `create_scorm_upload`) or `scormFileUrl` (publicly downloadable https URL) - on update either one REPLACES the package. |

## Process

### Step 1: Scope the course
Confirm with the user before building:
- **Audience**: which partner type / persona (a reseller's seller vs. an SI's consultant need different courses).
- **Topic and depth**: entry-level overview vs. certification-grade. If the user has no topic, propose 2-3 grounded in their knowledge sources and current gaps.
- **Sources**: which connected knowledge to draw from - docs sites, Notion, Confluence, Drive, the vendor's website, product docs over MCP. Never fabricate content; every module traces to a source.
- **Settings**: certificate? passing score? due date? auto-enroll?

Present a module-by-module outline (2-6 modules, 10-30 min total, one learning objective each) and get sign-off before authoring.

### Step 2: Gather branding
Pull logo, colors, and typography from the vendor's website or brand assets; ask if unavailable. The course must look like the vendor, not like an AI tool. Reuse their real product screenshots, diagrams, and terminology from the sources.

### Step 3: Author the course as a self-contained HTML app
One `index.html` (plus bundled assets) that works offline:
- **Visual and interactive**: styled sections or slides, progress indicator, inline SVG diagrams, expandable examples, knowledge checks between modules. No walls of text - show, then check.
- **Self-contained**: bundle every image, font, and script in the zip. No CDN links, no external requests, no trackers.
- **Assessment**: if the course has a passing score, end with a scored assessment (prefer scenario questions over trivia). No assessment → the course reports completion only.
- **Accessible**: semantic headings, alt text, keyboard-navigable, readable contrast.

### Step 4: Wire the SCORM runtime calls
Introw runs the package in its SCORM runtime player; the SCORM API is exposed by the parent frame. Author against **SCORM 1.2** (default; Introw also detects SCORM 2004 from the manifest). The package MUST report status - a beautiful course that never calls the API shows every partner as never finishing.

```js
function findAPI(win) {
  let tries = 0;
  while (win && !win.API && tries < 10) {
    win = win.parent && win.parent !== win ? win.parent : win.opener;
    tries++;
  }
  return win && win.API ? win.API : null;
}
const api = findAPI(window);
api?.LMSInitialize("");

// After each completed module (so progress survives an early exit):
api?.LMSCommit("");

// No assessment - on the final module:
api?.LMSSetValue("cmi.core.lesson_status", "completed");

// With an assessment - on submit (score 0-100):
api?.LMSSetValue("cmi.core.score.raw", String(score));
api?.LMSSetValue("cmi.core.lesson_status", score >= PASS_SCORE ? "passed" : "failed");

api?.LMSCommit("");
// On unload:
api?.LMSFinish("");
```

Introw evaluates the pass from the reported score against the course's `minimumPassingScore` (or an explicit "passed" status) and issues the linked certificate automatically. Keep `PASS_SCORE` in the package equal to the `minimumPassingScore` you set on the course.

### Step 5: Package as a SCORM zip
- `imsmanifest.xml` at the **zip root** - not inside a subfolder (the #1 import failure).
- The `<resource href>` launch file must exist in the zip.
- List every file in the manifest's `<resource>`; keep the zip under 2 GB.

Minimal SCORM 1.2 manifest:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<manifest identifier="com.vendor.course-slug" version="1.0"
  xmlns="http://www.imsproject.org/xsd/imscp_rootv1p1p2"
  xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_rootv1p2">
  <metadata><schema>ADL SCORM</schema><schemaversion>1.2</schemaversion></metadata>
  <organizations default="org">
    <organization identifier="org">
      <title>Course title</title>
      <item identifier="item1" identifierref="res1"><title>Course title</title></item>
    </organization>
  </organizations>
  <resources>
    <resource identifier="res1" type="webcontent" adlcp:scormtype="sco" href="index.html">
      <file href="index.html"/>
      <file href="assets/styles.css"/>
      <!-- every bundled asset -->
    </resource>
  </resources>
</manifest>
```

Zip from inside the course folder (`zip -X -r ../course.zip .`) so the manifest lands at the archive root. Verify before shipping: list the zip contents, confirm `imsmanifest.xml` is at the root and the launch href exists.

### Step 6: Hand Introw the zip
Preferred - upload it directly, no hosting needed:
1. `Introw:create_scorm_upload` (pass the zip's `fileName`) → returns `uploadUrl` + `scormFileKey`.
2. HTTP PUT the raw zip bytes to `uploadUrl` with header `Content-Type: application/zip` (e.g. `curl --fail -T course.zip -H "Content-Type: application/zip" "<uploadUrl>"`). The URL expires after 30 minutes - if it lapses, just request a new one.
3. Pass `scormFileKey` to `upsert_course` in the next step.

Fallback - if this environment cannot make HTTP requests with a file body (chat assistants): the same tool response includes `uploadPageUrl`. Give the user that link with the downloadable zip - it is a drag-and-drop page that uploads into the same slot, and requires them to be signed in to Introw in this organisation (they will be redirected to log in if needed). Ask them to say "done", then continue with `scormFileKey`; if `upsert_course` reports no file yet, wait and retry. As a last resort, a publicly downloadable https URL of the zip works as `scormFileUrl` (Introw copies it server-side, so it only needs to live until the call). Never pass local paths or base64. The 3:1 thumbnail is always a hosted https URL (stored as-is, so that one must stay live).

### Step 7: Create the course
1. If a certificate is wanted: `Introw:list_certificates`, confirm the pick with the user (certificate design/branding itself lives in the Introw UI).
2. Recap every setting (name, description, thumbnail, due date, passing score, certificate, auto-enroll, mode) and get explicit approval - this is a write.
3. `Introw:upsert_course` with no `courseId`, passing the zip as `scormFileKey` (or `scormFileUrl`). Default `lmsMode: SCORM_RUNTIME`; use `NATIVE` only if the user wants to continue editing inside Introw afterwards.
4. Import runs in the background: poll `Introw:list_courses` (name filter) until `scormStatus` is "ready", then report the `courseId`. With auto-enroll on, Introw holds the course back from partners until it is actually launchable - safe to enable at create.

### Step 8: Iterate - update settings or replace the package
- **Settings-only change** (due date, certificate, thumbnail, description...): `upsert_course` with `courseId` + just those fields. `null` clears a field.
- **Content change**: re-export, upload again (`create_scorm_upload` → PUT → new `scormFileKey`), then `upsert_course` with `courseId` + the new `scormFileKey` (or a `scormFileUrl`). This replaces the package **in place**: same course, same link, enrollments kept, completions and issued certificates stand - but in-progress learners restart on the new version. **Always confirm with the user before replacing.** The old package keeps serving until the new one is live; confirm the swap by watching `scormPackageVersion` change in `list_courses` (`scormStatus` stays "ready" throughout).

## Output format
- **Course outline** (pre-build, for sign-off): modules, objectives, sources per module, assessment plan.
- **The SCORM zip** + a one-paragraph content summary and where each module's content came from.
- **Publish receipt**: `courseId`, settings applied, import status, certificate linked, what partners will see and when.
- **Iteration note**: what to say to update or replace it later ("replace the package on course X with this new zip").

## Guardrails & PRM best practice
- **Knowledge-sourced, never fabricated.** Every module traces to the vendor's real docs/data over MCP; cite the source. No invented features, pricing, or claims - partner-facing training is customer-facing content.
- **Confirm before every write.** Outline before authoring; full settings recap before `upsert_course`; explicit confirmation before any package replacement (it resets in-progress learners - the tool's own warning says so; relay it).
- **The API wiring is non-negotiable.** Ship no package that doesn't report `lesson_status` (and `score.raw` when a passing score is set). Test the completion path mentally: which user action triggers "completed"/"passed"?
- **Score consistency.** The in-package pass threshold and the course's `minimumPassingScore` must match. Don't set a passing score on a course with no assessment.
- **Self-contained packages.** No external requests, no trackers, no secrets or internal-only data in the zip - partners download and run this content.
- **Audience segments live in the Introw UI.** `autoEnrollmentEnabled` only toggles auto-enrollment; remind the user to review the audience segments in Introw if targeting matters.
- **Plan limits.** Creating a course counts against the org's course limit; if the tool returns a limit error, surface it plainly rather than retrying.
- **Partner-type awareness.** Offer variants when the audience spans partner types (reseller vs. SI vs. referral) rather than one generic course.
- **Cross-skill handoff.** Topic should come from real gaps → `vendor-microcourse-from-closed-lost` (closed-lost patterns) or `vendor-support-content-gap-detector` (support questions). Distribution nudges per partner → `Introw:add_task`.
Drop this file into .claude/skills/vendor-scorm-course-builder/SKILL.md in your repo and Claude Code triggers it on the prompts in its description. Or run the same play in plain language from Claude, ChatGPT, Slack, Teams, or your CRM through Introw’s MCP server: every action writes back to your CRM source of truth.