This is a configured, source-grounded walkthrough, not a record of an exercised visitor session or human acceptance. Runtime evidence belongs on Status. Blocked paths are identified explicitly below.
What this is
OpenMAIC is an AI classroom generator, self-hosted here as an unmodified-upstream
application with a separate deployment overlay, published as a showcase at
maic.loca.zone behind a scoped HTTP Basic gate.
Sources: README.md:41, deploy/compose.yml, deploy/nginx/maic.loca.zone.conf.
Access
- The HTTPS application is gated at the nginx server level: every application
path, including HTML, assets and
/api/, requires the Basic credential. Source:deploy/nginx/maic.loca.zone.conf. - Obtain that credential from the operator out of band. It is deliberately absent from this public wiki; no username or password is supplied here.
- wiki.maic.loca.zone is the public documentation
vhost, separate from the gated application.
Source:
deploy/nginx/maic.loca.zone.conf. - The Basic credential is not a provider API key. nginx strips
Authorizationbefore proxying; visitor model keys use a separate application request path. Sources:deploy/nginx/maic.loca.zone.conf,app/generation-preview/page.tsx:97-103.
Using the showcase (BYOK)
The deployment supplies no provider credentials and leaves DEFAULT_MODEL
empty. Bring your own key through the application settings rather than expecting
a shared, operator-funded model. Source: deploy/maic.env.example.
The following describes a fresh browser with no previously saved configuration;
settings from a previous visit can change the initial display.
Source: lib/store/settings.ts:421-436.
- Open
/. After passing the Basic gate, the homepage provides the requirement field and setup controls. With no selected model, the settings gear shows “Setup required” in English; the model control offers “Set up model”. Sources:app/page.tsx:128,app/page.tsx:440-471,app/page.tsx:485-590,lib/i18n/settings.ts:1118-1119,lib/i18n/common.ts:64-66. - Open settings. Click the gear, or use “Set up model” to open the provider
section. Settings is a dialog, not a separate settings page.
Sources:
app/page.tsx:440-471,components/generation/generation-toolbar.tsx:128-143. - Configure your provider. Paste your own API key into its API-key field.
The field supports show/hide, and configuration changes are persisted as you
edit; the dialog’s Save action closes it rather than being the persistence boundary.
Sources:
components/settings/provider-config-panel.tsx:94-107,components/settings/provider-config-panel.tsx:164-198,components/settings/index.tsx:282-305,lib/store/settings.ts:944-946. - Pick a model. Use the provider/model picker in the generation toolbar.
A key alone is not the same as a selected model: generation checks the model
selection and opens setup instead of starting if it is empty.
Sources:
components/generation/generation-toolbar.tsx:383-405,app/page.tsx:233-248. - Type a requirement, then press Enter Classroom. The button remains disabled
for an empty requirement; a PDF attachment alone does not replace the prompt.
The action creates a generation session and navigates to
/generation-preview. Sources:app/page.tsx:245-248,app/page.tsx:282-297,app/page.tsx:316,app/page.tsx:577-589. - Watch outline and scene generation. The preview requests streamed outlines,
then the first scene’s content and playback actions using the selected model.
These are provider-backed requests, not a bundled lesson being loaded.
Sources:
app/generation-preview/page.tsx:91-116,app/generation-preview/page.tsx:472-488,app/generation-preview/page.tsx:595-647. - Enter
/classroom/{id}. After saving the generated state, the preview routes into the classroom. Remaining unfinished scenes can continue generating there; landing in the classroom does not mean every scene and media task has finished. Sources:app/generation-preview/page.tsx:714-726,app/classroom/[id]/page.tsx:103-149.
Understand where your key and classroom go
Your provider configuration, including the key, lives in your browser’s
localStorage under settings-storage. On provider-backed requests the client
sends the key to this server, which uses it when contacting the selected provider.
The operator’s server sees your key in transit. Browser storage does not mean
browser-only inference or that prompts and credentials never leave the device.
Sources: lib/store/settings.ts:28-149, lib/store/settings.ts:944-946,
lib/utils/model-config.ts:6-21, app/generation-preview/page.tsx:91-116,
lib/server/resolve-model.ts:41-54, lib/server/resolve-model.ts:64-71.
The optional provider Test button sends a real /api/verify-model request; it is
not just local form validation. A selected model also does not establish that the
key is valid: later provider failures are displayed as generation errors.
Sources: components/settings/provider-config-panel.tsx:110-145,
app/api/verify-model/route.ts:8-39, app/page.tsx:233-248,
app/generation-preview/page.tsx:727-734.
Browser-generated classrooms are saved in IndexedDB, and Recent Classrooms lists
that browser’s saved stages, not a shared server catalogue. The server’s data
volume does not back up your browser settings or browser-generated classrooms.
Sources: lib/store/stage.ts:249-264, lib/utils/stage-storage.ts:36-71,
lib/utils/stage-storage.ts:137-159, lib/store/settings.ts:944-946, deploy/compose.yml.
What works without any key
These paths are implemented without an OpenMAIC provider key. Classroom playback
and export still require existing scene data; a fresh browser is only a setup
shell, not a preloaded classroom. Sources: lib/store/stage.ts:98-111,
app/page.tsx:151-173, app/classroom/[id]/page.tsx:35-69.
- UI shell and preferences: homepage controls, Chinese/English locale,
light/dark/system theme, and the local avatar, nickname and bio settings do not
need provider credentials. Sources:
app/page.tsx:332-435,app/page.tsx:528-533,lib/hooks/use-i18n.tsx:12-40,lib/hooks/use-theme.tsx:24-26,lib/hooks/use-theme.tsx:53-55,lib/store/user-profile.ts:20-42. - Existing classroom playback: saved slides, quiz scenes and playback actions
are rendered locally. Existing audio can play; without audio, native speech or
a reading timer can advance narration. This does not generate new AI responses.
Sources:
components/stage/scene-renderer.tsx:15-31,components/stage.tsx:248-264,lib/utils/audio-player.ts:25-54,lib/playback/engine.ts:442-488. - Existing interactive content and whiteboards: saved interactive HTML renders
in an iframe, and saved whiteboard actions execute locally. Embedded HTML can
run scripts or reference remote resources; do not assume it is inert or offline.
Sources:
components/scene-renderers/interactive-renderer.tsx:12-26,lib/playback/engine.ts:544-555,lib/action/engine.ts:274-305. - Local quiz grading: choice questions are graded against their stored answers.
Short-answer grading is different: it calls
/api/quiz-grade; its failure path awards rounded half-credit and reports unavailable grading, not an AI assessment. Source:components/scene-renderers/quiz-view.tsx:61-135. - PPTX and ZIP export: the browser builds a PPTX, or a ZIP containing the PPTX
and existing interactive HTML. Export requires scenes, no pending/failed
outlines, settled media tasks and at least one slide; media tasks may be failed.
Existing media URLs may be fetched, so keyless export is not guaranteed offline.
Sources:
components/header.tsx:50-54,components/header.tsx:267-295,lib/export/use-export-pptx.ts:965-968,lib/export/use-export-pptx.ts:1082-1118,lib/export/use-export-pptx.ts:1133-1180. - Native Web Speech TTS and ASR: the default browser-native speech paths need
no OpenMAIC provider key where the browser supports them. Microphone permission,
browser support and recognition network errors still matter; native ASR is not
a promise of offline recognition. Cloud speech providers are separate paths.
Sources:
lib/store/settings.ts:255-273,lib/audio/constants.ts:609-620,lib/audio/constants.ts:747-751,lib/hooks/use-audio-recorder.ts:43-76,lib/hooks/use-audio-recorder.ts:93-168,lib/hooks/use-scene-generator.ts:123-156. - Default PDF parsing: the default
unpdfparser does not need a provider key, but parsing runs on this server. Turning parsed material into a new classroom still requires the LLM generation path described above. Sources:lib/store/settings.ts:276-282,lib/pdf/constants.ts:11-26,app/generation-preview/page.tsx:174-205,app/generation-preview/page.tsx:472-488.
Opening an unfinished classroom can automatically resume scene or media
provider work. Keyless playback means replaying existing content, not a guarantee
that visiting every classroom URL is passive. Source: app/classroom/[id]/page.tsx:103-149.
Running it yourself
These are the upstream README commands, not a reproduction of the showcase’s
separate loopback-only, gated deployment overlay.
Sources: README.md:80-149, deploy/compose.yml, deploy/nginx/maic.loca.zone.conf.
Runtime versions
| Component | Source-grounded requirement |
|---|---|
| Node.js | >=20.9.0 in package.json:6-7; .nvmrc:1 selects 22. |
| pnpm | 10.28.0, pinned by packageManager in package.json:125. |
| Next.js | 16.1.2 in package.json:60. |
| Docker base | node:22-alpine, with pnpm 10.28.0 in Dockerfile:2-5. |
The README’s shorter prerequisites say Node >=20 and pnpm >=10; use the
stricter package metadata and pin above. Source: README.md:75-78, package.json:6-7,125.
Install and configure
Upstream clone/install and environment-copy commands (README.md:80-92):
git clone https://github.com/THU-MAIC/OpenMAIC.git
cd OpenMAIC
pnpm install
cp .env.example .env.local
pnpm install runs the root postinstall, which builds the bundled mathml2omml
and pptxgenjs workspaces; it is not only a dependency download.
Source: package.json:10.
For the README’s server-configured setup, edit .env.local to supply at least one
LLM provider key, or use server-providers.yml. No key values are reproduced here.
For headless generation, also set a matching DEFAULT_MODEL in providerId:modelId
form; the resolver does not infer a default from whichever key you supplied.
Sources: README.md:94-116, lib/server/resolve-model.ts:30-31, lib/ai/providers.ts:1045-1059.
Start locally
Development (README.md:118-124, package.json:11):
pnpm dev
Open http://localhost:3000. For a production build and start, use the following
instead (README.md:124-130, package.json:12-13):
pnpm build && pnpm start
Docker alternative
After creating and editing .env.local, the upstream Docker path is
(README.md:143-149):
docker compose up --build
Upstream Compose publishes 3000:3000 and uses the named openmaic-data volume.
The showcase instead uses image maic-showcase:d088, loopback port 52300, a host
data bind mount and the maic.service wrapper. See Operations
before treating the upstream command as an internet-facing deployment recipe.
Sources: docker-compose.yml:1-15, deploy/compose.yml, deploy/maic.service.
What this deployment does NOT do
- Headless
POST /api/generate-classroomis blocked by configuration. The route exists, but its generation pipeline resolves the model from server configuration, not your browser’s BYOK settings. With no server key and noDEFAULT_MODEL, it falls back to OpenAIgpt-4o-mini, then model construction throws for the missing key. This is not a missing HTTP route or a promise of immediate HTTP rejection. Sources:deploy/maic.env.example,app/api/generate-classroom/route.ts:11-50,lib/server/classroom-generation.ts:178-189,lib/server/resolve-model.ts:30-31,lib/ai/providers.ts:945-947. - There is no bundled demo classroom. The store begins with no stage or scenes;
entry points load browser-saved or server-stored classrooms, not seeded lessons.
README GIFs and the external Live Demo are not runnable classroom data here.
Sources:
lib/store/stage.ts:98-111,app/page.tsx:151-173,app/classroom/[id]/page.tsx:35-59,README.md:16,README.md:183-249. - There is no PDF or classroom video/MP4 export. The implemented export choices
are PPTX and PPTX-plus-interactive-HTML ZIP. That ZIP is not a full classroom backup.
Sources:
components/header.tsx:267-295,lib/export/use-export-pptx.ts:1106-1180. - Sora video generation is not implemented. Sora appears in the registry/UI,
with no listed models, but the adapter dispatcher has no Sora implementation and
throws for unsupported providers. Supplying a Sora key does not complete it.
Sources:
lib/media/video-providers.ts:16-77,lib/media/video-providers.ts:145-153.