pre-alpha·MIT licensed

A modern PHP engine.
Built from scratch.

Minn fluently speaks with WordPress sites: the same database, the same file layout, the same REST API and WP-CLI verbs. Hosting tools, backups, migrations, and plugins keep working. The code underneath is new, small, and yours to read.

Reads a WordPress database as-is Untouched wp-config.php wp/v2 REST and WP-CLI Minn Admin boots unmodified Diffed live against real WordPress
tests/run-all.sh  ·  engine vs reference, same database
Minn the engine
GET/wp-json/wp/v2/posts?context=edit200 · identical
POST/wp-login.php302 · cookie accepted by both
GET/sample-page/200 · body identical
GET/feed/200 · byte for byte
GET/wp-sitemap.xml200 · identical
CLIwp option get siteurlidentical
WordPress the reference, same DB
GET/wp-json/wp/v2/posts?context=editthe oracle
POST/wp-login.phpthe oracle
GET/sample-page/the oracle
GET/feed/the oracle
GET/wp-sitemap.xmlthe oracle
CLIwp option get siteurlthe oracle
8,000+ checks green. Every surface is pinned by a captured fixture and diffed live, request by request, against a running WordPress on the same database. Any divergence is a finding.
276
classes in the Minn\ namespace. A clean-room reimplementation
8,000+
parity checks across 46 suites, run against real WordPress on the same database
0
Composer packages. Strict-typed PHP, no framework, no build step
1
admin, already built. Minn Admin boots on the engine unmodified
Already on WordPress?

Start with Minn Admin today. Installing Minn comes later.

Minn Admin is a plugin for WordPress sites: a reimagined admin served at /minn-admin/ on the site you have right now. On WordPress software, classic wp-admin stays as a fallback. On Minn there is no wp-admin: Minn Admin is the admin. Everything you learn there carries over unchanged.

  • Install it like any plugin. Free, MIT licensed, no build step, no Pro tier.
  • Live in it. Content, media, comments, users, settings, and more than a hundred plugin adapters that appear on their own.
  • Nothing to relearn. When Minn is ready for your site, the admin you already use comes with it.
The sequence
Phase 0Minn Admin is the daily admin on WordPress sites. Classic wp-admin stays as a fallback. A complete, REST-pure admin running against real sites.shipped
Phase 1The engine serves greenfield sites. Front end plus REST, Minn Admin as the only admin, fleet tooling that operates the site the way it operates a WordPress site.in progress
Phase 2The plugin runtime. Plugins load unmodified, layer by layer. Front end and data; no /wp-admin/.in progress
Phase 3Migration for the tractable slice. Brochure, forms, and content sites, with the caveats enforced by the tooling itself.earned later

A strangler fig, not a big bang. Each phase is earned by suites, not declared.

The thesis

WordPress is not only software.
It is a coordination standard.

WordPress software remains the dominant web platform because customers, hosts, developers, and now AI agents all coordinate there. The portable unit of site, the frozen schema, the REST API, and the labor pool are the product. The PHP is one implementation of those contracts. Here is what that coordination actually consists of, ranked by how much it matters.

1

A portable unit of site

Files plus a database dump, runnable on any PHP host on earth. Backup, migration, staging, and whole fleet-management stacks exist because the unit is standard.

2

A stable data contract

The posts, postmeta, options, and users schema has not meaningfully changed in twenty years. Backward compatibility is the actual product.

3

An operational surface

WP-CLI, the REST API, the file layout, the config conventions. The layer hosts automate against; the layer that makes hosting WordPress sites an industry.

4

A labor pool

Any freelancer can inherit any WordPress site cold. Choosing a WordPress site is choosing to never be hostage to whoever built it. The customer-control argument is the strongest one.

5

The plugin ecosystem

The weakest leg now, and weakening: AI erodes the long tail. What it does not erode is what a top-tier plugin really is, a maintenance liability transferred to a vendor who ships security releases.

The AI shift sharpens the thesis. When anyone can generate anything on any platform, the rational customer targets the platform where generated work stays portable, inheritable, and operable after the developer leaves. Today that is a WordPress site, because of legs one through four. The question is whether those legs require the WordPress codebase at all.

The graveyard lesson

Every challenger replaced the software and abandoned the contracts.

Ghost, Craft, Statamic, October: none of them dented WordPress, and they all failed the same way. Each replaced the code, which was never the moat, and walked away from the contracts, which were. A clean break means starting over on portability, tooling, hosting support, and the labor pool at once. No product is good enough to win four moats simultaneously.

The correct precedent

You do not ask the world to move. You inherit it through compatibility.

