Developers
Make it your system.
A lean PHP core without a framework, open interfaces and clearly documented extension points – from kits to your own CLI command.
Tech-Stack
What KLXM Studio is built with.
Versions according to composer.lock and tools/package.json of version 1.0.0.
| Area | Technology | Details |
|---|---|---|
| Runtime | PHP ≥ 8.4, no framework | Front controller, PSR-4 autoload (Core\ → app/) via Composer; extensions sodium, gd, mbstring, dom, pdo. |
| Database | SQLite or MySQL/MariaDB | Per website SQLite (default, one file) or MySQL/MariaDB ('db' in config/sites/{key}.php); backup via VACUUM INTO or mysqldump. Search index, chat, shared tables, media pools, support and AI logs always stay SQLite – pdo_sqlite is required, SQLite ≥ 3.35 (Debian 12/13, Ubuntu 22.04/24.04; AlmaLinux/RHEL 8/9 too old). Doctrine DBAL 4.4.4 (MIT) for table schemas. |
| Server | Apache, nginx or php -S | No .htaccess – only public/ is in the web root; runs on Plesk and ordinary PHP hosting, locally with php -S. |
| Search | loupe/loupe 1.1.0 (MIT) | Full text with typo tolerance on SQLite; optionally semantic/hybrid via vectors (Symfony AI Store). |
| AI | Symfony AI 0.14 (MIT) | platform + store; providers Ollama, Mistral, OpenAI and generic/OpenAI-compatible; local transcription with whisper.cpp. |
| Security | WebAuthn, TOTP, libsodium, CSP | Passkeys with lbuchs/webauthn 2.2.0 (MIT), TOTP with QR code (chillerlan/php-qrcode 5.0.5, MIT/Apache-2.0), libsodium for encrypted requests and secrets, Content Security Policy without unsafe-inline. |
| Calendar & sync | rlanvin/php-rrule 3.0.0 · sabre/dav 4.7.1 | Recurrence (MIT); CalDAV/CardDAV in the dav extension (BSD-3-Clause). |
| HTTP & Mail | symfony/http-client 8.0.16 · symfony/mailer 8.0.15 | Proxy for maps and thumbnails, AI providers, SMTP delivery (MIT). |
| Frontend | Vanilla JS, esbuild 0.25.12 | Scripts as IIFE and ES modules (.mjs), built with esbuild in tools/ (pnpm); admin UI isolated from the kit via Shadow DOM; CSS budgets per kit. |
| Vendor-Assets | Editor.js 2.31.7 · PDF.js 6.3.289 · MapLibre GL JS 6.11.2 | Block editor (Apache-2.0) with editorjs-drag-drop 1.1.16 (MIT), PDF viewer (Apache-2.0), maps (BSD-3-Clause); Lato font (OFL). |
| Icons | Phosphor Icons 2.1.1 duotone (MIT) | 511 icons in 23 topics, as a sprite per website. |
| Licence | MIT | Core, kits and extensions; your own kits and extensions under any licence. Third-party software see THIRD-PARTY-NOTICES.md. |
Extension points
Where you can hook in.
Every snippet is taken from the source code of version 1.0.0.
-
Kits
A kit is a self-contained package: blocks, central settings, design tokens, conditional CSS per block and structured data. New kit: php bin/console kit:create <name> [--from=…] – the starter kit is the default. Technically a kit lives in themes/{name}/theme.php – the folder name stays for compatibility (theme:create still works).
themes/essenz/theme.php 'jsonld' => 'essenz_jsonld', 'conditional_css' => [ 'css/b-faq.css' => ['faq'], 'js/video.js' => ['video'], ], 'design' => require __DIR__ . '/design.php', -
Blocks as PHP templates
One renderer per block type in themes/{name}/blocks – with inline editing via $b->edit(). The block automatically appears in the editor, the REST API and the MCP server.
themes/basis/blocks/richtext.php <div class="wrap wrap--text"> <?= basis_head($b) ?> <div class="prose"<?= $b->edit('text', 'rich') ?>><?= rich($d['text']) ?></div> </div> -
Block builder
Custom blocks without PHP: fields, a safe template language with escaping and scoped CSS; export as a kit block. Excerpt from this website’s “command line” block:
Admin → Blocks <ol class="cli-list"> {% for c in commands %}<li class="cli-row"> <code class="cli-cmd">{{ c.cmd }}</code> <span class="cli-text">{{ c.text }}</span> </li>{% endfor %} </ol> -
Extensions
An extension ships features, permissions, migrations, menu entries, routes, blocks, proxy sources and CLI commands – enabled per website via 'extensions' => ['dav']. Extensions live in extensions/{name} or come as Composer packages of type “mycms-extension” (composer require vendor/package), which the core discovers automatically.
extensions/dav/extension.php 'boot' => function (Core\Extension $x): void { $x->feature('dav', 'CalDAV/CardDAV (Kalender und Kontakte in Apps)', ['dav.use']); $x->permissions('CalDAV/CardDAV', ['dav.use' => '…']); $x->migration(1, fn(Core\Database $db) => MyCms\Dav\Dav::migrate($db)); $x->nav('/admin/dav', 'Kalender & Kontakte in Apps', 'dav', 'dav.use'); -
Example: Consent Kit
A complete extension with its own README, LICENSE (MIT) and THIRD-PARTY-NOTICES: consent management with 38 templates, a web component in Shadow DOM, Consent Mode v2 and a CSP that only widens after consent. Ported from KLXM’s REDAXO add-on consent_kit.
extensions/consent_kit // config/sites/{key}.php bzw. config/config.local.php 'extensions' => ['consent_kit'], // abschalten, ohne die Erweiterung zu entfernen: 'features' => ['consent' => false], -
Output hooks
Extensions can post-process the website HTML, add sources to the CSP (never unsafe-inline) and add links to the legal line.
app/Extension.php $x->htmlFilter(fn(string $html, array $ctx) => $html) $x->csp(fn() => ['script-src' => ['https://…']]) $x->footerLinks(fn() => [['label' => …, 'href' => '#…']]) -
REST-API
OpenAPI 3.1 at /api/v1/openapi.json. Tokens with read or write level, expiry and mode “apply directly” or “for approval” – only a SHA-256 hash is stored.
curl curl -H "Authorization: Bearer $TOKEN" https://ihre-domain.de/api/v1/me -
MCP server
Model Context Protocol over Streamable HTTP with 42 tools, including list_pages, update_block, save_entry, upload_media, set_design, publish_page – with the same tokens and rules as the API.
Claude Code claude mcp add --transport http mycms https://ihre-domain.de/mcp --header "Authorization: Bearer cms_…" -
Command line
Around 50 commands for accounts, websites, network, kits, fonts, migration, backups, shared data, search and AI; extensions add their own.
bin/console php bin/console site:create kunde www.kunde.de,kunde.de basis php bin/console migrate --all php bin/console health php bin/console blocks:selftest -
Data tables
Custom tables with 23 field types, conditions, detail pages and public forms – shared between several websites of an installation.
bin/console php bin/console data:share <handle> --members=a,b [--see-members] [--merge] php bin/console shared:list -
External sources
RSS 2.0/1.0, Atom, JSON (path), XML (XPath) and OpenImmo 1.2 (XML, ZIP or pull URL) are fetched server-side, mapped with transforms into entries of a data table and synced; images go to the media library, synced entries are read-only. Protected against SSRF, XXE and ZIP slip.
Mapping (JSON) · bin/console {"id_path": "guid | link", "rows": {"titel": {"path": "title", "tx": "text"}, "datum": {"path": "pubDate | dc:date", "tx": "date"}, "bild": {"path": "enclosure@url | media:content@url", "alt": "title"}}} */15 * * * * php bin/console sources:sync --all -
Languages
Fixed texts use lt('…') (website) or __('…') (admin); translations are a PHP array per language, i18n:missing lists gaps.
themes/essenz/lang/site/en.php 'Datenschutz' => 'Privacy', # php bin/console i18n:missing en --site-texts -
Design tokens
Every token becomes a CSS variable or class; the style editor shows presets and checks contrast, also via API and MCP (get_design/set_design).
themes/essenz/design.php $color('accent', 'Signal (Füllfarbe)', '--e-a', '#D85B19', '#F0782F', ['with' => 'background', 'min' => 3], -
Feature flags per website
Presets and individual features per website; disabled features lock their permissions – navigation, API and MCP follow automatically.
config/sites/{key}.php 'preset' => 'full' | 'content' | 'minimal', 'features' => ['data.schema' => false, 'api' => false], 'blocks' => ['deny' => ['video'], 'allow' => null],
Get started
Local in four steps.
From the README quick start. The developer manual lives in the admin at /admin/hilfe/technik.
-
Get the source
Public repository: github.com/klxm/studio – bugs and requests at github.com/klxm/studio/issues.
git git clone https://github.com/klxm/studio.git cd studio -
Dependencies and build
Composer 2 for PHP, Node 22 + pnpm 10 only for the build – the server needs neither Node nor pnpm.
shell composer install cd tools && pnpm install && pnpm build && cd .. -
Run
The first request creates the database and config/config.local.php (app_key, setup_token) and seeds the kit’s starter content.
shell php -S localhost:8000 -t public public/index.php -
Create an account
Or open /admin/setup with the setup token. Then set up encryption, email delivery and kit details.
shell php bin/console user:create name@example.org admin
Contact
Talk to KLXM Crossmedia.
A demo, use in your agency or technical questions – we answer personally.
Am Schürmannshütt 40g
47441 Moers
Germany
- Phone
- +49 2841 889998-0
- info@klxm.de
- Website
- klxm.de (opens in a new tab)