This is a Symfony project. Check composer.json for the exact Symfony/PHP version in use, and read symfony.lock to see which recipes ran. Don't assume Doctrine, Twig, API Platform, Messenger, or Lock are installed unless one of those says so.
php artisan boost:add-skill xver/php-auth-core
Save this content to: AGENTS.md
# AGENTS.md
This is a Symfony project. Check `composer.json` for the exact Symfony/PHP version
in use, and read `symfony.lock` to see which recipes ran. Don't assume Doctrine,
Twig, API Platform, Messenger, or Lock are installed unless one of those says so.
## Ask before generating
If the task doesn't specify, ask rather than guess:
- Persistence: Doctrine ORM, Doctrine ODM, or none?
- Interface: server-rendered (Twig), API (Serializer, maybe API Platform), or both?
- Auth: SecurityBundle, and which authenticator?
If you can't ask (no interactive channel), state the assumption you're making and
pick the smallest option (e.g. no persistence layer) rather than scaffolding a
full stack nobody asked for.
## Adding features: Flex, not hand-wiring
Install new capabilities with `composer require <package>` (e.g. `symfony/lock`,
`symfony/messenger`, `orm-pack`) and let the Flex recipe register the bundle and
generate its config. Don't hand-edit `config/bundles.php` or hand-write a bundle's
base config; that's what the recipe is for. Don't skip a good-fit component just
because it isn't installed yet; installing it is one command.
## Conventions
Follow https://symfony.com/doc/current/best_practices.html to write idiomatic
Symfony:
- Use PHP attributes for framework metadata, and not only on controllers:
`#[Route]`, `#[MapRequestPayload]`, `#[IsGranted]` on actions, `#[Assert\...]`
on properties, `#[AsCommand]`, `#[AsEventListener]`, `#[AsMessageHandler]`, and
`#[AsAlias]` / `#[AsTaggedItem]` / `#[Autoconfigure]` on services. No YAML or
XML routing.
- Rely on autowiring and autoconfiguration. Type-hint constructor arguments and
let the container resolve them. Where a type-hint can't express it, stay in the
class with `#[Autowire]` (parameters, env vars, expressions) or `#[Target]` (one
of several implementations of an interface). A YAML service definition is the
last resort, not the first.
- Controllers extend `AbstractController`, stay thin, and delegate to services.
- Use the framework for what it already does: Form for server-rendered forms,
Validator for validation, Serializer for JSON, Messenger for async work,
Security (voters, authenticators) for access control, Twig `path()`/`url()`
instead of hardcoded URLs.
- Before hand-writing infrastructure (locks, queues, caches, HTTP clients,
mailers, schedulers) or reaching for a third-party library, check whether a
Symfony component covers it. It usually does.
Three specifics worth spelling out, because they are easy to get wrong:
- Bind request data with `#[MapRequestPayload]` / `#[MapQueryString]` on action
arguments, which wires up Serializer and Validator for you, instead of calling
`json_decode()` or `SerializerInterface` by hand. If neither package is
installed yet, `composer require` them rather than falling back to manual
parsing.
- Use constructor property promotion, and `readonly` for DTOs and value objects.
- Use `symfony/lock` (`LockFactory`) for mutual exclusion. A hand-built flag or
lock file looks fine in review and is usually wrong under concurrency.
## Everyday workflow
- Run the app with `symfony serve -d`, and commands with `symfony console ...`
(or `bin/console` when the Symfony CLI isn't available).
- When something fails, read `var/log/dev.log` and the web profiler
(`/_profiler`) before changing code.
- If `maker-bundle` is installed, prefer `bin/console make:*` with every argument
passed up front and `--no-interaction` where supported: makers prompt on a
terminal by default, which hangs a non-interactive shell. If a maker still
needs interactive input, hand-write the code instead.
- If Doctrine ORM is installed, schema changes go through migrations
(`bin/console make:migration`, then `doctrine:migrations:migrate`), never
`doctrine:schema:update` or hand-written SQL.
- `.env` is committed and holds defaults only. Real secrets belong in `.env.local`
(git-ignored) or the secrets vault (`bin/console secrets:set`), read via
`%env(...)%`.
## Testing
This project's PHP runtime is provided by Devbox. If `php` or other project tools
are missing from the shell, run them inside the project environment with
`devbox run -- <command>`; don't assume the host has PHP installed. For example,
run tests with `devbox run -- php bin/phpunit` (or
`devbox run -- vendor/bin/phpunit`) and check the runtime with
`devbox run -- php -v`.
Install `symfony/test-pack` if it isn't already. Functional/HTTP tests extend
`WebTestCase`; service-level tests extend `KernelTestCase`. A feature isn't done
until it has a test that exercises it the way a caller would, an HTTP request for
a controller or a service call for a service, not just "it didn't throw."
## Code style
Symfony's coding standard, the `@Symfony` php-cs-fixer ruleset (a PSR-12-derived
superset). Run `vendor/bin/php-cs-fixer fix` if `friendsofphp/php-cs-fixer` is
installed; it isn't part of the skeleton by default.
## Discover, don't guess
Framework APIs change between versions and your training data may be stale. Look
things up in the project instead of relying on memory:
- `bin/console about`: versions, environment, paths.
- `bin/console debug:router`, `debug:container`, `debug:autowiring <name>`,
`debug:config <bundle>`, `config:dump-reference <bundle>`: what exists and how
it is configured.
- `bin/console lint:container`, plus `lint:twig templates/` and
`lint:yaml config/` where those packages are installed: validate before running.
- Read the installed source and docblocks under `vendor/`.
- Docs: https://symfony.com/doc/current/ (switch to the version matching
`composer.json` if it differs).
This is a Symfony project. Check composer.json for the exact Symfony/PHP version
in use, and read symfony.lock to see which recipes ran. Don't assume Doctrine,
Twig, API Platform, Messenger, or Lock are installed unless one of those says so.
If the task doesn't specify, ask rather than guess:
If you can't ask (no interactive channel), state the assumption you're making and pick the smallest option (e.g. no persistence layer) rather than scaffolding a full stack nobody asked for.
Install new capabilities with composer require <package> (e.g. symfony/lock,
symfony/messenger, orm-pack) and let the Flex recipe register the bundle and
generate its config. Don't hand-edit config/bundles.php or hand-write a bundle's
base config; that's what the recipe is for. Don't skip a good-fit component just
because it isn't installed yet; installing it is one command.
Follow https://symfony.com/doc/current/best_practices.html to write idiomatic Symfony:
#[Route], #[MapRequestPayload], #[IsGranted] on actions, #[Assert\...]
on properties, #[AsCommand], #[AsEventListener], #[AsMessageHandler], and
#[AsAlias] / #[AsTaggedItem] / #[Autoconfigure] on services. No YAML or
XML routing.#[Autowire] (parameters, env vars, expressions) or #[Target] (one
of several implementations of an interface). A YAML service definition is the
last resort, not the first.AbstractController, stay thin, and delegate to services.path()/url()
instead of hardcoded URLs.Three specifics worth spelling out, because they are easy to get wrong:
#[MapRequestPayload] / #[MapQueryString] on action
arguments, which wires up Serializer and Validator for you, instead of calling
json_decode() or SerializerInterface by hand. If neither package is
installed yet, composer require them rather than falling back to manual
parsing.readonly for DTOs and value objects.symfony/lock (LockFactory) for mutual exclusion. A hand-built flag or
lock file looks fine in review and is usually wrong under concurrency.symfony serve -d, and commands with symfony console ...
(or bin/console when the Symfony CLI isn't available).var/log/dev.log and the web profiler
(/_profiler) before changing code.maker-bundle is installed, prefer bin/console make:* with every argument
passed up front and --no-interaction where supported: makers prompt on a
terminal by default, which hangs a non-interactive shell. If a maker still
needs interactive input, hand-write the code instead.bin/console make:migration, then doctrine:migrations:migrate), never
doctrine:schema:update or hand-written SQL..env is committed and holds defaults only. Real secrets belong in .env.local
(git-ignored) or the secrets vault (bin/console secrets:set), read via
%env(...)%.This project's PHP runtime is provided by Devbox. If php or other project tools
are missing from the shell, run them inside the project environment with
devbox run -- <command>; don't assume the host has PHP installed. For example,
run tests with devbox run -- php bin/phpunit (or
devbox run -- vendor/bin/phpunit) and check the runtime with
devbox run -- php -v.
Install symfony/test-pack if it isn't already. Functional/HTTP tests extend
WebTestCase; service-level tests extend KernelTestCase. A feature isn't done
until it has a test that exercises it the way a caller would, an HTTP request for
a controller or a service call for a service, not just "it didn't throw."
Symfony's coding standard, the @Symfony php-cs-fixer ruleset (a PSR-12-derived
superset). Run vendor/bin/php-cs-fixer fix if friendsofphp/php-cs-fixer is
installed; it isn't part of the skeleton by default.
Framework APIs change between versions and your training data may be stale. Look things up in the project instead of relying on memory:
bin/console about: versions, environment, paths.bin/console debug:router, debug:container, debug:autowiring <name>,
debug:config <bundle>, config:dump-reference <bundle>: what exists and how
it is configured.bin/console lint:container, plus lint:twig templates/ and
lint:yaml config/ where those packages are installed: validate before running.vendor/.composer.json if it differs).How can I help you explore Laravel packages today?