Repository navigation
Releases: THU-MAIC/OpenMAIC
Release list
OpenMAIC v1.2.1 — Web research: Kimi, DeepSeek and Firecrawl
1.2.1 is a regular patch release. Its main theme is web research: Kimi, DeepSeek and Firecrawl join as web-search providers, and a new webFetch slot lets the agent's fetch_url tool use a hosted reader instead of the built-in one. It also contains one breaking change, the removal of the legacy director-graph classroom chat (#1913), and removes retired models from the built-in catalogs (#1939). Read Breaking Changes before upgrading from 1.2.0.
Breaking Changes
- The legacy director-graph classroom chat is removed; classroom chat always runs on Pi. #1913
- Pi needs a Classroom model with tool calling: select one for Classroom in Course Model Config, or set the
classroomslot (or thellmslot it inherits from) inopenmaic.yml. For Gemini, use the nativegooglepreset. - Remove
NEXT_PUBLIC_PI_CHAT_ENABLED. A production build accepts only unset, an empty string,trueor1(exact match) and fails with migration guidance on any other value. The Docker build arg and its Compose forwarding remain only to carry the value to that check. POST /api/chatis removed and answers404. WithACCESS_CODEset, an unauthenticated request still gets401first.
- Pi needs a Classroom model with tool calling: select one for Classroom in Course Model Config, or set the
Highlights
- Web research. Every new provider is opt-in or must be assigned; existing search defaults and the keyless
builtinreader stay as they are.webFetchslot. The reader behind the agent'sfetch_urltool is now a capability slot with its own provider registry. It defaults tobuiltin(the existing local reader);webFetch: nullinopenmaic.ymlremoves the tool. Kimi is the first hosted reader, reusing thekimiorkimi-coding-plancredentials. Choose the reader in Course Model Config → Web Fetch and enter keys in Settings → Model Services → Web Fetch. URL and private-address checks run before a URL reaches a hosted reader and again on the final URL it reports; each request uses one reader, with no fallback. #1912- Kimi web search. Shares the Kimi chat key and base URL; Open Platform keys use Search Pro and Coding Plan keys use the Coding Plan search endpoint. A Kimi chat key alone does not enable search: set
WEB_SEARCH_KIMI_ENABLED=true, addweb-search.kimitoserver-providers.yml, or, withopenmaic.yml, assignslots.webSearchto akimiprovider.WEB_SEARCH_KIMI_ENABLED=falseturns it off. #1911 - Token plans can declare web fetch. Connecting Kimi Coding Plan in Settings → Token Plan now assigns web fetch to the plan alongside chat and web search, taking over the implicit
builtindefault without a conflict prompt; disconnecting returns to the server default. Lock thewebFetchslot to keepbuiltin. #1927 - DeepSeek web search and fetch. The
deepseekpreset reusesDEEPSEEK_API_KEYand its API base for both tools. Opt in to search withWEB_SEARCH_DEEPSEEK_ENABLED=true, aweb-search.deepseekentry, or an explicitwebSearchslot; assignwebFetch: deepseekinopenmaic.ymlfor fetch. #1937 - Firecrawl web search and fetch. One
firecrawlprovider (preset: firecrawl) serves bothwebSearchandwebFetchwith one key.FIRECRAWL_API_KEY/FIRECRAWL_BASE_URLconfigure it in legacy setups, where it comes last in the search preference order; web fetch stays onbuiltinuntilwebFetchis assigned to it. A self-hosted Firecrawl base must be declared inopenmaic.yml. #1931 #1834 (by @JuampiHernandez)
Features
- Classroom chat:
cue_usercan offer 2 to 4 suggested replies, shown as one row of buttons in the roundtable. Choosing one sends it as an ordinary learner message; learners can still type their own reply. #1379 (by @yanpgwang)
Bug Fixes
- Chat: on plain HTTP at a non-localhost address (a LAN or Tailscale IP, for example), where the browser has no Web Locks, classroom chats failed to load and every save retried in a loop. Chats now save and load there; two tabs on the same chat resolve last-write-wins. The deployment guide recommends HTTPS for phones and tablets. #1929
- i18n: the server picks the initial language from the locale cookie, then
Accept-Language, and sets<html lang>to match, so server and client render the same language: a browser in another language no longer gets Chinese server HTML that switches after load./and/_not-foundnow render dynamically. #1874 (by @costajohnt) - Generation: a non-numeric or non-finite shape
rotateis reported as a model-output error with its element path instead of silently becoming0; a missing ornullangle still means0(@openmaic/generation0.3.21). #1891 (by @Hahaa909) - Roundtable: the suggested-reply bubble no longer appears stacked with the outgoing chat bubble and then jumps down; it appears once, in place, after the previous bubble has left. #1943
Packages
@openmaic/generation0.3.21 (was 0.3.20). Other packages are unchanged from 1.2.0.
Known issues
- Google shuts down the Veo 3.1 previews on October 22, 2026; after that the built-in Veo provider has no working model. #1940
- Qwen voice cloning still uses a retired model, so registering or synthesizing a cloned voice fails until it moves to CosyVoice;
TTS_QWEN_VOICE_CLONE_MODELcan point to another model. #1941 - Volcengine Ark Agent Plan models report no image input, so reference images are dropped for them. #1942
Other Changes
- Models: remove retired entries from the built-in catalogs and presets (existing saved IDs remain user-managed): #1939
- deepseek:
deepseek-v4-flash,deepseek-v4-flash-vision-exp. Usedeepseek-flash. - qwen:
qwen3.6-max-preview,qwen3-max. Useqwen3.7-max. - kimi:
kimi-k2.5,kimi-k2-thinking. Usekimi-k3. - siliconflow:
deepseek-ai/DeepSeek-R1-Distill-Qwen-7B,Pro/moonshotai/Kimi-K2.5,THUDM/GLM-4.1V-9B-Thinking,THUDM/GLM-Z1-Rumination-32B-0414. Use an available model from the provider catalog. - grok:
grok-4-1-fast-reasoning,grok-4-1-fast-non-reasoning,grok-code-fast-1. Usegrok-4.3orgrok-build-0.1. - grok-image:
grok-imagine-image-pro. Usegrok-imagine-image. - tencent-hunyuan:
hy3-preview; also removehunyuan-2.0-thinking-20251109andhunyuan-2.0-instruct-20251111from environment examples. Usehy3. - xiaomi:
mimo-v2-pro,mimo-v2-omni,mimo-v2-flash. Usemimo-v2.6-proormimo-v2.6-flash. - doubao:
doubao-seed-1-8-251228. Usedoubao-seed-evolving. - seedream:
doubao-seedream-3-0-t2i-250415. Usedoubao-seedream-5-0-260128. - seedance:
doubao-seedance-1-5-pro-251215. Usedoubao-seedance-2-0-mini-260615. Keepdoubao-seedance-1-0-lite-t2v-250428while its status is Retiring, not Shutdown. - qwen-image:
qwen-image-max,qwen-image-max-2025-12-30,qwen-image-plus,qwen-image-plus-2026-01-09,qwen-image. Useqwen-image-3.0. - nano-banana:
gemini-3.1-flash-image-preview,gemini-3-pro-image-preview. Usegemini-nano-banana-2.1orgemini-3-pro-image. - veo:
veo-3.0-fast-generate-001,veo-3.0-generate-001,veo-2.0-generate-001. Useveo-3.1-generate-preview(scheduled to retire October 22, 2026). - qwen-tts:
qwen3-tts-instruct-flash,qwen-tts. Useqwen3-tts-flash. - Ark Agent Plan doubao:
doubao-seed-2.1-turbo,doubao-seed-2.0-pro,doubao-seed-2.0-code,doubao-seed-2.0-lite,deepseek-v3.2,minimax-m2.7,glm-5.2,glm-5.1,kimi-k2.6. Usedoubao-seed-2.1-pro,deepseek-v4-proorminimax-m3. - Ark Agent Plan seedream:
doubao-seedream-5.0-lite. Usedoubao-seedream-5.0-pro. - Ark Agent Plan seedance:
doubao-seedance-1.5-pro. Usedoubao-seedance-2.0-mini. - Removed IDs that vendors route to a catalog successor resolve to it for capability lookups, so saved configurations keep image input, thinking controls and reasoning replay:
deepseek-v4-flashanddeepseek-v4-flash-vision-exp→deepseek-flash,hy3-preview→hy3,grok-code-fast-1→grok-build-0.1, Ark Agent Planglm-5.2→glm-5.3. grok-4-1-fast*(served asgrok-4.3at a fixed reasoning effort) and SiliconFlowPro/moonshotai/Kimi-K2.5remain valid in saved configurations. They lose catalog capability metadata, including image input and thinking controls; reselect a replacement model to restore that metadata.- Retain
qwen3-tts-vc-2026-01-22as the non-selectable grouping ID for saved cloned voices. The model has retired: clone registration and synthesis fail until migration to CosyVoice.TTS_QWEN_VOICE_CLONE_MODELcan point to another model. - Keep upcoming retirements in the catalog: MiMo V2.5 / V2.5 Pro on October 21, 2026; Veo 3.1 Fast / Standard / Lite previews and Doubao Seed 2.0 Lite / Mini on October 22, 2026;
gpt-image-1on October 23, 2026. Google's recommended Veo replacement,gemini-omni-1.1-flash, is not yet supported by the Veo adapter. - Ark Agent Plan: add the officially listed migration targets
doubao-seed-2.1-lite,glm-5.3,kimi-k3andkimi-k2.8-preview(the Small-tier replacement forkimi-k2.7-code). - Keep models with future retirement dates and unverified entri...
- deepseek:
OpenMAIC v1.2.0 — Server-first, with classroom export
Up to 1.1.x the browser drove course generation one request per step and kept the courses, the provider keys and the model settings itself. Closing the tab stopped a course halfway, every browser had to be set up on its own, a deployment could offer providers but not fix which models its users get, and the headless API ran a separate pipeline that drifted from the web app. 1.2.0 moves all of this to the server: courses and media, identity, model configuration and course generation live there, and the browser is a client. Classrooms can now also leave OpenMAIC: as a PPTX that keeps every scene, or as one offline HTML file that plays the lesson.
The cost is the deployment shape: 1.2.0 needs PostgreSQL and a long-running Node.js server. Serverless hosts, Vercel included, stay on 1.1.x. Read Breaking changes and Before you upgrade first, then follow the deployment guide's Upgrading from 1.1.x.
Design: RFC #1754 (release), #1701 (model configuration) and #1809 (classroom export).
Highlights
- Generation runs on the server. Classic generation is a server-side run that keeps going when the page is closed, resumes from its last checkpoint after a restart or a crashed worker, streams progress to every open tab, and pauses at a failed step so that Retry re-runs only that step. Images and videos are generated alongside the scenes, and a single failed item can be retried. The web app and the headless API share one pipeline. #1756 #1759 #1761
- Models are configured on the server.
openmaic.ymldeclares providers and capability slots (llmwithcourse.*,classroomandagent, plustts,asr,image,video,webSearchanddocument).slotsare defaults users may change,lockfixes slots for everyone, andallowUserKeys: falsekeeps users from adding their own providers. Settings take the matching shape (set it up yourself, choose a model or configured by the administrator), and keys are stored encrypted on the server and never leave it. #1727 #1733 #1767 #1793 - Materials are parsed as soon as they are attached. The composer uploads and parses each file in place and shows progress, Ready, or Failed with Retry; Generate waits until every file is ready, and the preview opens without a material-analysis step. #1796
- Identity and persistence. Three identity modes: single-user for personal installations (the Docker Compose default), anonymous visitors (the cookie now lasts 400 days and is renewed while in use), and accounts through host auth methods. Anonymous work can be claimed into an account with
POST /api/identity/claim. Courses, media, custom agents and model settings are stored on the server, the database schema is versioned, and the first load after the upgrade moves each browser's data to the server once. #1757 #1758 - Classroom export.
- The PPTX keeps the whole lesson. Interactive, quiz and PBL scenes stay in place as placeholder slides with an Open online button and a QR code that open the scene in the online classroom. Export PPTX and Export Resource Pack offer placeholder slides (recommended) or slides only. #1811 #1819 #1823 #1693
- Offline HTML. One self-contained file that plays the classroom without a network connection: narration with captions, spotlight and laser, auto-advancing slides, slide video, discussion cards and interactive widget actions; quiz, interactive and PBL scenes hold until the learner moves on. Export with narration and video or without narration. Classrooms over 400 MB are exported as a ZIP of
classroom.htmland its media folders. #1813 #1842 #1845 #1848 #1850
- Inline math survives saving. Formulas typed in the slide text editor are stored as LaTeX source and typeset by the clients, render-service previews and the PPTX export follow, and every KaTeX/Temml path disables formula-defined macros. #1829 #1904 #1827
Security
1.2.0 includes every fix of the 1.1.x security releases, and these advisories:
- GHSA-r2xp-m5r2-g7xj (High): callers could use server-managed provider credentials with arbitrary models. Model authorization is now enforced for server-managed providers across chat, media, speech, model-based web search and workspace assignments. Reported by @13ob0. #1879
- GHSA-x3gm-gw9m-94h9 (Medium): MP4 render jobs were not bound to the requesting owner. Reported by @Duang777. #1884
- GHSA-6jrw-cp5x-j8jc (Low): deleted courses did not revoke legacy classroom media URLs. Reported by @Duang777. #1883
- GHSA-6c52-8h4v-5xvg (High): stored XSS in slides loaded through
/api/persistence. Fixed in 1.1.3 and in this line since 1.2.0-rc.1. #1799
Hardening since rc.2: user-authored skill content is fenced with an unforgeable end marker #1816, formula-defined macros are disabled in every math renderer #1827, and CSS escapes are refused in inline styles #1815.
Breaking changes
- PostgreSQL and a long-running server are required.
DATABASE_URLis mandatory. Deploy with Docker (docker compose upnow includes PostgreSQL and runs single-user on127.0.0.1) or withpnpm start.NEXT_PUBLIC_PERSISTENCEandvercel.jsonare removed. MODEL_ROUTESwithoutopenmaic.ymlstops the server at startup. Deployments running the Pro agent must writeopenmaic.ymlfirst; the route-to-slot table is under "Migrating from the legacy configuration" in the configuration docs. Withoutopenmaic.yml, the provider variables,server-providers.yml,DEFAULT_MODELandMODEL_FALLBACKkeep working but are deprecated.- Providers with server-managed credentials need an explicit model list (
*_MODELS, ormodelsunder the provider inopenmaic.yml/server-providers.yml). Without one, only default, fallback and slot references are authorized. A startup warning names each provider that has credentials but no list. - Upgrade the render-service together with or before the app. Render jobs are owner-bound, and old/new mixes fail closed.
- The browser no longer sends provider settings. The
x-api-key,x-model,x-base-url,x-model-routes,x-image-*andx-video-*headers and the matching body fields are deprecated, honoured only for a slot with nothing assigned and never underallowUserKeys: false. - Headless API.
POST /api/generate-classroomtakes{ requirement, materialIds? }; upload documents first withPOST /api/materials(pdfContentis refused). Job ids are run ids, so earlier job ids answer404. Every capability the server configures runs (GET /api/generate-classroom/capabilitiesreports which). In anonymous-cookie mode, keep one cookie jar for the upload, the submission and the polls. - Routes removed:
/api/generate/{scene-outlines-stream,agent-profiles,scene-content,scene-actions},/api/extract-document,/api/web-search, andGET/POST /api/classroom. Use/api/generation-runs. - A course is read-only while it is being generated (
409 COURSE_GENERATINGfor other writers). - Runtime sessions are keyed by the resolved owner.
PERSISTENCE_DEV_TOKEN,NEXT_PUBLIC_PERSISTENCE_TOKENandPERSISTENCE_ALLOW_INSECURE_DEV_AUTHare removed. If the token was your only access gate, put the deployment behindACCESS_CODE, a gateway or owner auth methods first. - Assets belong to an owner;
ASSET_QUOTA_BYTESis a per-owner limit. - Pi classroom chat refuses models that cannot call tools (
tool_calling_required) and Google's OpenAI-compatible Gemini endpoint (gemini_native_required); use the nativegooglepreset for Gemini. #1894 #1897 - Embedders:
@openmaic/storage0.32–0.37 moves document ownership to thedocumentOwnershiprelation, drops the IndexedDB fallback of the browser storage seams, and removesServerPersistenceProvider.documentStore.
Before you upgrade
- Back up the database. The fir...
v1.2.0-rc.2 — Security
Security release candidate for 1.2.0. It fixes three vulnerabilities reported privately; see the advisories below.
Upgrade notes
- Providers that use server credentials now need an explicit model list (
*_MODELSormodels); without one only default/fallback models are usable. See the breaking-change section below.- Upgrade the render-service together with or before the app.
Thanks to @13ob0 and @Duang777 for the reports and fixes.
Advisories
- GHSA-r2xp-m5r2-g7xj (High): missing model authorization for server-managed provider credentials. Reported by @13ob0.
- GHSA-x3gm-gw9m-94h9 (Medium): MP4 render jobs not bound to the requesting owner. Reported by @Duang777.
- GHSA-6jrw-cp5x-j8jc (Low): deleted courses did not revoke legacy classroom media URLs. Reported by @Duang777.
Security
- Enforce model authorization for server-managed providers across chat, media, speech, model-based web search and workspace model assignments. Unauthorized and unknown model ids return the same HTTP 403 response before provider access. Users' own credentials continue to work. #1879 (with @13ob0)
- Render jobs are bound to the requesting owner. The render-service and app must be upgraded together; upgrade every service instance (or drain old instances) together with or before the app. Old/new version mixes fail closed through a dedicated owner-bound job namespace. #1884 (by @Duang777)
- Deleted courses no longer serve their legacy classroom media:
/api/classroom-media/<id>/...checks the course lifecycle before touching the filesystem and answers a tombstoned course with the same 404 as a missing file. Successful responses areprivate, max-age=300, must-revalidateinstead ofpublic, immutable. #1883 (by @Duang777)
Breaking change: server-managed model authorization
- Set
*_MODELSfor every provider with server-managed credentials, or setmodelsunder each provider inopenmaic.yml/server-providers.yml. Without a list, only deployment default/fallback and capability slot references authorize models; preset catalogues and workspace assignments do not. Provider-only media slots authorize a single adapter default. Services without model ids need no list. Providers configured without credentials (local Ollama, Lemonade) are not restricted; a keyless gateway that adds its own upstream credential should be given a key and a model list. - Migration: list the model ids users should be able to select (including voice compatibility models), restart the server, then update workspace selections that are no longer authorized. A startup warning names the configuration setting for each provider with credentials but no explicit list.
Bug Fixes
- S3 asset storage:
@openmaic/storage0.37.3 supports path-style addressing for S3-compatible object stores such as MinIO and Ceph. SetAWS_S3_FORCE_PATH_STYLE=true(or1) together withAWS_ENDPOINT_URL_S3so objects are addressed asendpoint/bucket/key; leaving it unset keeps the existing behaviour for Amazon S3 (#1686). - Server persistence:
@openmaic/storage0.37.2 boundsHttpDocumentStorerequests with a deadline (requestTimeoutMs, default 30s,<= 0disables) covering the request round trip — sending the body and receiving the response headers — so a persistence endpoint that stops answering fails like any other transport error instead of holding its caller forever. The stage autosave keeps at most one save in flight and starts the next only once that promise settles, so a request that never settled silently stranded every later save for the life of the page while the editor went on rendering the in-memory document; the reload showed what had actually reached the server. A request aborted at the deadline rejects withHTTP_REQUEST_TIMEOUT, which the autosave's existing backoff retries. The budget is the floor plus an allowance proportional to the request body (sized at a fixed 100 KiB/s) and is capped at 10 minutes, so a large document on a slow link is not mistaken for a stall; reading the response body stays outside the bound. This mirrors the budgetHttpAssetStorealready applies throughprobeTimeoutMs/startBoundedOperation. - Synchronous scene previews and video exports no longer block each other; each uses its own execution lane. #1830
- Preview concurrency is capped by the render resource profile and reported by
/health. Cancelling a preview during Chromium startup retains its execution slot until launch and browser cleanup settle.
OpenMAIC v1.1.4 — Security
A security release. Providers that use server credentials only send models the deployment authorizes, render jobs are bound to the requesting owner, and deleted courses stop serving their legacy media. Read Breaking change before upgrading, and upgrade the render-service together with or before the app. The same fixes ship in v1.2.0-rc.2. Thanks to @13ob0 and @Duang777 for the reports.
Advisories
- GHSA-r2xp-m5r2-g7xj (High): missing model authorization for server-managed provider credentials. Reported by @13ob0.
- GHSA-x3gm-gw9m-94h9 (Medium): MP4 render jobs not bound to the requesting owner. Reported by @Duang777.
- GHSA-6jrw-cp5x-j8jc (Low): deleted courses did not revoke legacy classroom media URLs. Reported by @Duang777.
Security
- Render jobs are bound to the requesting owner. Upgrade every render-service instance (or drain old instances) together with or before the app. Mixed service versions fail closed through a dedicated owner-bound job namespace.
- Legacy classroom media stops being served when its course is deleted. Media responses use private caching with revalidation, and lifecycle lookup failures fail closed.
- Providers using server credentials now authorize the selected model before provider access across chat, generation, media, voice, transcription, search and connection tests. Model authorization refusals return the same HTTP 403
PROVIDER_DISABLEDresponse. Users' own credentials and keyless providers are unaffected.
Breaking change: server-managed model authorization
- Configure
*_MODELSor each provider's YAMLmodelslist. Without a list, chat authorizes onlyDEFAULT_MODELand operatorMODEL_ROUTESreferences; other model-selecting capabilities authorize only their single default. Preset catalogues do not grant access. Services without model selection need no list. - With an explicit list, TTS, ASR, image, video and Claude web search use a listed client choice or substitute the first listed model for an unlisted or missing choice. Speech preview, narration and transcription send catalogue defaults on the 1.1.x client: put the desired pinned model first, without needing to list the client default. Unlisted models never reach the provider with server credentials.
- Qwen clone voices map the built-in clone sentinel to the configured
TTS_QWEN_VOICE_CLONE_MODELbefore authorization. Include the final clone target in the TTS model list; the override alone does not authorize it. - Migration: list all selectable model ids, including voice compatibility models, restart the server, and update saved chat selections and capability selections without explicit lists outside the authorized set. Startup warnings identify credentialed model-selecting providers without a list. Give a gateway that adds upstream credentials a key and a model list, or restrict models in the gateway itself.
OpenMAIC v1.1.3 — Security
A security release. Course documents served by /api/persistence now carry only the slide HTML the renderer produces, on every write and every read. Read Behavior Changes before upgrading.
Security
- Course documents: with server persistence enabled,
/api/persistence/documents/...stored and returned slide HTML without sanitizing it. Document reads are capability-by-id, so anyone with a course link loads that course, and the classroom renders slide text, shape text, table cells and LaTeX snapshots as HTML. A course written through this path could therefore run script in the browser of anyone who opened its link. The owner-bound document store now applies the same sanitization policy as/api/classroomto the stage and scenes on every write and every read, so new documents are stored clean and documents stored earlier are served clean. GHSA-6c52-8h4v-5xvg #1799
The same fix ships in v1.2.0-rc.1.
Behavior Changes
- Slide HTML written through
/api/persistenceis reduced to the renderer's formatting vocabulary (the policy/api/classroomalready applies): scripts, event-handler attributes,javascript:URLs and embedded objects are removed, and inline styles are re-serialized without spaces (text-align: center;becomestext-align:center). Formatting the editor produces is kept. - Documents already stored are not rewritten in the database; they are sanitized when read, and stored clean the next time they are saved.
v1.2.0-rc.1 — server-first (release candidate)
The release candidate for 1.2.0, server-first.
Up to 1.1.x the browser drove course generation one request per step and kept the courses, the provider keys and the model settings itself. Closing the tab stopped a course halfway, every browser had to be set up on its own, a deployment could offer providers but not fix which models its users get, and the headless API ran a separate pipeline that drifted from the web app. 1.2.0 moves all of this to the server: courses and media, identity, model configuration and course generation live there, and the browser is a client. Generation becomes a server-side run shared by the web app and the API, and models are configured once per deployment. The cost is the deployment shape: a long-running Node process and PostgreSQL instead of a serverless host.
Design: RFC #1754 (release) and #1701 (model configuration). Read Breaking Changes and Before you upgrade first.
Highlights
-
Generation runs on the server. Classic generation is a server-side run that keeps going when the page is closed, resumes from its last checkpoint after a restart or a crashed worker, streams progress to every open tab, and pauses at a failed step so that Retry re-runs only that step. Images and videos are generated alongside the scenes, and a single failed item can be retried. The web app and the headless API share one pipeline. #1756 #1759 #1761
-
Models are configured on the server.
openmaic.ymldeclares providers and capability slots:llmwithcourse.*,classroomandagent, plustts,asr,image,video,webSearchanddocument.slotsare server defaults that users may change.lockfixes slots (orall) for everyone.allowUserKeys: falsekeeps users from adding their own providers.- The settings take the matching shape: set it up yourself, choose a model or configured by the administrator.
- Keys are stored encrypted on the server and never leave it. #1727 #1733 #1767 #1793
-
Materials are parsed as soon as they are attached. The composer uploads and parses each file in place and shows progress, Ready, or Failed with Retry. Generate waits until every file is ready, and the preview then opens without a material-analysis step. Re-uploading the same file reuses the earlier parse. #1796
-
Identity. There are three modes:
- single-user for personal installations (the Docker Compose default);
- anonymous visitors, whose cookie now lasts 400 days and is renewed while in use;
- accounts, through host auth methods.
Anonymous work can be claimed into an account with
POST /api/identity/claim. -
Custom agents are stored on the server (
/api/agents). #1758 -
The database schema is versioned (
openmaic_schema_migrations). #1757 -
Upgrades carry browser data to the server. The first load after the upgrade moves the browser's courses, chat, progress, folders, media, custom agents and model settings to the server, once per browser.
Breaking Changes
-
PostgreSQL and a long-running server are required.
DATABASE_URLis mandatory.- Deploy with Docker (
docker compose upnow includes PostgreSQL and runs single-user, on127.0.0.1) or withpnpm start. - Serverless hosts, Vercel included, stay on 1.1.x; the README explains how to deploy it.
NEXT_PUBLIC_PERSISTENCEandvercel.jsonare removed.
- Deploy with Docker (
-
MODEL_ROUTESwithoutopenmaic.ymlstops the server at startup. Deployments running the Pro agent must writeopenmaic.ymlbefore upgrading. The route-to-slot table is under "Migrating from the legacy configuration" in the configuration docs. Withoutopenmaic.yml, the provider variables,server-providers.yml,DEFAULT_MODELandMODEL_FALLBACKkeep working, but are deprecated. -
The browser no longer sends provider settings. The
x-api-key,x-model,x-base-url,x-model-routes,x-image-*andx-video-*headers, and the matching body fields, are deprecated.- They are honoured only for a slot with nothing assigned.
- They are never honoured under
allowUserKeys: false.
-
Headless API.
POST /api/generate-classroomtakes{ requirement, materialIds? }.- Upload documents first with
POST /api/materials;pdfContentis refused. - Job ids are run ids, so job ids from earlier builds answer
404. - The
enable*,agentModeand web-search request fields are ignored. Every capability the server configures runs, andGET /api/generate-classroom/capabilitiesreports which ones. - Submissions are checked up front (
400 MISSING_MODEL,MISSING_API_KEY, …) and limited per owner (429 ACTIVE_RUN_LIMIT). - In anonymous-cookie mode, keep one cookie jar for the upload, the submission and the polls.
- Upload documents first with
-
Routes removed:
/api/generate/{scene-outlines-stream,agent-profiles,scene-content,scene-actions}/api/extract-document/api/web-searchGET/POST /api/classroom
Use
/api/generation-runsinstead. -
A course is read-only while it is being generated. Other writers get
409 COURSE_GENERATINGuntil its run completes or ends. Deleting the course and moving it between folders stay allowed. -
Runtime sessions are keyed by the resolved owner.
PERSISTENCE_DEV_TOKEN,NEXT_PUBLIC_PERSISTENCE_TOKENandPERSISTENCE_ALLOW_INSECURE_DEV_AUTHare removed.- If the token was your only access gate, put the deployment behind
ACCESS_CODE, a gateway or owner auth methods first. - Earlier runtime sessions are not migrated.
- If the token was your only access gate, put the deployment behind
-
Assets belong to an owner.
ASSET_QUOTA_BYTESis a per-owner limit. -
Interrupted courses are not resumed. Courses interrupted in the browser before 1.2.0 show their remaining scenes as interrupted.
-
Embedders.
@openmaic/storage0.32–0.37 changes:- document ownership moves to the
documentOwnershiprelation; - the browser storage seams have no IndexedDB fallback;
ServerPersistenceProvider.documentStoreis removed.
- document ownership moves to the
Before you upgrade
- Back up the database. The first start runs the schema migrations. On a large
document_stagestable, it builds an index under a write lock; you can build that index concurrently beforehand (see the full notes). - Rolling back to 1.1.x needs either the ownership copy-back SQL (under Breaking Changes in the full notes) or that backup.
- Set
OPENMAIC_SECRET_KEYwhen several replicas share the database, whendata/does not survive a restart, or when the working directory is read-only. Otherwise back updata/instance-secret.keytogether with the database. - Choose an identity mode: single-user, a shared team owner, anonymous, or host auth.
- Keep
data/classrooms. Classrooms stored there are imported once, in the background. - Check which capabilities will run. With the legacy configuration, the first configured provider of each kind becomes the server default. Course research then runs whenever web search is configured, and headless jobs use every configured capability. To turn one off for everybody, set its slot to
nulland list it inlock. - Connect PostgreSQL directly or through a session pool. A transaction-mode pooler (PgBouncer
pool_mode = transaction) is not supported. - Follow the guide. The deployment guide's "Upgrading from 1.1.x" table lists every step.
Known issues
- Web-search services in Settings → Model Services have no Test connection button.
- A token plan connected with an invalid key shows as connected; the error appears only when a course is generated.
- A very short requirement can drift off topic or ignore an explicit slide count.
Full change notes
Breaking Changes
- Server-backed persistence is always on. Courses, folders and folder membership, chat history and learner runtime, and generated media are stored on the server through
/api/persistence; the browser has no storage backend of its own any more. The build-timeNEXT_PUBLIC_PERSISTENCEswitch is removed (from the client, the Dockerfile anddocker-compose.yml) and ignored. The server now requiresDATABASE_URLand exits at startup without it ([boot] Invalid server configuration; the server will not start: DATABASE_URL is not set. ...);pnpm db:up/pnpm db:downstart and stop a separate development database (the Composepostgresservice definition under its own project and volume,openmaic-dev-db), published on127.0.0.1(OPENMAIC_DB_PORT, default5432), for local development; other deployments pointDATABASE_URLat a PostgreSQL database they run. Only device-local state stays in the browser (settings, playback position, the editor's current scene and undo history, a local cache of media the server already stores, and browser voice profiles), in a newmaic-device-cacheIndexedDB database; Settings → Clear Local Cache clears exactly that. Courses an earlier browser-only build stored in the browser are not deleted; the one-way importer below moves them to the server. - Docker Compose:
docker compose upnow starts PostgreSQL (no profile) and a server-backed app (DATABASE_URLset fromPERSISTENCE_POSTGRES_PASSWORD) that waits for PostgreSQL to be healthy, in single-user mode (docker-compose.defaults.env, read before.env.localso it can be overridden there). The app port is published on127.0.0.1only; start with `O...
OpenMAIC v1.1.2 — Security
A security release. Server-side requests to provider URLs that a caller can choose now connect only to the addresses that passed validation and refuse redirects, and error responses no longer carry provider response bodies or connection details. Read Behavior Changes before upgrading.
Security
- Provider connections: when a provider is not configured on the server, the settings UI can supply its own base URL, endpoint or model. Several routes validated such a URL once and then connected with a transport that resolved DNS again or followed redirects: PDF parsing and connectivity checks, the Azure voice list, model listing, image and video providers, and LLM calls. Some of these routes also echoed provider response bodies or connection errors back to the caller. This allowed requests to internal addresses and probing of internal services. These requests now go through the strict provider transport, which pins every connection to validated addresses and refuses redirects. IP-literal hosts and the built-in default URLs of unmanaged providers are held to the same policy. Caller-facing errors are fixed text. Client-supplied AliDocMind endpoints must be official hosts. GHSA-g87c-cm4q-cw5x #1704
- Classroom media generation downloads provider-returned image and video URLs through the strict provider transport: HTTPS public addresses only,
data:URLs decoded locally, and size bounded while streaming #1692 (by @Yi-111-a). Agent-runtime image and video tools now do the same #1704.
Behavior Changes
- A caller-supplied LLM, image/video, model-list, PDF-check or self-hosted MinerU base URL that answers with a redirect is refused instead of followed. Configure the final URL.
- A caller-supplied provider base URL containing a query string or fragment is refused.
- A caller-chosen loopback or private address, including an IP literal or an unmanaged provider's built-in
localhostdefault (Ollama, Lemonade, VoxCPM), needsALLOW_LOCAL_NETWORKS. Configure the provider on the server to keep it operator-managed. - Server-configured providers (LLM, image/video, TTS/ASR, MinerU, MinerU Cloud) may use local network addresses without
ALLOW_LOCAL_NETWORKS. Cloud metadata and reserved ranges stay blocked, and redirects from them followALLOW_LOCAL_NETWORKS. - A client-supplied AliDocMind endpoint must be an official
docmind-api.<region>.aliyuncs.comhost over HTTPS; other endpoints answer403 INVALID_URL. Server-configured endpoints are unchanged. - Provider check and generation errors are fixed messages without the provider's response text or connection errors:
/api/verify-pdf-providersuccess no longer includesstatus;/api/azure-voicesanswers provider failures with502;/api/provider/probe-modelsreports other HTTP failures as502with the status class only;- LLM errors for a client-selected endpoint read
Cannot connect to API: connection failed(orrequest timed out,redirects are not allowed) or the HTTP reason phrase; - MinerU Cloud errors report the HTTP status or numeric code.
- Agent-runtime video and poster downloads require HTTPS.
- Pinned provider requests connect directly and do not use Node's environment proxy (
NODE_USE_ENV_PROXYwithHTTP_PROXY/HTTPS_PROXY). - A provider id that names an inherited object property (such as
constructor) is no longer treated as server-configured.
OpenMAIC v1.1.1 — Security
A security release. One advisory is published with this release. There are no other changes since 1.1.0.
Security
- MinerU Cloud parsing fetched provider-supplied URLs without the address policy. The presigned upload URL and the result ZIP URL returned in MinerU Cloud's JSON responses were fetched with a plain
fetch: no SSRF validation, redirects followed unchecked, and no size limits. When MinerU Cloud is not configured on the server, a caller can supply its own base URL, so its endpoint could point the server'sPUTof the uploaded document and the result download at loopback, private or other internal addresses. Every MinerU Cloud request now goes through the strict provider transport, which validates each redirect hop and connects only to the addresses the guard validated. The upload and ZIP URLs from the response must be HTTPS public addresses under every policy, and the upload does not follow redirects. Address-policy refusals are not retried. JSON responses, the ZIP download and each decompressed entry are size-bounded, with decompression stopped as soon as a limit is crossed. The configured API root keeps the operator'sALLOW_LOCAL_NETWORKSpolicy, so self-hosted setups are unaffected. The shared SSRF guard now also classifies IPv4-compatible IPv6 addresses (::/96) by their embedded IPv4. GHSA-cpjc-vgjh-c5jp — reported by @AbelWangYaBo (#1688)
Upgrade: deployments that let users bring their own MinerU Cloud base URL should upgrade. Deployments that configure MinerU Cloud on the server are not exposed through this path.
Full Changelog: https://github.com/THU-MAIC/OpenMAIC/blob/main/CHANGELOG.md
OpenMAIC v1.1.0 — Classroom chat on an agent loop
Classroom chat now runs on an agent loop by default: learners can point at a slide element, an interactive component or a whiteboard drawing and ask about it, and the teacher can read the lesson, check the live state of an interactive experiment and search the web before answering. Settings are reorganized around the course workflow, with a model choice per generation step and first-class Token Plan connections (TokenDance, MiniMax, Seed and Kimi). Read Behavior Changes before upgrading.
Highlights
- Pi classroom chat is the default. The in-class conversation moves from the director graph to an agent loop that can read slides on demand, search the web and call classroom tools within a single answer #1628 #1637
- Ask about what you're looking at. Reference a single PPT element, an interactive component or a whiteboard element from the playback bar and ask about it; interactive pages that declare state are sampled at question time, so the teacher can explain the result the learner is actually seeing, and
read_sceneexposes an interactive page's static instructions #1508 #1632 #1656 - Settings, rebuilt around the course workflow. Choose a model for each generation step (outline, slides, interactive pages, scene actions and more), toggle each capability on or off, and manage Token Plans in one place #1644
- Token Plans. One-key presets for TokenDance (every modality) and the Kimi Coding Plan (text only; other modalities stay on your own providers) #1525 #1664
Features
- Models: add OpenRouter image and video providers #1356, Gemini 3.8 Flash and 3.7 Flash #1629, and Xiaomi MiMo V2.6 #1655
- TTS: pace classroom narration requests and classify MiniMax RPM limits so rate-limited runs slow down instead of failing #1650; auto-detect Vietnamese for browser-native narration #1487
- Storage: workbench image and video generation write through the asset pool (#1007 part 6) #1524; ZIP imports persist media in the server asset pool #1520
- Persistence: optional single-tenant mode that resolves every request to one shared owner (
PERSISTENCE_SHARED_OWNER_ID) #1639 - Render service: admission control and per-task resource budgets #1492
- Attribution: TokenDance gateway requests carry an
X-APP-URLheader identifying the OpenMAIC deployment #1675
Bug Fixes
- Generation: reject quiz options whose values are not A–Z and constrain them at the source #1651; reject unusable interactive scripts and surface runtime errors on the page #1649; keep narration speech free of formulas and LaTeX #1586; tolerate non-array
mediaGenerationsin outlines #1469; add a browser-safe package entry #1609; stabilize model picker teardown #1618 - Playback and audio: mobile narration survives past the first segment and discussion lines reuse one media element #1477 #1610; stop superseded scene engines #1510; queue widget messages until the iframe is ready #1532; resolve CDN-backed narration consistently #1521; keep refused narration instead of re-billing it #1523; derive the Azure SSML locale from the selected voice #1566; rebuild FormData bodies for the undici transport #1580
- PPTX import and editor: preserve tab columns, text insets, arrows, text/chart/image styling, shape autofit, Wingdings checkmarks, diagonal corners, table typography and punctuation wrapping; include every color attribute in the style cache key; share line bounds for alignment and dragging; bound ZIP inflation by default #1518 #1534 #1577 #1581 #1571 #1631 #1588
- Media and web search: refuse redirects on adapter generation and poll calls #1636; keep long Grok relay generations alive and inline image bytes #1364; emit keyframe images as data URLs #1444; stop leaking Brave's HTML challenge page into errors #1553; bound the model-discovery response body timeout #1478
- Export: surface video render rejection reasons #1414; include active line geometry in bounds #1626
- Server and storage: validate
pdfContentinput #1578; sanitize agent session text #1504; correlate 5xx responses with request IDs #1601; warn when access-code protection is disabled #1599; show effective upload limits in errors #1418 - Docker: create
/app/dataowned by the runtime user so classroom persistence works #1442; build workspace packages in the builder stage #1598 - Misc: send
taskEngineModeon the on-demand vocational scene path #716; POSIX zip entry names for exported skills on Windows #1641; i18n and persistence fixes #1595 #1596
Behavior Changes
- Pi is the default classroom chat runtime. To keep the legacy director-graph chat, build with
NEXT_PUBLIC_PI_CHAT_ENABLED=false#1628 - Stricter generated content. Quizzes whose option values are not A–Z and interactive pages with unparseable scripts are now rejected as invalid model output and retried or skipped by the existing path, instead of being saved broken #1651 #1649
- Settings layout. The web-search toggle moved from the generation toolbar into Settings; an existing preference is migrated once on first load #1644
- Courseware references are opt-in. The playback-bar reference entry (PPT, interactive and whiteboard) is enabled with
NEXT_PUBLIC_COURSEWARE_REFERENCE_ENABLED=true#1656
Other Changes
- Docs: align security and behavior claims with shipped code, and document the Docker builder heap limit #1592 #1607
- Refactors and CI: shared per-course session lifecycle, shared narration walk for export, MIME policy from the format registry, Node 24 publish actions, Windows-safe media tests #1619 #1621 #1590 #1569 #1584 #1615
Contributors
Thanks to the community contributors in this release: @AbelWangYaBo, @acse-bq23, @Ai-Eastern, @BeAIcoder, @Cham1229, @ciclou1, @dajiaohuang, @Duang777, @Hosuke, @HuntercodeT, @hydraxman, @LeoParkerOu, @lianglaibin116-cloud, @ly-wang19, @mianbaofang, @nqthiep, @PassCode023, @puxiao, @Qnh233, @ttkm2023, @WizKid1968, @YizukiAme, @zdnemz.
OpenMAIC v1.0.3 — Security
A security release. Three advisories are published with this release, and Next.js is upgraded to patch a critical remote code execution. It also carries the fixes and features merged since 1.0.2.
Security
- Access-code tokens never expired, and verification was not throttled. Verification tokens (
timestamp.HMAC) were accepted regardless of age because neither verifier checked the timestamp, andPOST /api/access-code/verifyhad no attempt throttling. Both verifiers now enforce a 7-day server-side lifetime and reject non-canonical signatures, and verification is rate-limited per client whenTRUST_PROXY_HEADERS=true; without a trusted proxy the app cannot attribute requests to a client, so a long randomACCESS_CODEis the protection and a warning is logged when it is short. GHSA-qpmr-534w-hhpg — reported by @CaptBoykin (#1513) - The render service ran untrusted HTML in headless Chromium without a network policy. On the
/previewand/renderpaths the packager's Content-Security-Policy was not applied, so inline script could reach loopback and internal addresses, and on/renderthe response was painted into the returned MP4. Both paths now inject a first-parsed CSP, the preview frame is additionally guarded by request interception, and framed same-origin.svg/.xhtmldocuments are sanitized. In the shipped image the container's egress lockdown already limited the reachable surface to loopback; deployments that disable it or run the service unisolated were exposed. GHSA-vqq3-22q7-289w — reported by @CaptBoykin (#1512) - Audio provider requests followed redirects and re-resolved DNS unvalidated. TTS, ASR, voice registration and voice cloning validated a client-supplied base URL once and then issued a plain fetch, so a redirect or a DNS-rebinding answer could reach an internal address. These requests now validate every redirect hop and connect only to the addresses the guard validated, on every hop; a client base URL can never reach a private, loopback or cloud-metadata address, even with
ALLOW_LOCAL_NETWORKSset. GHSA-9p8q-rcmg-pmjw — reported by @CaptBoykin (#1514) - Next.js upgraded to patch a critical RCE. Bumped from 16.2.11 to 16.3.3, which patches an unauthenticated remote code execution on Windows-hosted servers (GHSA-p293-qw3h-jr36 / CVE-2026-75604). (#1503)
Features
- Storage: the server owns the asset entry lifecycle and releases assets on course deletion. (#1472, #1473)
- Skills: add an inquiry-based exercise-class teaching skill grounded in the zone of proximal development. (#1382)
Bug Fixes
- Importer: resolve embedded PPTX videos when the legacy link points at NULL, and upload video posters through the configured callback (
@openmaic/importer0.2.1). (#1507) - Storage: keep jsonb writes valid when model output contains NUL or lone surrogates (#1499); allow one owner material to be bound to multiple sessions (#1500).
- Classroom: render a transient server error as a retryable state instead of the terminal "course does not exist" card, on both the pane and the standalone route. (#1485)
- Upload: resolve the generic Office MIME (
application/vnd.ms-office) via the filename extension. (#1498) - Settings: maintain the ASR language state invariant on provider selection. (#1443)
- TTS: treat a custom provider's Add-dialog default base URL as a configured credential path so generation narration is not skipped. (#1482)
- Export: tolerate malformed authored CSS in classroom exports instead of dropping later assets. (#1422)
- Render service: preserve plan audio during chunk assembly. (#1358)
- Docker: enable the Pro workbench flag in Docker builds and allow a non-TLS localhost cookie. (#1484)
Other Changes
- Docs: document the deployment assumptions and pre-report checks in the security policy. (#1511)
- Tests: isolate the image URL-guard test environment so it no longer inherits the generic OpenAI fallback. (#1476)
Full Changelog: https://github.com/THU-MAIC/OpenMAIC/blob/main/CHANGELOG.md