php artisan boost:add-skill redaxo/source
Save this content to: AGENTS.md
---
package: redaxo/source
source_path: AGENTS.md
repo: https://github.com/redaxo/core
---
# AGENTS.md
This file provides guidance to AI coding assistants working with code in this repository.
## Project Overview
REDAXO is a PHP Content Management System. This repository (`redaxo/core`) contains the core. PHP 8.5+ is required.
The default development branch is `6.x` — PRs target this branch unless stated otherwise. `5.x` is the maintenance branch.
## Common Commands
### Quality Checks
```bash
composer check # Run all checks (cs + sa + phpunit + taint)
composer cs # Code style: rector + php-cs-fixer (fixes in place — no dry-run script)
composer sa # Static analysis: phpstan + psalm
composer phpunit # Run all test suites
composer baseline # Regenerate all analysis baselines
```
### Individual Tools
```bash
composer phpstan # PHPStan
composer psalm # Psalm
composer psalm:no-cache # Psalm with a cleared cache (see note below)
composer taint # Psalm taint analysis
composer rector # Rector
composer cs-fixer # php-cs-fixer
```
> **Stale Psalm cache:** If `composer psalm` reports errors that look unrelated to your changes (or that disappear/reappear
> depending on which files you touched), rerun with `composer psalm:no-cache` before assuming the errors are real or going
> through git-stash gymnastics to compare against the baseline.
### Running a Single Test
```bash
vendor/bin/phpunit --filter testMethodName
vendor/bin/phpunit tests/Database/SqlTest.php
```
### Console & Docker
```bash
php project/bin/console # List all CLI commands (Symfony Console)
php project/bin/console setup:run # Run setup
php project/bin/console migrate # Sync DB schema with core + addons after a code update
docker-compose up -d # Start (port 80)
REDAXO_PORT=8080 docker-compose up -d # Start on custom port
```
## Architecture
### What belongs to this repo
This repository **is** the `redaxo/core` package — the package is the whole repository root, not a subdirectory. Everything in the root ships as core except the dev-only paths excluded from the dist via `.gitattributes` `export-ignore` (notably `addons/`, `project/`, `tests/`, the dotfiles and the analysis configs). Core's PHP classes (`Redaxo\Core\`) live in `src/`, but core equally comprises the boot sequence (`boot/`), backend pages (`pages/`), fragment templates (`fragments/`), translations (`lang/`), setup (`setup/`), DB schemas (`schemas/`) and assets (`assets/`, `assets_src/`).
Two addons live under `addons/`, but they are different in nature: **`debug`** is the `redaxo/debug` package — a real, published addon that is split out into a standalone repository via git subtree split and required here only as a dev dependency. **`test`** is an internal helper used solely within this repo for testing and is *not* published.
The **`project/` skeleton** is the `redaxo/project` package — published standalone via git subtree split and used with `composer create-project` — which also doubles as this repo's local development instance (see *Local dev instance* below). Visual-test fixtures (modules/templates) live under `.tools/fixtures/` (namespace `Redaxo\Core\Fixtures`), so they stay out of the shipped skeleton.
### Key concepts
- **`Core` static class** (`src/Core.php`) — central application registry for paths, config, request, current user.
- **Addon system** — `Addon` / `AddonManager` (`src/Addon/`). Each addon is a subclass of `Addon`, registered via composer.json `extra.redaxo.addon-class`. Metadata comes from composer.json; integration happens through overridable hooks — `boot()` (runtime init), `install()`/`uninstall()` (schema/data setup — must be idempotent, runs on every `console migrate`), `getPages()` (backend pages) — plus the `$load` and `$defaultConfig` properties.
- **Extension points** — REDAXO's hook/event system: register listeners with `Extension::register('NAME', ...)`, fire points with `Extension::dispatch(new ExtensionPoint(...))`. Classes live under `Redaxo\Core\ExtensionPoint`. This is the primary integration mechanism for addons.
- **Fragments** (`fragments/`) — template snippets rendered via `Fragment` (`src/View/Fragment.php`).
- **Boot flow** — `AbstractProject` (Symfony `RuntimeInterface`) drives boot via `boot/core.php` → `boot/addons.php` → environment entry (`boot/backend.php`, `boot/frontend.php`, `boot/console.php`). The entry points live in the project (`project/public/index.php`, `project/public/redaxo/index.php`, `project/bin/console`).
- **Local dev instance** — `project/` is loaded as a Composer path repo and symlinked into `vendor/redaxo/project`. `composer install`/`update` runs `.tools/bin/init-project`, which writes the gitignored `project/vendor/autoload_runtime.php` shim (delegating to the root autoloader). Run the app via `project/bin/console` and the `project/public/` document root; runtime data lives in `project/var/` (gitignored).
### Class naming
All core classes live in the `Redaxo\Core\` namespace, mapped to `src/`. Tests live under `tests/` mirroring the `src/` layout, namespace `Redaxo\Core\Tests`, files named `*Test.php`.
## Coding Standards
- 4 spaces indentation, LF line endings, UTF-8
- Soft line limit ~120 chars (applies to comments too — don't wrap at 80)
- Code style enforced by rector + php-cs-fixer (custom REDAXO config) — run `composer cs` after edits
- PHPStan level 6 + Psalm level 1, both with baselines in `.tools/phpstan/` and `.tools/psalm/`
- PHPUnit strict mode: warnings, notices, deprecations all fail the build
- In YAML files, prefer single quotes when quoting is needed
- Comments and commit messages in English; commits use conventional commits (`feat:`, `fix:`, `refactor:`, `docs:`, `chore:`, `test:`, `style:`, `ci:`)
- **Properties**: prefer modern public properties (with `readonly`, asymmetric visibility, property hooks as appropriate) over getter/setter methods
### Baselines
The static analysis baselines exist to grandfather pre-existing issues. **New code must not add to the baselines** — fix the issue instead. Only regenerate baselines (`composer baseline`) when intentionally accepting new findings, and call that out in the PR.
## Backwards Compatibility
- `6.x` is actively under development and has not shipped a stable release yet. Breaking changes to public APIs are acceptable while we still can — prefer **fixing the design** over piling on `@deprecated` shims.
- `@internal`-marked symbols may change without notice.
- DB schema changes belong in the relevant install/update path.
- Behavior that needs to stay aligned with `5.x` (because changes are regularly merged up) should be kept structurally close to its `5.x` counterpart unless the divergence is intentional.
This file provides guidance to AI coding assistants working with code in this repository.
REDAXO is a PHP Content Management System. This repository (redaxo/core) contains the core. PHP 8.5+ is required.
The default development branch is 6.x — PRs target this branch unless stated otherwise. 5.x is the maintenance branch.
composer check # Run all checks (cs + sa + phpunit + taint)
composer cs # Code style: rector + php-cs-fixer (fixes in place — no dry-run script)
composer sa # Static analysis: phpstan + psalm
composer phpunit # Run all test suites
composer baseline # Regenerate all analysis baselines
composer phpstan # PHPStan
composer psalm # Psalm
composer psalm:no-cache # Psalm with a cleared cache (see note below)
composer taint # Psalm taint analysis
composer rector # Rector
composer cs-fixer # php-cs-fixer
Stale Psalm cache: If
composer psalmreports errors that look unrelated to your changes (or that disappear/reappear depending on which files you touched), rerun withcomposer psalm:no-cachebefore assuming the errors are real or going through git-stash gymnastics to compare against the baseline.
vendor/bin/phpunit --filter testMethodName
vendor/bin/phpunit tests/Database/SqlTest.php
php project/bin/console # List all CLI commands (Symfony Console)
php project/bin/console setup:run # Run setup
php project/bin/console migrate # Sync DB schema with core + addons after a code update
docker-compose up -d # Start (port 80)
REDAXO_PORT=8080 docker-compose up -d # Start on custom port
This repository is the redaxo/core package — the package is the whole repository root, not a subdirectory. Everything in the root ships as core except the dev-only paths excluded from the dist via .gitattributes export-ignore (notably addons/, project/, tests/, the dotfiles and the analysis configs). Core's PHP classes (Redaxo\Core\) live in src/, but core equally comprises the boot sequence (boot/), backend pages (pages/), fragment templates (fragments/), translations (lang/), setup (setup/), DB schemas (schemas/) and assets (assets/, assets_src/).
Two addons live under addons/, but they are different in nature: debug is the redaxo/debug package — a real, published addon that is split out into a standalone repository via git subtree split and required here only as a dev dependency. test is an internal helper used solely within this repo for testing and is not published.
The project/ skeleton is the redaxo/project package — published standalone via git subtree split and used with composer create-project — which also doubles as this repo's local development instance (see Local dev instance below). Visual-test fixtures (modules/templates) live under .tools/fixtures/ (namespace Redaxo\Core\Fixtures), so they stay out of the shipped skeleton.
Core static class (src/Core.php) — central application registry for paths, config, request, current user.Addon / AddonManager (src/Addon/). Each addon is a subclass of Addon, registered via composer.json extra.redaxo.addon-class. Metadata comes from composer.json; integration happens through overridable hooks — boot() (runtime init), install()/uninstall() (schema/data setup — must be idempotent, runs on every console migrate), getPages() (backend pages) — plus the $load and $defaultConfig properties.Extension::register('NAME', ...), fire points with Extension::dispatch(new ExtensionPoint(...)). Classes live under Redaxo\Core\ExtensionPoint. This is the primary integration mechanism for addons.fragments/) — template snippets rendered via Fragment (src/View/Fragment.php).AbstractProject (Symfony RuntimeInterface) drives boot via boot/core.php → boot/addons.php → environment entry (boot/backend.php, boot/frontend.php, boot/console.php). The entry points live in the project (project/public/index.php, project/public/redaxo/index.php, project/bin/console).project/ is loaded as a Composer path repo and symlinked into vendor/redaxo/project. composer install/update runs .tools/bin/init-project, which writes the gitignored project/vendor/autoload_runtime.php shim (delegating to the root autoloader). Run the app via project/bin/console and the project/public/ document root; runtime data lives in project/var/ (gitignored).All core classes live in the Redaxo\Core\ namespace, mapped to src/. Tests live under tests/ mirroring the src/ layout, namespace Redaxo\Core\Tests, files named *Test.php.
composer cs after edits.tools/phpstan/ and .tools/psalm/feat:, fix:, refactor:, docs:, chore:, test:, style:, ci:)readonly, asymmetric visibility, property hooks as appropriate) over getter/setter methodsThe static analysis baselines exist to grandfather pre-existing issues. New code must not add to the baselines — fix the issue instead. Only regenerate baselines (composer baseline) when intentionally accepting new findings, and call that out in the PR.
6.x is actively under development and has not shipped a stable release yet. Breaking changes to public APIs are acceptable while we still can — prefer fixing the design over piling on @deprecated shims.@internal-marked symbols may change without notice.5.x (because changes are regularly merged up) should be kept structurally close to its 5.x counterpart unless the divergence is intentional.How can I help you explore Laravel packages today?