Introduction
What Squilla is and why it exists.
The CMS where AI does the work
Squilla is a Go-based, AI-native CMS built on a kernel + extension model. The kernel is a small Go binary that provides infrastructure only — content nodes, public rendering, authentication and sessions, the CoreAPI, the MCP server, the event bus and filter chain, and the VDUS engine that drives the admin SPA. Every user-visible feature — media, email, SEO, sitemaps, forms, content blocks, the visual editor — ships as an independent extension with its own gRPC plugin (when it needs Go), admin micro-frontend, database tables, and SQL migrations.
The mental model is: core is the Linux kernel, extensions are Debian packages. The kernel exposes generic plumbing (CRUD on nodes, an event bus, capability-checked CoreAPI calls, an HTTP proxy that forwards /admin/api/ext/<slug>/* to the right plugin). Extensions provide actual features by composing that plumbing.
If the kernel can't answer in 50ms, the kernel is doing too much.— Internal design doc, v0.2
Why we built it
Existing CMS options force a choice: be developer-friendly OR content-editor-friendly; be fast OR flexible; be open-source OR AI-ready. Squilla refuses the trade-off, and pays for that refusal by being opinionated about where features live.
- The kernel is Linux-small — a few thousand lines of Go that cannot grow with the feature surface, because features are not allowed in.
- The extension model is Debian-clean — every extension owns its data, its UI, its routes, and its lifecycle. Disabling an extension removes its surface area without leaving orphaned tables or dead admin pages.
- The MCP layer is AI-native — every CoreAPI verb is exposed as a typed MCP tool with an OpenAI-style JSON schema. An LLM can author content, install extensions, render previews, and verify the result without ever touching the filesystem.
- The runtime is Go-native — sub-50ms TTFB on the public site is the design target, not an aspiration. Atomic-swapped maps for hot config, GIN-indexed JSONB for content blocks, and per-process plugins isolated from the kernel.
- The license is GPL-3.0 — the LICENSE file in the repository is the authoritative copy, and that copy is forever.
What lives where
The boundary between kernel and extension is not stylistic; it is enforced by a single rule that's worth memorising:
That rule decides every architectural argument. Concretely:
- Image optimisation, WebP conversion, thumbnail generation, S3-style cache routing → media-manager extension. The kernel keeps zero bytes-on-disk fallback;
core.media.uploadroutes to whichever active extension declaresprovides: ["media-provider"]. - Email template management, rule-based dispatch, send logs, password-reset email composition → email-manager extension. The kernel only emits events; the dispatcher inside email-manager subscribes to
*, matches admin-defined rules, renders templates, and hands the rendered message to whichever extension declaresprovides: ["email.provider"](smtp-provider, resend-provider, or your own). /robots.txt, AI-crawler policy, per-node SEO meta, structured-data JSON-LD → seo-extension. The kernel does not own the robots route.- XML sitemaps → sitemap-generator extension.
- Forms with field-schema validation, submission storage, webhook delivery, CF7-style HTML authoring → forms extension.
- The library of pre-built content blocks (CTA, hero, accordion, pricing table, etc.) → content-blocks extension. These are not core types — they're block_types
source: "extension". - The visual editor that lets you drag, edit, and reorder blocks on the live page → visual-editor extension. The kernel does not know what a draggable block is.
- Public route proxy mechanism, event bus, filter chain, capability gating → core. These are generic. Any extension can use them.
This separation is what makes the system tractable for an LLM to operate. There are no implicit features. If something works, an active extension is responsible for it; if it doesn't, you can read the extension's manifest and source and know exactly why.
The three authoring surfaces
Anything you build for Squilla lives in one of three places:
- Themes — layouts, partials, content-block templates, and theme-scoped Tengo scripts. Themes own the look of the public site and can ship seed content. Hot-swappable. See Themes Overview.
- Extensions — features that add data, routes, admin UI, or plugin behaviour. Either gRPC (full Go) or Tengo-only (scripting and HTTP routes, no compiled binary). See Extensions Overview.
- Tengo scripts — embedded sandboxed scripts that subscribe to events, register routes, or mutate values via the filter chain. Both themes and extensions can ship them. See Scripting with Tengo.
None of these require a kernel restart to install or activate. The filesystem watcher picks up new theme and extension directories automatically; core.theme.activate and core.extension.activate spawn or kill plugin subprocesses without touching the main binary.
Where to next
Installation covers the docker-compose path for local development and the Coolify path for one-click production deploys. Quickstart walks through registering a custom node type and publishing content end-to-end, entirely through MCP, with no filesystem access. The MCP Server reference is the entry point for AI-driven workflows; the CoreAPI Reference is the entry point if you're writing Go.