Your first five minutes.
Download the bootstrap ZIP and extract it. You need PHP 8.3+ with pdo_sqlite, openssl for SMTP, and zip for packaging and updates. No Composer, npm, or build step.
php core/bin/console.php install
php core/bin/console.php health
php -S localhost:8080 -t public public/router.phpVisit localhost:8080. Installation explicitly creates SQLite tables, records schema version 1, and selects the Studio theme. Re-running it preserves settings and pages. Requests never install or migrate a database.
public/ as its only document root.Small is a design decision.
The core goal of webspine is to let you build, extend, and maintain your own website entirely with AI. Familiar code, a readable structure, and explicit contracts give an AI contributor a project it can understand.
Bring your own AI app with access to the project files, such as ChatGPT Desktop, Claude Code, or OpenCode. The project stays independent of any AI vendor; you can also edit every file by hand.
- Keep the core small and understandable.
- Keep content and routes in
site/, presentation insite/themes/, and capabilities insite/plugins/. - Choose providers explicitly. Avoid hidden configuration in the database.
- Preserve a theme’s identity. Every website can look different.
AI contributors should inspect existing work, make scoped changes, run relevant checks, report gaps, and protect secrets. The bootstrap is a foundation, not a finished CMS.
One project. Clear boundaries.
core/Framework, bundled providers, tools, tests, and guidessite/Content, identity, page titles, URLs, and starter datasite/themes/Templates, shared layouts, scoped CSS, and browser JSsite/plugins/Provider and feature extensions with manifestsconfig/Private provider selection and credentialsstorage/SQLite, update stages, backups, and lockspublic/The only web document rootcore/bin/Installation, health checks, packaging, and updates.dist/Generated release ZIPs and checksums; ignored by Gitcore/tests/Dependency-free integration testscore/docs/Architecture, deployment, and contributor guidanceThe SQLite provider implements storage, settings, pages, and optional Entities CRUD. Plugins declare typed entities and use shared create/read/list/update/delete operations after running php core/bin/console.php entities:install. See core/docs/entities.md and site/plugins/catalog/ for examples. Feature plugins use interfaces, never provider-specific SQL. MariaDB and PostgreSQL adapters will need their own queries, migrations, and data-transfer tooling.
Configuration before connection.
Copy config/example.php to config/local.php. Keep the local file private. Select providers and enabled feature plugins here, before database access.
'providers' => ['storage' => 'sqlite', 'mail' => null],
'plugins' => ['field-notes', 'release-download'],
'sqlite' => ['path' => 'storage/site.sqlite'],Select 'mail' => 'smtp' and fill in the SMTP configuration to enable bundled PHPMailer. The provider requires TLS and sends plain-text messages. Mail is disabled by default; there is no public form or automatic email.
SQLite belongs on local disk with modest write concurrency. Keep the database and update backups outside the document root.
Change the surface.
Duplicate site/themes/studio/, choose a lowercase directory ID, and update theme.json. Keep API version 1 and provide layout.php plus the templates referenced by site/pages.php. The shared layout wraps every page. Edit wording in site/content/, page titles in site/pages.php, and identity in site/meta.php; theme files own markup and styles.
php core/bin/console.php theme your-themeThe active theme is stored by the settings service. Assets are served only from the selected theme’s assets/ folder through a constrained route. Scope CSS under a theme class, escape strings with e(), and keep JavaScript progressively enhanced.
PHP themes and plugins execute trusted code. Review them before installing; they are not sandboxed.
Add capabilities, cleanly.
Custom plugins live in site/plugins/; bundled providers live in core/plugins/. IDs must be unique across both directories. Every plugin declares its ID, semantic version, API, and dependencies in plugin.json. The entry file returns an object implementing Webspine\Contracts\Plugin.
{
"id": "my-feature", "version": "0.1.0", "api": 1,
"dependencies": {"field-notes": "0.1.0"}
}public function register(App $app): void {
$pages = $app->services->get(Pages::class);
$app->router->get('/hello', function () use ($pages, $app) {
$page = $pages->find('hello');
return $app->theme->render('page', [
'title' => $page['title'], 'body' => $page['body'],
]);
});
}The registry accepts implementations of declared interfaces and rejects duplicate registrations. Providers register services; feature plugins consume them. Providers must be selected in private configuration rather than loaded implicitly as dependencies.
Visit the working example plugin ↗Move the core forward.
Core releases carry an exact file inventory with SHA-256 hashes, version, PHP minimum, and API compatibility. Updates validate and stage the archive, check compatibility and health, then activate under an exclusive lock. Failed health checks roll back changed files. A persistent recovery journal blocks requests after an interrupted activation until recovery.
php core/bin/console.php package
php core/bin/console.php update /path/to/core-release.zip
php core/bin/console.php rollback
php core/bin/console.php recoverSite files, themes, custom plugins, config, and data are preserved. Bundled providers in core/plugins/ update with the framework. Create your website from a bootstrap once; use core release archives for framework updates. Pulling or copying the upstream repository over a customized site does not provide this preservation guarantee. Core updates do not migrate databases. Back up the site separately before upgrading. Drain production workers and reset OPcache after activation.
Give the public one doorway.
Set your Apache or nginx document root to public/. Route requests to index.php; the included Apache configuration requires mod_rewrite and override permissions. Disable directory indexes and deny arbitrary PHP files. See core/docs/deployment.md for an nginx example.
The PHP worker needs read access to framework and extensions, and write access to storage/. Only the operator performing an update needs write access to framework files. Use HTTPS, back up data, and keep config/local.php out of version control.
For a bootstrap ZIP including the starter theme and providers, run php core/bin/console.php package --full. A normal core release contains only managed framework files.
Solid underneath.
Templates escape untrusted output. SQLite queries are parameterized. Asset routes are confined to the selected theme and approved file types. The starter theme includes keyboard navigation, visible focus, reduced-motion support, responsive layouts, and accessible tabs.
php core/tests/run.phpIntegration checks cover installation, persistence, provider substitution, routing, escaping, extension contracts, archive integrity, preservation, and rollback. WCAG 2.2 AA is the target; a full assistive-technology audit remains to be done.
Here today. Next tomorrow.
Routing and responses; registry, plugin contracts, action hooks; SQLite settings and pages; explicit idempotent installation and schema recording; theme selection and protected assets; optional SMTP with PHPMailer; installation, health, packaging, and reversible local core updates; integration tests.
MariaDB / PostgreSQL adapters and data transfer; independent plugin and provider updates; signed online updates, potentially operated by AI; admin and content editing; authentication; public forms and uploads.
Version 0.1.0 is an implemented bootstrap. It is not yet a complete CMS.