Basehim 1.0.1 is out
Basehim is now open source. Version 1.0.1 is published on GitHub under the MIT licence — a CMS with a built-in Model Context Protocol server, so AI agents can search, read and draft your content with permissions you decide, running on the kind of hosting real clients actually buy.
Download 1.0.1 from GitHub, or read on for what's in it.
Why this exists
Nearly every conversation about AI and the web assumes a particular kind of website: one with a deploy pipeline, a container registry, and somebody on the team who knows what a queue worker is.
Most websites are not that. They sit on cPanel, they were built by one developer for one client, and the deployment process is dragging a folder into File Manager. The hosting costs a few dollars a month, and that is the correct amount to spend.
Basehim is for those sites. Agent access, a real API and a modern permission model, with no terminal required.
A built-in MCP server
Basehim exposes a Model Context Protocol endpoint at /mcp, at the root of your own domain. Add https://your-site.com/mcp as a custom connector in an AI assistant and it registers itself — there is no client id and no secret to configure by hand.
It is not an add-on. The MCP server ships in core, which is what makes the next part possible.
Scoped access, not all-or-nothing keys
The usual way to give an AI agent access to a CMS is an API key that can do everything, because retrofitting real scoping into a permission system that was not designed for it is genuinely hard.
Basehim was designed for it. Agents authenticate over OAuth 2.1 with PKCE and dynamic client registration, and every token carries explicit scopes:
posts:read·posts:writetaxonomies:read·taxonomies:writemedia:readcomments:read·comments:writesettings:read·users:read
A token issued to read posts cannot touch users. Not "shouldn't" — the scope is checked where access happens, and there is no path around it. An agent that drafts blog posts gets posts:read and posts:write, and that is the complete extent of what it can reach.
Issue a separate token per integration and you can revoke one without disturbing the others. Revoking takes effect immediately. Apps can contribute their own scopes, so your site's list may be longer than the one above — fetch /.well-known/oauth-authorization-server to see what yours advertises.
A full REST API
Everything the admin can do, /api/v1 can do: posts, pages, media, taxonomies, terms, menus, comments, users, settings, apps, cache and scheduling.
Responses are wrapped in a data envelope and errors follow RFC 7807 problem details. Reading published content needs no authentication at all; anything that writes, or reads drafts, does. Three ways in — an API key for scripts and server-to-server work, a JWT for apps acting on behalf of a signed-in person, and OAuth for agents.
One thing worth knowing before you start: single items are fetched by slug, but updates and deletes address them by id. So GET /posts/hello-world, but DELETE /posts/12. It catches people out.
The complete API reference lists every endpoint, and the same reference is generated inside your own admin at /admin/api/reference.
Installs by uploading files
This was the constraint that shaped everything else, and it was not negotiable:
- No Composer
- No npm, no bundler, no build step
- No
vendor/directory to sync - No Redis, no queue workers, no cron dependency for core
- No
public/directory — your document root ispublic_html, and fighting that is a losing battle
Unzip into public_html/, open your site in a browser, and the installer handles the database, admin account and starter content. It takes about a minute. Subdirectory installs work out of the box, and DB_PREFIX lets several sites share one database when your host gives you a fixed number.
Requirements are PHP 8.1 or newer with pdo_mysql, mbstring, fileinfo, gd and zip; MySQL 5.7+ or MariaDB 10.3+; and Apache with mod_rewrite. Tested on PHP 8.1 through 8.4.
Apps are a folder and a class
An app is a directory in content/apps/ with an app.json manifest and an entry class extending App\Core\App. Hooks, filters, routes, admin menu items, dashboard widgets, app-scoped settings, app-owned database tables and bundled assets are each a single method call on the base class. You never touch the container unless you want to.
Install by uploading a zip from Apps, from the built-in marketplace where every download is checksum-verified, or by dropping the folder in — it is detected automatically. Apps declare the permissions they need in their manifest, and you see and approve that list before activation.
Themes are just as plain: a theme.json manifest and a templates/ folder. No compile step, no framework to learn. Ship one by zipping a folder.
A WordPress migrator ships in the box, because most content already lives somewhere.
Security
Passwords are hashed with bcrypt at cost 12. CSRF tokens on every form. Short-lived HS256 JWTs, with refresh tokens stored as hashes and revocable. API keys stored as SHA-256 hashes — the plaintext is shown once, at creation, and never again. Sessions are HttpOnly and SameSite=Lax, and Secure when HTTPS is detected. PDO prepared statements throughout with emulation disabled. Uploads validated by MIME type, extension and size. App archives checked for path traversal before extraction.
Two things are on you after installing: delete install.php when the installer finishes, and generate real values for APP_KEY and JWT_SECRET rather than keeping the defaults.
If you run nginx, read this bit. The bundled .htaccess denies direct HTTP access to .env, storage/ and app source directories. Nothing else enforces those rules. On nginx you must replicate them in your own config, and if you don't, your environment file is one URL away.
What isn't finished
This is a 1.0, and it is more useful to say so plainly than to find out later.
There is no automated test suite yet. Continuous integration syntax-checks every file across four PHP versions and applies every migration against MySQL 8, but behaviour is not covered. This is the single most useful thing anyone could contribute.
The ecosystem is small. Two themes and a handful of apps. If your project needs a mature ecosystem today, use something older — that is a sincere recommendation, not false modesty.
One documented helper does not exist. The agent API guide shows a $this->agents() shorthand on the app base class. It was never implemented. The service works through the container in the meantime, and it is listed in the known issues rather than quietly left for someone to trip over.
Get it
Basehim 1.0.1 is on GitHub, MIT licensed. Start with Getting started for your first ten minutes, or Installing Basehim for the full walkthrough.
If you install it and something breaks, open an issue — that is far more useful than not hearing about it. If you get an agent doing something interesting with it, that is more interesting still.