THE FIELD GUIDE / v0.1.0

Understand it.
Make it yours.

A practical guide to a deliberately small framework.

01 / GET GOING

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.

Download webspine v0.1.0 ↗
php core/bin/console.php install
php core/bin/console.php health
php -S localhost:8080 -t public public/router.php

Visit 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.

Use the PHP development server locally. In production, configure your web server with public/ as its only document root.
02 / THE INTENT

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 in site/themes/, and capabilities in site/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.

03 / A PLACE FOR EVERYTHING

One project. Clear boundaries.

core/Framework, bundled providers, tools, tests, and guides
site/Content, identity, page titles, URLs, and starter data
site/themes/Templates, shared layouts, scoped CSS, and browser JS
site/plugins/Provider and feature extensions with manifests
config/Private provider selection and credentials
storage/SQLite, update stages, backups, and locks
public/The only web document root
core/bin/Installation, health checks, packaging, and updates
.dist/Generated release ZIPs and checksums; ignored by Git
core/tests/Dependency-free integration tests
core/docs/Architecture, deployment, and contributor guidance

The 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.

04 / CHOOSE EXPLICITLY

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.

05 / YOUR EXPRESSION

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-theme

The 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.

06 / EXPLICIT CONNECTIONS

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 ↗
07 / PRESERVE WHAT YOU MAKE

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 recover

Site 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.

Hashes detect corruption; they do not authenticate a release. Only apply local archives from a source you trust. Signed online updates and separate extension updates are planned.
08 / OUT IN THE WORLD

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.

09 / DO THE BORING THINGS WELL

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.php

Integration 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.

Before adding mutation endpoints, implement authentication, authorization, input validation, and CSRF protection. This bootstrap has no admin editor, uploads, or public mutation forms.
10 / THE STATE OF THE SPINE

Here today. Next tomorrow.

Built

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.

Planned

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.