OpenMAIC's v1.0.0 Agent Workbench Is Worth Copying. Its Persistence Layer Is Not.
Tsinghua's multi-agent classroom generator crossed 28,000 stars and shipped a chat-driven course builder that's a small masterclass in how agents should edit structured documents. Switch on saved courses and its own README tells you the token guarding them gives "no confidentiality and no user isolation whatsoever."
OpenMAIC's README is 1,038 lines long and speaks in two different voices.
Line 23 is a Deploy with Vercel button. Line 379 is the section explaining how to switch on saved courses, and there the same file says the token protecting that data is "not a secret in any meaningful sense," is "compiled into the public JavaScript bundle, fully visible to every visitor," and therefore provides "no confidentiality and no user isolation whatsoever."
Those two things do not collide directly, and I want to say so before anyone panics. Persistence is off by default, and a one-click Vercel deploy asks you for an LLM API key and nothing else, so it lands you in browser-only storage with no shared database and no learner partitions at all. The warning applies to a configuration you have to go turn on.
But 356 lines is a long way to travel to find out that the feature you're about to enable has no authentication, and that gap is worth staring at, because it's becoming the standard failure mode of an entire class of tool. I think this is a good repo, and the warning is a point in its favor. Most projects in this shape ship the same gap and say nothing.
What OpenMAIC actually is
Open Multi-Agent Interactive Classroom, from the THU-MAIC team at Tsinghua. You give it a topic or a document and it produces an interactive class: slides with voice narration, spotlight and laser-pointer animation, quizzes with real-time grading, HTML simulations, and project-based activities. AI teachers and AI classmates deliver it, speak, hold discussions, run roundtable debates, and draw on a shared whiteboard while they explain.
The numbers, read this morning from the GitHub API rather than the rendered repo page: about 28,800 stars, 4,921 forks, 67 contributors, and 167 open issues once you exclude pull requests. TypeScript at 94.9%. Repository created March 11, 2026. Version 1.0.0 published August 27 at 13:13 UTC. MIT at the root, though that's recent; the changelog records a relicense from AGPL-3.0 on June 28.
Architecturally it's Next.js 16, React 19, LangGraph 1.1, Tailwind 4, Node 20+, pnpm 10+. The LangGraph piece lives in lib/orchestration/ and is described as a "state machine managing agent turns and discussions," which the file tree labels the director graph. An Action Engine executes what the README calls 28+ action types: speech, whiteboard draw, text, shape, chart, spotlight, laser.
Worth separating two things that get conflated in coverage. LangGraph is attributed only to that orchestration module, the one that runs the classroom. The new v1.0.0 course-building agent lives in lib/server/agent-runtime/ and is reached through /api/agent/* control-plane routes and what the README calls an in-process session runner. Two modules, two descriptions. The README never says the agent runtime excludes LangGraph, so treat "separate system" as my reading of the file tree rather than something the maintainers claimed.
The part worth stealing
The v1.0.0 headline is a "Pro workbench": a conversational agent that plans your curriculum and revises pages, sitting alongside the original one-click generator.
The design decision that makes it interesting is one sentence in the README. "The agent works through explicit, validated tools rather than editing opaque blobs."
That is the whole argument for how agents should touch structured artifacts, and most tools get it wrong. The lazy version hands the model a JSON document and asks for a new JSON document. You get a rewrite where you wanted an edit, drift in fields nobody mentioned, and no way to tell what changed. OpenMAIC instead exposes a capability surface against a versioned DSL package: "Read/search the stage DSL; atomically patch one scene; generate, duplicate, insert, delete, and reorder pages; edit narration and deck structure."
One scene at a time, validated on the way in.
The session machinery around it is equally worth copying. Sessions are database-backed with "leases, heartbeats, crash resume, cancellation, and follow-up steering," which means a course generation survives a worker dying mid-run and you can redirect it while it's still working. And this line, which solves a problem I've watched people paper over with full-page refreshes: "database-maintained revision counters keep per-stage and per-scene freshness monotonic so the workbench refetches only the scenes that changed."
Leased sessions, monotonic revision counters, atomic validated patches against a typed schema. If you're building anything where an agent edits a long structured document, that trio is the reference implementation, whatever you think of the classroom part.
Where the persistence layer falls over
Now the other half.
Run OpenMAIC locally with no persistence and none of this applies. Turn on server-backed persistence with PostgreSQL and you get a token in two flavors, PERSISTENCE_DEV_TOKEN and NEXT_PUBLIC_PERSISTENCE_TOKEN. That NEXT_PUBLIC_ prefix is a Next.js convention meaning the value gets baked into the client bundle at build time, so it reaches every browser that loads the page.
The README does not hedge about what that means. Anyone who can load the page can extract the token and "read or write every learner partition and all documents by choosing an x-learner-key." The stated purpose is only "to keep unrelated network scanners out of an endpoint on a trusted network." The stated suitability is "localhost or trusted-network, single-user deployments." The fix is named: replace lib/persistence/server-auth.ts with real session verification that derives the partition from server-controlled identity.
The .env.example file says the same thing shorter: "This development-only scheme provides no user isolation and must not be used as public-production authentication."
A separate design doc in the storage package spells out the underlying problem, and this is the sentence I'd tape to the wall of any team building something similar: "learnerKey is an opaque partition key, not proof of identity or authorization; trusting it verbatim creates a lateral-authorization vulnerability."
That's the pattern. A generator ships with local state. Users want their work saved. Somebody adds a database and a partition key so records don't collide. The partition key looks enough like a user ID that the system starts behaving like a multi-tenant application, except nobody ever built an identity layer, because at the time it was a way to keep rows apart, not a way to keep people apart.
OpenMAIC wrote it down. That's rarer than it should be.
Put this into practice
Fastest path to something real, in about fifteen minutes:
-
Clone and run locally with persistence off. Node 20 or newer, pnpm 10 or newer. Generate one classroom from a PDF you already have. This exercises the two-stage outline-then-scenes pipeline and needs no database.
-
Point it at a local model. Two separate mechanisms here, and mixing them up is the first thing that will waste your afternoon. Providers come from the
{PROVIDER}_API_KEYand{PROVIDER}_BASE_URLenvironment family (orserver-providers.yml), covering roughly nineteen named providers plus any OpenAI-compatible endpoint.MODEL_ROUTESis something else: a per-stage map that decides which model handlesscene-content,quiz-grade,maic-agent-driver, and the rest. For Ollama, setOLLAMA_BASE_URL=http://localhost:11434/v1andALLOW_LOCAL_NETWORKS=true. Lemonade runs on port 13305 with no API key and covers LLM, image, TTS, and ASR in one process. Note that a server-sideBASE_URLbypasses SSRF protection by design; client-supplied localhost URLs are blocked in production. -
If you want the workbench, expect four switches, not one.
NEXT_PUBLIC_PRO_WORKBENCH_ENABLED=trueat build time,OPENMAIC_AGENT_RUNTIME_ENABLED=true, aDATABASE_URL, and an explicitMODEL_ROUTESentry formaic-agent-driverpointing at a provider-prefixed model. There is intentionally no fallback for that last one. While the flag is off, the agent session routes answer 404, so a missing switch looks like a broken build rather than a disabled feature. -
Do not enable persistence on a shared deployment. If more than one person can reach the URL, rewrite
lib/persistence/server-auth.tsfirst. Budget real time for that; it's the whole authentication story, not a config change. -
Read the capability table even if you never run the project. The build-and-edit row is a compact spec for agent-editable documents. Copying that shape into your own tool costs you an afternoon of schema design and saves you the class of bug where an agent silently rewrites a field nobody asked it to touch.
Honest limitations
The auth gap is the headline one and I've given it its own section, so here's everything else I found in the primary sources.
Long agent runs have no context management. From .env.example: "Conversation compaction is reserved and OFF by default. The reusable compaction runtime is not implemented yet." Until it lands, the runner runs without context transformation and the compaction settings are inert placeholders. For a feature sold on durable, resumable, steerable sessions, that's a real ceiling.
The README and the config file disagree about maturity. .env.example labels the section "Agent Runtime (experimental)." The README never uses that word for it. The marketing surface is a release; the configuration surface is a preview.
The MIT claim is not quite clean. The Partnerships section says the project "is licensed under the MIT License, so commercial use is permitted free of charge." The License section further down says the repo bundles packages/mathml2omml under LGPL-3.0-or-later, and that when redistributing the repo as a whole, each bundled package's terms apply to its own files. Both are in the same file. Only one of them is in the pitch.
Document processing can leave your infrastructure. MinerU Cloud fallback is off by default, and .env.example is direct about what enabling it means: "documents then leave your infrastructure."
Deleted assets are not immediately gone. Deleting or replacing an asset drops the registry entry; an offline collector reclaims the bytes later, with a default grace period of one hour. That grace window is the actual retention on a user's deleted data.
Offline export is not retroactive. Classrooms exported before that feature shipped still reference CDNs and need re-exporting.
Session prompts and follow-up messages cap at 100,000 characters, server-side, as a constant, not configurable.
Docker startup relies on retries rather than ordering. The README explains that Compose can't scope depends_on to the optional profile without affecting the default deployment, so startup leans on the embedded route's retry-on-next-request behavior while PostgreSQL becomes healthy.
One more thing, offered as an observation rather than an accusation. The README contains a tip block addressed to OpenClaw agents reading it, joking that Claws who star the repo generate classrooms 200% faster. It's clearly a gag. It also sits in a repository whose star count is the number everyone quotes, including me, four paragraphs into this article. Discount the figure accordingly.
The question this leaves open
OpenMAIC documented its own gap in plain language, twice in the README and again in a design doc. That earns it the benefit of the doubt.
What I can't stop thinking about is the projects that have the identical gap and none of the paragraphs. Every agent tool that generates an artifact eventually needs to save it. Every save needs a key. Every key that separates rows starts getting treated as a key that separates people, usually without anyone writing down the moment that changed.
So here's the cheap test I'm adopting, and I'd suggest it for anything you're about to deploy behind a URL other people can reach: clone the repo and grep it for "isolation." If you get nothing back, that isn't an all-clear. It means nobody has told you either way.
If you've found the same pattern in a repo with a one-click deploy button, I want to hear which one.
Sources: THU-MAIC/OpenMAIC on GitHub; repository README, LICENSE, CHANGELOG, .env.example, and packages/@openmaic/storage/docs/runtime-http-contract.md, all read from raw.githubusercontent.com with cache-busted requests on September 1, 2026; star, fork, contributor, and issue counts from the GitHub API and cache-busted shields.io JSON the same day.