- PHP >= 8.2
- Composer 2
composer create-project marrow/skeleton my-app
cd my-app
cp .env.example .env
php forge key:generate
php forge migrate --seed
npm install
php forge serve --watch-css # PHP server + Vite dev server togetherVisit http://localhost:8080.
| Path | Purpose |
|---|---|
bootstrap/app.php |
Builds the Application instance — the one place public/index.php and forge both require |
public/index.php |
HTTP front controller — point your web server here |
forge |
Console entry point (php forge list) |
bin/server.php |
Router used by php forge serve / php -S |
config/ |
One file per subsystem — see Configuration |
modules/Account/ |
Owns the User model, RBAC/2FA/audit-log migrations, and the roles seeder — no routes of its own |
modules/Home/ |
A minimal working HMVC module (/ and /health) |
database/migrations/ |
Queue + notifications tables (framework infrastructure, not owned by any one module) |
database/seeders/ |
The master DatabaseSeeder, which delegates to Account's own seeder |
resources/views/ |
Twig templates — only layouts/ ships by default; errors/components/partials/emails are auto-registered as Twig namespaces the moment you create them |
resources/{css,js}/, vite.config.js, package.json |
Vite + Tailwind CSS v4 build pipeline — see Frontend Assets |
tests/ |
Pest, wired to boot the real Application and dispatch through Http\Kernel |
There is no
app/directory, and that's deliberate. Authentication isn't framework-level glue — it's a domain concern, soUserand its schema live in theAccountmodule instead of a genericapp/Models/. Everymake:*generator still defaults toapp/...when--moduleis omitted and creates that directory itself on demand (@mkdir(..., 0755, true)before writing) — see TheforgeCLI for the exact default path each one writes to — but nothing forces you to use it. Prefer--module=Namefor anything that belongs to a specific domain, the wayAccountandHomedo here.Controllers always live in a module. Routing only ever loads
modules/*/routes.php— there is no global route file forapp/. A controller generated withphp forge make:controllerand no--modulelands inapp/Controllers/, but nothing will ever route to it. Always pass--module=Name.
php forge make:module BlogThen enable it in config/modules.php:
'enabled' => [
\Modules\Account\AccountModule::class,
\Modules\Home\HomeModule::class,
\Modules\Blog\BlogModule::class,
],This skeleton ships with just the framework itself — nothing else is
bundled by default, so composer install stays fast and the dependency
tree stays small. Add any of these yourself when you actually need them:
composer require marrow/form-builder # Django-style backend forms
composer require --dev marrow/anvil # Docker Compose dev environment
composer require --dev marrow/ai-context # generates AGENTS.md for AI coding agentsEach registers itself automatically on install (package auto-discovery — see Modules), no config edit needed. See each package's own README for usage.
Full framework documentation lives in the
framework repository's docs/,
starting with Getting Started.
See CHANGELOG.md.
MIT — see LICENSE.
Made with ❤️ by Aure Dulvresse