Mix Space Core: an AI-powered headless CMS you run yourself
AI-powered CMS core for personal blogs and creator websites, with AI summaries, translation, moderation, and writing workflows.
At a glance
- What is it?
- Mix Space Core is the NestJS server at the centre of the Mix Space stack, pairing a self-hosted blog CMS with AI summaries, translation and moderation. This review covers how it installs, where its architecture gets complicated, and who should stay away.
- Who is it for?
- Adopt Mix Space Core if you are comfortable running PostgreSQL, Redis and a Docker Compose stack, and you want AI summaries, translation and moderation attached to a blog you control. Do not adopt it if you expect a single binary, a managed database, or permissive licensing for a closed-source product: the README describes the licence as AGPLv3 plus MIT with an ADDITIONAL_TERMS.md, and the package.json lists AGPLv3 alone.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What Mix Space Core actually solves
Most blogging tools assume you will write, publish and move on. Mix Space Core assumes the opposite: that a personal site accumulates years of posts, several languages and a comment section that needs watching. The repository describes it as an AI-powered headless CMS for personal blogs, creator homepages and content websites, and the topics list names the specific jobs: ai-summary, ai-translation, tts, content-workflow.
The audience is narrow and identifiable. You are one person, or a very small group, running a site under your own domain, and you want the AI features to live next to the content rather than in a separate service you have to wire up. The stack is opinionated about that: PostgreSQL and Redis are required, not optional, and the admin dashboard is built into the server and served at /proxy/qaqdmin rather than deployed separately.
What it is not is a hosted product. There is no homepage field in the repository metadata, and the README points to per-app READMEs for setup and operational docs. If you want someone else to run the database and patch the server, this is the wrong shape of project entirely.
How the monorepo is put together
The repository is a pnpm workspace, not a single application. apps/core is the NestJS server using Fastify, PostgreSQL and Redis. apps/admin is a React 19 dashboard SPA. apps/ios is a native client built with XcodeGen. apps/push-relay is described as an independently deployable, privacy-preserving APNs relay, and apps/telemetry is an anonymous instance-telemetry collector running as a Cloudflare Worker with D1.
The data flow the README diagrams is worth reading closely. Frontends such as Yohaku talk to the core through @mx-space/api-client. The admin SPA goes through /proxy/qaqdmin. The iOS client uses an OpenAPI client. For push, the core sends only a comment id to the relay, and the relay talks to APNs. That is a deliberate separation: the relay never sees comment content, which is what the phrase privacy-preserving is doing in the description.
The packages directory holds the shared contracts. @mx-space/ai carries SSE event unions used by both server and clients, @mx-space/push-protocol is versioned and shared between the core and the relay, and @mx-space/webhook is a signature-verified handler SDK. @mx-space/mongo-pg-cli is a one-shot migration tool for moving v11 MongoDB data to v12 PostgreSQL. The presence of that package tells you something about the project's history: it changed database engines, and the migration path is shipped rather than documented as a manual exercise.
Installing Mix Space Core and starting the dev server
The README gives a Quick Start for local development. Node.js 22.12.0 or newer is required according to the engines field, and the package manager is pinned through Corepack. The first two commands enable Corepack and install the workspace:
corepack enable
pnpm installNext, bring up the dependencies. The repository ships a docker-compose.yml that defines PostgreSQL and Redis for development, and the README calls them by service name:
docker compose up -d postgres redisWith those running, the core dev server starts on port 2333. The admin SPA runs alongside it on port 9528, in a second terminal:
pnpm dev
pnpm dev:adminThe README states the core dev server is reachable at http://localhost:2333 and the admin SPA at http://localhost:9528. For anything beyond local work, the repository provides docker-compose.server.yml as a production deployment template and a multi-stage dockerfile. The production compose file pulls innei/mx-server:latest, mounts ./data/mx-space into /root/.mx-space, publishes 2333, and health-checks against http://127.0.0.1:2333/api/v3/ping every 90 seconds.
Configuration comes from environment variables. The .env.example is explicitly labelled as being for Docker Compose and lists JWT_SECRET, ALLOWED_ORIGINS, ENCRYPT_KEY, ENCRYPT_ENABLE, MX_PUSH_RELAY_ORIGINS, CDN_CACHE_HEADER, FORCE_CACHE_HEADER, PG_URL, THROTTLE_TTL and THROTTLE_LIMIT. The ENCRYPT_KEY comment says it must be 64-bit, and ENCRYPT_ENABLE defaults to false. The compose file supplies its own defaults for the database, Redis and snowflake worker id, so a local stack needs little beyond a JWT secret.
The migration step that gates startup
The most consequential detail in the deployment files is how migrations run. They do not run on boot. The compose file defines a separate mx-migrate service using the same image with the command node migrate.mjs, and the app service declares depends_on with condition: service_completed_successfully. If the migration container exits non-zero, the application container does not start at all.
The comment above that service explains why: mx-migrate boots a full Nest context because it runs both schema migrations through Drizzle and app-data migrations through a Nest-bootstrapped registry, so it needs the same configuration the runtime app needs, including Redis, the snowflake worker id and the JWT secret. That is why the compose file defines a shared x-mx-env anchor rather than giving each service its own environment block.
This design is defensible and also a real operational constraint. A failed migration leaves you with a stopped app rather than a running app against a half-migrated schema, which is the safer failure. But it means the migration container is on the critical path for every deploy, and a missing environment variable in the migration service will look like a failed deployment rather than a configuration error. The README notes that upgrade notes live in the core README under Upgrading; the top-level README does not document rollback.
API conventions and the guards that enforce them
The README specifies a response envelope: success returns { data, meta? } and errors return { error: { code, message, details? } }. Code is camelCase end to end, while the wire format is snake_case. That is a small decision with a large consequence for anyone writing a client, because it means the boundary between internal and external naming is enforced rather than incidental.
What makes this more than a style note is that the repository enforces it. The root package.json defines check:controller-response-envelope and check:validate-false-paired, both run through tsx, and the typecheck script chains them before the core typecheck. So pnpm typecheck fails if a controller returns a shape that does not match the envelope, or if validation decorators are paired incorrectly. There is also check:ai-translation-hash, which suggests the AI translation pipeline has a hash check that can be verified in CI.
This is the part of the project I would point a sceptical reader at. Plenty of CMS projects document a convention and then drift from it. Here the convention has a script attached, and the script runs in the same command a contributor already runs before pushing.
Where Mix Space Core is the wrong choice
The licence is the first thing to check and the least clear thing in the repository. The README's badge and License section say AGPLv3 plus MIT and point to ADDITIONAL_TERMS.md. The root package.json lists "license": "AGPLv3" with no mention of MIT. Both files are in the repository, so both are real, but they do not say the same thing, and the repository metadata reports the licence as NOASSERTION. If you are evaluating this for anything commercial, read LICENSE and ADDITIONAL_TERMS.md together, and treat the discrepancy as something to resolve before you build on it rather than after.
The second constraint is the dependency surface. PostgreSQL and Redis are both required, the migration runs as a separate release-phase container, and the production compose file expects a writable volume at ./data/mx-space. That is a normal shape for a self-hosted application and an awkward one for anyone who wanted a single process with an embedded database.
The third is scope. The monorepo ships an iOS client, a push relay and a telemetry worker. You do not have to deploy the relay: MX_PUSH_RELAY_ORIGINS is empty in the example env file, and the core only contacts origins you list. But the repository is organised around the full stack, and the README directs you to apps/core for the server's own documentation. Expect to read more than one README to understand a deployment.
How it compares with a static site generator plus a separate AI service
The obvious alternative for a personal site is a static site generator such as Hugo or Astro, with content in Git and AI features bolted on through a separate script or API call at build time. The difference in approach is where the content lives and when work happens.
With a static generator, the post is a file, the AI summary is produced by a build step you write yourself, and the published site is a directory of HTML. Nothing runs at request time, and there is no database to back up. With Mix Space Core, the post is a row in PostgreSQL, the AI features are part of the server, and the admin dashboard is a running application served at /proxy/qaqdmin. Summaries, translation and moderation happen against live content rather than against a build artefact.
That trade is not a matter of one being better. If your site is mostly static prose and you publish a few times a month, the database and the migration container are overhead you will pay for continuously. If you want comment moderation, push notifications to a native client, and AI translation tied to the same content records, a static pipeline means rebuilding all of that yourself. The @mx-space/ai package exists precisely because the SSE event contracts for those features are shared between server and clients, which is work a static site does not have to do.
Maintenance, releases and upgrade cost
The repository is not archived, and the last push was on 2026-09-14. Three releases landed that same day: v14.12.4, v14.12.3 and v14.12.2, all within roughly three hours of each other. That release cadence is worth noting for what it implies about upgrades: patch versions arrive frequently, and the version number in the compose file is latest, so a redeploy pulls whatever was published most recently.
If you pin to latest, you inherit that cadence. The mitigation is in the repository's own structure. Migrations are forward-only SQL run as a one-shot release-phase step, and the compose file makes the app wait for them, so an upgrade is a pull plus a restart plus a migration that either succeeds or stops the app. The README points to the core README's Upgrading section for the details; the top-level README does not describe a downgrade path, and the mongo-pg-cli package is a one-shot v11 to v12 tool rather than something you would run twice.
The practical cost is that you should test the migration container against a copy of your data before pointing it at production. That is not generic advice here: mx-migrate needs the same environment as the app, including Redis and the snowflake worker id, and it exits before the app starts. A dry run against a restored database is the specific thing that tells you whether an upgrade will succeed.
Editorial conclusion
Adopt Mix Space Core if you are comfortable running PostgreSQL, Redis and a Docker Compose stack, and you want AI summaries, translation and moderation attached to a blog you control. Do not adopt it if you expect a single binary, a managed database, or permissive licensing for a closed-source product: the README describes the licence as AGPLv3 plus MIT with an ADDITIONAL_TERMS.md, and the package.json lists AGPLv3 alone. Before committing, read apps/core/README.md for the deployment and upgrading steps, confirm which of the two licence files governs your use, and check that the mx-migrate service completes against a copy of your data, because the app container will not start until it exits successfully.
Frequently asked questions
What is Mix Space Core and who is it for?
It is the NestJS server at the centre of the Mix Space stack, described in the README as an AI-powered headless CMS for personal blogs, creator homepages and content websites. It is aimed at people running their own site who want AI summaries, translation and moderation attached to their content, and it requires PostgreSQL and Redis.
How do I install Mix Space Core?
The README's Quick Start runs corepack enable and pnpm install, then docker compose up -d postgres redis, then pnpm dev for the core server on port 2333 and pnpm dev:admin for the admin SPA on port 9528. Node.js 22.12.0 or newer is required according to the engines field.
Why does the Mix Space Core container fail to start after an upgrade?
The production compose file defines an mx-migrate service that runs node migrate.mjs, and the app service depends on it with condition: service_completed_successfully. If the migration exits non-zero, the app does not start, so a missing environment variable in the migration service looks like a failed deployment.
What licence does Mix Space Core use?
The README's License section says AGPLv3 plus MIT and points to ADDITIONAL_TERMS.md, while the root package.json lists "license": "AGPLv3" and the repository metadata reports NOASSERTION. Read LICENSE and ADDITIONAL_TERMS.md together before relying on either description.
Does Mix Space Core send my comment data to Apple's push service?
The README's architecture diagram shows the core sending only a comment id to the Push Relay, which then talks to APNs, and the relay is described as privacy-preserving. The core contacts relay origins only if you list them in MX_PUSH_RELAY_ORIGINS, which is empty in the example env file.
Community notes