Why
Generated code needs a governable contract.
Lantern should let instructors create useful course apps without
creating new LMS integration risk for every idea. The generated app
contract makes the app responsible for browser UI, lesson content,
interaction logic, preview assertions, and structured attempt events.
Generated apps may provide
- Browser UI.
- Lesson content.
- Learner interaction logic.
- Preview assertions.
- Structured attempt events through
window.GatewayApp.
Generated apps must not provide
- LMS integration code.
- Backend services.
- Direct storage.
- Direct grade passback.
- Arbitrary network access.
- Worker or Durable Object code.
Package shape
Every generated app includes preview proof.
manifest.json
dist/index.html
dist/pico.min.css
dist/lantern-app.css
dist/app.css
dist/app.js
content/activity.json
preview/fixtures.json
preview/tests.json
Optional files depend on starter and grading mode:
scoring/rubric.json
grading/specs/*.js
evidence/example-output.json
Instruction, contract, source, and diagnostics files used by the
authoring harness are not package artifacts. Package validation consumes
only the package files.
Runtime boundary
The LMS launches Lantern. Lantern launches the reviewed app.
Generated app code runs as browser code on the reviewed runtime origin.
It does not receive raw LMS access tokens, LTI launch JWTs, D1 or R2
bindings, Cloudflare environment bindings, Worker Loader control, direct
database handles, secrets, or arbitrary outbound HTTP capability.
Lantern may use Workers, D1, R2, Dynamic Workers, Worker Loader, or
Durable Objects behind the platform boundary. Those implementation
choices do not become generated app capabilities.
SDK
Generated apps use only window.GatewayApp.
getLaunchContext()Read scoped launch context.
getActivityContent<T>()Read reviewed activity content.
readLocalState<T>()Resume the current learner's state.
writeLocalState<T>(value)Save resumable progress through Lantern-owned storage.
emitAttemptEvent(event)Record reportable learner actions.
submitEvidenceArtifact(input)Submit structured evidence through the governed path.
submitScoreProposal(input)Send a score proposal without writing to the LMS.
runBrowserGrader()Run reviewed browser grader specs when the package is a browser autograder.
finalizeAttempt(input)Finish the attempt with an explicit completion state.
const gateway = window.GatewayApp;
if (!gateway) {
throw new Error('GatewayApp is required.');
}
Manifest capabilities must match SDK use exactly. If code calls
writeLocalState(), the manifest must declare
write_local_state. If the app does not need local state, it
must not request that capability.
Events and state
Use Lantern state and Lantern events.
Generated apps use readLocalState() and
writeLocalState(value) for resumable progress. They use
emitAttemptEvent(event) for answer, progress, and complete
events. They call finalizeAttempt({ completionState: "completed" })
when the activity is done.
type AttemptEvent =
| {
type: 'answer';
questionId: string;
answer: string | string[];
correct?: boolean;
scoreGiven?: number;
scoreMaximum?: number;
timestamp: string;
}
| { type: 'progress'; checkpoint: string; value: number; timestamp: string }
| { type: 'complete'; timestamp: string };
Generated packages must not use
localStorage, sessionStorage, cookies, or IndexedDB. - SCORM, xAPI, cmi5, LRS, LMS, grade, or external reporting APIs.
- Arbitrary
fetch() calls for learning records. - Remote scripts, stylesheets, images, fonts, icons, or CDNs.
- Imports, module exports,
eval, or new Function. - Canvas, Moodle, Blackboard, or Sakai API clients.
- Cloudflare Worker entrypoints, Durable Objects, D1, R2, KV, Queue, service bindings, or
env.* access.
Definition of done
A generated app is not done until Lantern can prove it.
- The initialized workspace exists and records this contract.
- TypeScript authoring source passes strict typecheck when source files exist.
dist/app.js is browser-only reviewed code with no imports. - Required package files are present.
- Pinned Pico and Lantern stylesheets are unchanged.
manifest.json passes schema validation. - Manifest capabilities match SDK calls.
- Static policy checks pass.
- Package validation passes.
- Preview/runtime assertions pass.
- Design and style contract checks pass.
- A pending package version is saved only after all checks pass.
- A human reviewer can inspect capabilities, preview evidence, activity logs, runtime logs, and package files before approval.
Reviewer questions
- What does this app ask the learner to do?
- What capabilities does it request?
- What learner state does it store?
- What attempt events does it emit?
- Does it finalize attempts?
- Does it request evidence or browser grading?
- Does preview prove the required behavior?
- Is anything elevated enough to require IT or security review?