Concepts
Capabilities and packs
How Thallo's features are packaged, and what switching one on or off does.
Thallo arrives as one Composer package, but most of the features it brings have a switch. This page names them, says what a switch does to a running site, and separates Thallo's own packs from the Glueful framework extensions beside them.
A capability is a switch, a pack is a package
A capability is a feature with a switch: search, navigation menus, the approval workflow.
Each one has an id — thallo.search, thallo.navigation — and the id is what the admin, the
configuration and the code all use to name it.
A pack is the Composer package a capability ships in. Thallo's packs are named
glueful/thallo-* and every one of them is required by glueful/thallo-core, so a new project
already has them all on disk. You do not install a pack to get its feature; you switch its
capability on.
The capabilities an install has
| Capability | What it covers | Default |
|---|---|---|
Accounts (thallo.accounts) |
Registration, sign-in and account pages for visitors of the site. | On |
Analytics (thallo.analytics) |
Product-analytics fact store fed by lifecycle events. | On |
Data collections (thallo.collections) |
Developer-defined data collections with a public CRUD/query API. | On |
Commerce (thallo.commerce) |
Adopts glueful/commerce and links Commerce products to Thallo entries. |
Off |
Content importers (thallo.importers) |
CSV, Markdown and WordPress content/user import adapters. | On |
Navigation (thallo.navigation) |
Menu trees served headless and to themes. | On |
Rendered delivery (thallo.render) |
Server-rendered pages from published content via filesystem Twig themes. | On |
Search (thallo.search) |
Public, delivery-parity content search, over PostgreSQL or Meilisearch. | Off |
SEO (thallo.seo) |
Sitemaps, per-entry SEO meta, and robots.txt. | On |
Subscriptions (thallo.subscriptions) |
Workspace SaaS billing: platform plans and per-workspace subscriptions. | On |
Multi-tenancy (thallo.tenancy) |
Tenant-owned content model + data, scoping, seed/sync and enablement. | Off |
Approval workflow (thallo.workflow) |
Single-stage editorial review over draft/publish. | On |
Search is off by a deliberate default in Thallo's own configuration. Commerce and Multi-tenancy are off because each depends on a framework extension that a fresh install leaves disabled.
Off means inactive, not uninstalled
A capability that is off is still installed. Its code is loaded and its tables stay: a pack's migrations run when the pack is installed, not when its capability is switched on. Nothing is dropped, and switching back needs no rebuild. What goes away is the surface:
- Routes. They are never registered, so a request to one gets the router's standard JSON 404, not a handler that answers "disabled". The gate is in the backend, not only in the admin: a direct API call to a Thallo importer fails closed while Content importers is off. Switching Rendered delivery off is the extreme case — every public path falls through to that 404 and the install is purely headless.
- Menus. The admin sections a capability owns disappear from the sidebar — Review queue with the approval workflow, Collections with data collections, Commerce with commerce.
- Block types. A block type that belongs to a capability is hidden from Settings › Block Types while it is off, and its row is never deleted. It reappears, with the blocks already placed on pages, when the capability comes back.
- Commands.
php glueful search:reindexexists only while Search is on.
Where the switches are
Go to Extensions › Capabilities. Each row shows the capability's name, its id, its description, the engine it depends on if it has one, and a badge: On, Off, or Requested · engine unavailable, which means you asked for it but its engine cannot back it.
Reading and changing this list needs the system.access permission; without it the tab shows
"Operator access required". A flip saves immediately and takes effect on the next request, so
reload the admin after switching something.
From a shell, php glueful thallo:capabilities prints the same list, and --enable=ID or
--disable=ID flips one under the same rules. Long-running workers keep the old state until they
restart. See the command reference.
Content search also appears in Settings › General. It is not a second switch: both write
the same thallo.search state.
When a capability depends on an engine
Five capabilities name an owning engine — the framework extension that does the work. Accounts
needs glueful/users, Content importers glueful/import-export, Commerce glueful/commerce,
Subscriptions glueful/subscriptions and Multi-tenancy glueful/tenancy.
Such a capability is on only when it is both requested and backed: the engine must be installed, enabled, and have its schema migrated. If any of that is missing, the row says so, names the command that fixes it, and refuses to turn on until you have run it.
A capability nobody has ever touched follows its engine. That is why Commerce reads plainly Off on a fresh install rather than "on, engine unavailable": enabling the engine is the opt-in.
What switching one on can ask for
- A migration. An engine's tables have to exist before the capability it backs can be on.
php glueful extensions:enable <package>migrates the extension's schema first; if a schema is pending or divergent the capability row tells you and namesphp glueful migrate:runorphp glueful migrate:verify. - A config value. Search picks its engine from
SEARCH_ENGINE—auto,postgresormeilisearch.autouses Meilisearch whenMEILISEARCH_HOSTis set and the site's own PostgreSQL otherwise, so search needs nothing else installed. - A command. Switching Search on indexes nothing by itself. Run
php glueful search:reindexto build the index from published content. - A cron line. Analytics keeps raw facts for
ANALYTICS_RETENTION_DAYSdays (90 by default) andphp glueful analytics:prunedeletes the rest. No job inconfig/schedule.phpruns it, so schedule it yourself alongside the scheduler.
Extensions are the other kind of package
Thallo's packs are libraries: always loaded, never separately enabled, governed only by their
capability switch. A Glueful extension is a different thing — a Composer package that
Composer discovers and that does nothing until its provider is listed in config/extensions.php.
An install ships with eight enabled: aegis, audit, email-notification, i18n,
import-export, media, subscriptions and users. Three ship installed and disabled:
commerce, payvia (payments) and meilisearch.
Extensions › Installed lists what Composer found, with each one's version, provider, schema state and an Enable or Disable button; Extensions › Browse searches the Glueful catalogue. From a shell:
php glueful extensions:list
php glueful extensions:enable glueful/commerce Enabling migrates the extension's schema first. php glueful extensions:disable reverses it, and
preserves the schema and the data.
One extension is not yours to toggle. glueful/tenancy is marked protected, and every generic
enable and disable — CLI, API and admin — refuses it: workspaces are turned on by their own
staged flow. See workspaces and
turn on workspaces.
Setting a default in configuration
The admin's switchboard is stored in the database and wins over everything else. Until a
capability has been switched there, Thallo reads the capabilities map in config/thallo.php.
That file is optional — Thallo ships its defaults with the package and your config/ directory
holds only overrides — so create it to pin a default for a deployment:
<?php
return [
'capabilities' => [
'thallo.analytics' => false,
],
]; Keys are full capability ids, with their dots. Once someone flips the same capability in Extensions › Capabilities, the stored state answers and this file no longer decides.
Where to go next
The guides switch individual capabilities on and use them: add search to the site, sell products, let visitors sign up and sign in.