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 Authorization before 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.

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. 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 unpdf parser 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

ComponentSource-grounded requirement
Node.js>=20.9.0 in package.json:6-7; .nvmrc:1 selects 22.
pnpm10.28.0, pinned by packageManager in package.json:125.
Next.js16.1.2 in package.json:60.
Docker basenode: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-classroom is 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 no DEFAULT_MODEL, it falls back to OpenAI gpt-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.

See also