Not “a better CMS”. Nginx against Apache. MariaDB against MySQL. FrankenPHP against PHP-FPM. A from-scratch engine that speaks the incumbent’s interface so precisely that the surrounding infrastructure cannot tell. That is the play.

nginx : apache mariadb : mysql frankenphp : php-fpm minn : wordpress
The play

Two tiers of compatibility, with a hard line between them.

WordPress speaks to three audiences. Minn answers two. The operational contract is sacred. The runtime plugins call into is reimplemented, clean-room, the way Wine speaks Win32. Humans never go through /wp-admin/: Minn Admin is the only UI.

Audience 1 · toolingSpeak

Hosts, backups, CLI.

The schema, the file layout, wp/v2, WP-CLI, feeds, sitemaps, cookies. Kinsta and CaptainCore cannot tell.

  • wp_* tables, untouched wp-config.php
  • REST, WP-CLI, probes, login cookies
Audience 2 · plugin PHPSpeak

Unmodified plugins load.

Hooks, options, WP_Query, $wpdb. A site owner does not want ported plugins. They want their plugins.

  • Clean-room runtime, symbol-gated
  • Front end and data. Not a settings screen.
Audience 3 · humansMute

No /wp-admin/.

List tables, meta boxes, the dashboard, the Customizer, Gutenberg-as-an-app: not a Minn surface. Minn Admin is the only UI.

  • /wp-admin/ 302s to /minn-admin/
  • Plugin settings screens are not coming

Browse the lexicon for every family: Speak, Hear, and Mute, sourced from the markdown agents read.

Tier 1 · the operational contract

Indistinguishable at the seams.

  • The database schema. Real wp_* tables, read and written, tolerating serialized-PHP blobs forever.
  • File layout and wp-config.php shape, so backup and migration tooling just works. The engine boots from the file WordPress generated, untouched.
  • wp/v2 REST core routes: posts, pages, media, users, terms, comments, settings, revisions, search, plugins.
  • WP-CLI verbs for the ops core: option, user, plugin, theme, db, search-replace, and the wp-cli.yml that routes them.
  • Permalinks, feeds, sitemaps, block rendering, block themes. Login, sessions, cookies, and nonces the hosting layer probes, cross-accepted in both directions.
Tier 2 · the plugin runtime, reimplemented

Plugins just work. Layer by layer.

A site owner does not want ported plugins, they want their plugins. So the engine implements the functions plugin code calls: the hook engine, the content and options API, admin registrations (not screens), the editor globals. Loaded from active_plugins, unmodified. Every function’s signature is checked against an inventory reflected from the reference; every behavior is a captured probe.

E0Inventory: 3,903 functions, 394 classes, 2,940 hooks, reflected from the referencedone
E1Hook engine and plugin lifecycledone
E2Content, options, media, cron, HTTP, comments, REST, blocks, $wpdbmost of it
E3Admin registrations, not screens. add_menu_page records. Nothing is rendered. /wp-admin/ redirects.done
E4Editor: block.json registration and the editor globalslater
E5Long-tail runtime symbols, by fatal count. XML-RPC, the Customizer, and multisite stay mute as products.later

Definition of done, phase one

Kinsta, CaptainCore, Disembark, and UpdraftPlus operate the site the way they operate a WordPress site. Backups restore, migrations round-trip, WP-CLI automation runs, monitors stay green, and Minn Admin boots unmodified. That sentence is the whole spec.

How it is built

Capture from the oracle. Implement from the capture. Never from the source.

A parked copy of WordPress runs against the same database as the engine. It is the oracle: every behavior is observed there, recorded as a fixture, implemented from that record, and then diffed live, request by request. WordPress source is never opened while engine code is written.

1

Capture

Boot the reference on the shared database. Curl the exact response, run the exact CLI verb, record it under contracts/fixtures/. Observed behavior is data.

2

Implement

Write the engine from the fixture and the behavioral note. Interface names (routes, columns, keys, verbs) match exactly; every implementation line is original.

3

Prove two ways

A fixture suite pins the captured shape and runs anywhere. A live parity suite diffs the engine against the running reference. Any divergence is a finding, not a flake.

4

Record the contract

