Skip to main content
Version: 2026-09-21 (current)

How a hosted tool works

A hosted tool is a web component: one custom HTML element, defined in a JavaScript file, that Voshi loads inside the course page when someone opens your tool. Voshi does everything around it — the LMS integration, hosting your files on a CDN, logging the student in, placement in courses, provisioning, storage, and grade passback. Your code draws the activity and talks to Voshi through one object.

The lifecycle of a launch​

  1. Someone opens your tool from a course. Voshi handles the LMS side and works out who they are, which course they are in, and which of your locations the link points at.
  2. Voshi loads your code — the version of your tool that course runs — and your styles and templates.
  3. Voshi constructs your element, passing it one argument: the Voshi API, already loaded with the launch details and ready to call.
  4. Your element renders whatever the learner should see, reads any saved work from api.storage, and, when the learner finishes graded work, calls api.submitGrade().

The page around your element belongs to Voshi. It watches your element's height and tells the LMS, so the frame fits your content — give your element :host { display: block } and it just works.

What your code looks like​

The smallest possible tool:

// app.js
class HelloTool extends HTMLElement {
constructor(api) {
super()
this.api = api // keep the Voshi API for later
this.attachShadow({ mode: 'open' }) // your markup and styles live in here
}

connectedCallback() {
const name = this.api.isStaff ? this.api.user.full_name : 'there'
this.shadowRoot.innerHTML = `<p>Hello, ${name}. You opened ${this.api.location.label}.</p>`
}
}

customElements.define('hello-tool', HelloTool)

Three things every tool does, and the AI Builder does them for you:

  • The constructor takes api and stores it. It attaches a shadow root and nothing else; browsers forbid a constructor from touching the page.
  • Rendering happens in connectedCallback, after the element is on the page. Query this.shadowRoot, never document — your element's markup is inside the shadow root, and document.querySelector cannot see it. This is the most common mistake in hand-written tools.
  • The tag is registered with customElements.define. The tag must be lowercase and contain a dash.

A real tool usually keeps its markup in index.html and its styles in styles.css, which Voshi loads for it and hands over as api.assets. See Your tool's files and Assets.

What Voshi does for you​

NeedHow it is met
HostingYour files are served from a CDN. Upload or build, and they are live in the Sandbox.
Login and identityapi.user says who launched, with a stable ID. No passwords, no accounts, no sessions to manage.
Which course, which activityapi.course and api.location.
Saving workapi.storage — four JSON rows per launch, plus files on each. See Storage.
Gradesapi.submitGrade(). See Grades.
Course setupAutomatic. When a course is copied into a new term, its course and location storage come along.
Placement in coursesInstructors pick from your locations in a picker Voshi presents.
VersionsYou publish; courses adopt a version and keep it. See Versions.

The rules​

Hosted tools run inside other people's course pages, so a few things are off limits. Voshi checks what it can at upload time, and the AI Builder already follows them.

  • No server, no network calls of your own. Everything your tool needs from the platform comes through api; the only thing it ever fetches is its own files, through api.assets. There is no API key, because there is no server to keep one on.
  • No libraries, no CDNs, no build step. Your files are plain JavaScript, CSS, and HTML, served exactly as uploaded. import other files of your own by relative path; a bare name like import 'lit' cannot be resolved.
  • No localStorage or sessionStorage. Nothing about a learner may be kept in the browser. Use api.storage.
  • No document queries, no eval. Work inside this.shadowRoot.
  • Keep state in the element unless it must survive between visits, in which case it goes in api.storage.

Where things happen​

Everything about your tool lives in the dashboard: building, testing, locations, versions, logs. There is nothing to configure anywhere else.

Next​