A fresh install cannot follow this page yet, and the blocker is sharper than "some modules are missing".
The published packages ship the install contract and none of its
implementations. coolms/core carries ModuleInstallerInterface,
StructureInstallerInterface and VfsInstallerInterface; coolms/core-bundle
carries the coolms:install runner — all four are in the public repositories,
and grepping them for implements ModuleInstallerInterface returns nothing.
That is the claim, and it is yours to check rather than ours to assert.
For comparison: measured 2026-09-07 against the CoolMS application tree, 27 such implementations. That tree is not public, so this is the one number here you cannot settle for yourself — the date says where it came from, not when it runs out.
That is why the install page ends with coolms:install exiting 1 over an empty
set, and why there is no next command to give you. coolms:theme:* belongs to
the Theme module, coolms:navi:seed to Navi, and sections and the /content
tree to Web and Content — all still directories in src/ rather than packages,
so a stranger's install has neither the commands nor the tree they write to.
This page is therefore a description, not a walkthrough. It is accurate about a full installation and every command on it is real; what does not exist yet is the install a reader could run them against. It is written down while the sequence is known rather than reconstructed later, and it will become followable when the modules ship — not when this page is edited.
A site here is a section with a theme bound to it. Both are rows, not
files, and the pages they serve live in the VFS under /content/<section>.
Install and activate a theme#
docker compose exec app php bin/console coolms:theme:install coolms-site
docker compose exec app php bin/console coolms:theme:activate coolms-site --section=coolms-site
Install registers the theme from its package. Activate binds it to a section — which is why the section is named on the second command and not the first: one theme can serve several sections, and a theme that is installed but bound to nothing is a normal state rather than a half-finished one.
Publish it#
docker compose exec app php bin/console coolms:theme:publish coolms-site
Publishing is a separate step because the templates are copied into the
VFS, and the VFS copy is what renders. Editing a template in the package and
reloading the page shows you the old one until you publish again. This is not an
oversight: a published template can be edited in the admin, so publish will not
overwrite one that has been, and --overwrite is how you say you mean it.
Publishing also builds the theme's block stylesheet — every {css} its
templates and the platform's declare, gathered into one file per theme and
linked from the layout, with comments stripped.
Seed the starting content#
docker compose exec app php bin/console coolms:theme:seed --theme=coolms-site --section=coolms-site
A theme ships a seed/manifest.yaml describing the pages it expects to exist,
the blocks on them and the navigation entries that point at them. Seeding is
idempotent and it refuses a page a human has edited — the report says
refused rather than overwriting, and --force is how you overrule it.
That refusal is the reason seeding is safe to re-run after every change to the manifest, which is how the landing page is maintained.
What you should see#
docker compose exec app php bin/console coolms:navi:seed
Navigation nodes are contributed by modules and by the theme's manifest. With
those seeded, the section has a menu, the menu has entries, and the entries
resolve to pages under /content/<section>.
A section serves on its own host. Reaching the site means reaching the
host the section is bound to. A request that arrives on a host no section claims
lands on the fallback site, which has its own pages — and a /docs/ there that
answers 200 while every page under it answers 404. That combination reads
exactly like a broken install and is not one; check the host before checking the
content.
Next#
Your first process — the half the CMS suffix stopped covering.