Every oracle-learned fact and every honest gap lands in contracts/*.md, machine-checkable and agent-legible. The contract is the product.

# what a milestone looks like
$ cd wp-reference && php -S 127.0.0.1:8123 router.php   # the oracle
$ php tests/theme.test.php
  ok   / matches fixture
  ok   / matches the reference body
  ok   /hello-world/ matches fixture
  ok   /category/uncategorized/ matches the reference body
  
  28 passed, 0 failed

$ php tests/rest-parity.test.php
  ok   GET /wp/v2/posts?context=edit  engine == reference
  ok   GET /wp/v2/types               _fields quirk reproduced
  26 passed, 0 failed

Agent-first is a build method, not a feature

Nobody had done the ops-compatible rewrite because it is an enormous amount of boring, well-specified work. That is precisely what coding agents do well when gated by suites. Every unit ships with a behavioral suite; the suites, not the prose, are ground truth.

Security by declaration

A route’s capability requirement is metadata on the route, mechanically auditable and diffable across releases. Prepared statements only. No unserialize() of untrusted data, ever: serialized blobs are read by tolerant parsers, never executed.

Agent legibility answers the turnover argument

The take-over story for a customer stops being “find another WordPress freelancer” and becomes “point any coding agent at the contracts”.

What the oracle caught

Facts no documentation would have surfaced.

substr($hash, -4)

Modern $wp$ bcrypt hashes derive the auth-cookie key from the last four characters of the hash, not the legacy phpass window. Everything else verifies; only the HMAC fails. Found by brute-forcing the fragment window.

6'2" → 6’2″

Texturize turns a digit-apostrophe into a curly quote but a digit-double-quote into a double prime, and skips pre, code, kbd, style, and script.

?_fields=name → []

On wp/v2/types the associative payload is filtered whole, so any _fields value yields an empty array. The engine reproduces the quirk by construction.

term_taxonomy.count

Stored, and trusted on read. Every write that changes a term’s published total has to recount or the stale number leaks into every list response.

401 vs 403

A bad cookie is rest_not_logged_in; a bad nonce is rest_cookie_invalid_nonce. Cross-acceptance is byte-identical in both directions: a session WordPress minted works on Minn, and one Minn minted works on WordPress.

perm=editable

With more than one post type, the “editable” query restricts every status to the caller’s own posts, admins included. The activity feed depends on that observed behavior.

The license question

Can a WordPress-compatible engine be MIT? Yes.

GPL obligations attach to distributing WordPress’s code or derivative works of it. Minn distributes neither. Compatibility is not derivation. Copyright never protects a procedure, system, or method of operation (17 U.S.C. §102(b)); interfaces, schemas, and protocols are exactly that, and where a compatible route must be named /wp/v2/posts, the expression merges with the idea.

  • Google v. Oracle (2021): reimplementing an API surface for a new platform was fair use.
  • Lotus v. Borland, Sega v. Accolade, Sony v. Connectix: command hierarchies are methods of operation; reverse engineering for compatibility is fair use.
  • In practice: Wine reimplements Win32, Samba reimplements SMB, FerretDB speaks MongoDB under Apache 2.0, and WP-CLI itself is MIT at the heart of the GPL ecosystem.
  • Fork versus reimplementation is the whole question. ClassicPress kept the contracts and stayed a fork: the license came with the tree, so it is GPL forever. A reimplementation written from specifications of behavior is a new work, and its author chooses the license.
The traps, named

What would actually cause a problem.

  • Copied code, including mechanically transformed code. Minn’s predecessor generated its build from WordPress’s own source; that output was a derivative work and could never have been MIT. This is the cautionary tale the whole method is built around.
  • Bundled GPL assets. No core JavaScript, no block-library CSS, no bundled themes, no Dashicons ship in the engine. The block stylesheet you are looking at is Minn’s own.
  • Trademark, not copyright, is the live wire. “WordPress” appears only to identify the software and sites Minn is compatible with, never in the project name or domain.

The hygiene program: spec-first development from fixtures captured on a live instance, implementation from the spec and never the source, a similarity gate against the WordPress tree, tracked provenance for every file, and an hour with an open-source-savvy IP lawyer before the runtime milestone ships. This page is analysis, not legal advice.

Status · pre-alpha

What works today, and what does not.

The engine boots from an unmodified wp-config.php, serves a database WordPress software created, and is written from scratch with only the code it needs to be compatible with WordPress sites. A real site (a client site cloned with the engine swapped in) renders at parity with its parked WordPress software, element by element, in a browser.

Compare the code size: WordPress core next to Minn with Minn Admin, measured from the release zip the same way on both sides and refreshed at each release.

Working, pinned by suites

  • A visitor can read the site. Permalinks, hierarchies, archives, search, pagination, redirects, 404s: 93 URL shapes at parity.
  • Block themes render as data. Templates, parts, patterns, site-editor overrides, theme.json to CSS with presets byte-identical, and a geometry suite that measures every visible element against the reference in Chrome.
  • Classic PHP themes run. Template hierarchy, wp_head defaults, and live body parity against the reference. Proven on a real site that still uses PHP templates.
  • The admin half. wp/v2 posts, pages, media, users, terms, comments, settings, revisions, autosaves, locks, search, plugins. Minn Admin boots and every view answers.
  • Auth, both directions. Cookies, sessions, nonces, capabilities, wp-login.php, password reset, sign-in throttling, application passwords.
  • The probe surface. Feeds byte for byte, sitemaps, robots, cron, mail, the REST index, the version file tooling parses.
  • WP-CLI on Minn, and a one-command minn install / eject that swaps a WordPress webroot over and back, byte for byte.
  • Plugins load as code. 1,687 runtime functions checked against the inventory; on a production site cloned onto the engine, 24 of 25 plugins run unmodified, and a second 48-plugin clone loads everything but one.

Not yet, said plainly

  • No /wp-admin/. Plugin settings screens are not coming. If a plugin only has a wp-admin page, Minn Admin covers it with an adapter, or that page does not exist on the engine.
  • No block editor globals. Editor-side plugin scripts have nothing to attach to.
  • Commerce is not the target slice. WooCommerce boots in the lab; a store needs far more than booting. Brochure, forms, and content sites come first.
  • Multisite, XML-RPC, the customizer, the upgrader: the long tail, by fatal count.
  • The engine’s own strings are English only for now; the app already speaks your language.
  • Not on GitHub yet. The source opens with the first tagged cut. Until then, Minn Admin is the public piece.
HARD PART · 01

Serialized PHP is forever

Reading real WordPress databases means tolerating serialized blobs in options and postmeta indefinitely. Greenfield sites keep it out of new data; migrated sites drag the long tail in.

HARD PART · 02

The runtime is the long road

Front-end plugins work once hooks and the content API exist. A plugin’s own settings screen is never hosted: Minn Admin adapters own that UI. Editor plugins need the editor globals. “Any plugin” means front end and data, reached layer by layer, not declared.

HARD PART · 03

Commerce comes last

A large share of real small-business sites are brochure, forms, and content. That slice is exactly what is tractable, and it is the slice the engine targets first. WooCommerce booting in the lab is a milestone, not a green light.

HARD PART · 04

Bus factor

The customer-control argument only transfers once someone other than the founder can maintain the engine. MIT, machine-readable contracts, and exhaustive suites are the mitigation.

Fair questions

Things people ask first.

What is Minn, and what is Minn Engine?

Minn is the project: this site, what you install, the product. Minn Engine is the developer name for the runtime, the way people say WordPress core. Minn Admin is the interface, a plugin that already runs on WordPress and on Minn.

Is this a fork of WordPress?

No. Minn is written completely from scratch, with only the minimal amount of code needed to be compatible with WordPress sites. That is what makes the MIT license possible; a fork would be GPL forever.

Will my plugins work?

Increasingly, on the front end and in data. The engine reimplements the runtime plugins call into, clean-room, and loads them unmodified behind a symbol gate: a plugin that calls a function the runtime lacks is skipped with the reason rather than fataled. A plugin’s own wp-admin settings screen is not hosted. Minn Admin covers that job with an adapter, or that page does not exist on the engine.

Will my host notice?

That is the definition of done, and the point. The webroot keeps index.php, wp-config.php, wp-settings.php, wp-includes/version.php, and wp-content/ exactly where tooling expects them, and wp/v2, feeds, sitemaps, and wp-cron.php answer the way monitors and backup tools probe them. /wp-admin/ redirects to Minn Admin: there is no wp-admin UI. Real fleet tooling is run against a real site until those tools operate it the same way they operate a WordPress site.

Can I go back?

Yes, in one command. minn eject restores the parked WordPress files byte for byte. Nothing is written to your database that WordPress would not have written itself.

Why PHP?

Because the moat being inherited is PHP hosting. Modern PHP on FrankenPHP-class runtimes is fast, and the infrastructure already speaks it. Modern PHP, 8.3 minimum, no framework, no build step, no dependencies.

Where is the admin?

Minn Admin, a plugin for WordPress sites, is the interface. It boots on the engine unmodified because it never touched wp-admin internals in the first place. On WordPress software, classic wp-admin stays as a fallback. On the engine there is no wp-admin: Minn Admin is the admin. It speaks wp/v2 plus its own namespace, and it works on the WordPress site you have today. Start there.

Where is the source?

The engine is developed in the open on a local repository and opens on GitHub with its first tagged cut. Minn Admin’s source is public now, and its contracts are the same ones the engine serves.

A second engine for WordPress sites.

Try Minn Admin on the site you have today. When 100% of what you do happens in /minn-admin/, consider an engine swap with Minn.