Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message
Agents
symfony/maker-bundle
claude-code
cursor
generator
code generator
scaffold
scaffolding
dev

Every maker must also work with --no-interaction. Command::run() skips interact() entirely in that mode, so anything only set there is missing in generate().

Install
php artisan boost:add-skill symfony/maker-bundle

Save this content to: AGENTS.md

# Agents.md

Every maker must also work with `--no-interaction`. `Command::run()` skips `interact()`
entirely in that mode, so anything only set there is missing in `generate()`.

## The one rule

Never keep a value on a property. Put it on the `InputInterface` as an option or
argument. `interact()` asks only when the value is missing and writes the answer onto the
input. `generate()` reads the value from the input, never from a property.

```php
public function interact(InputInterface $input, ConsoleStyle $io, Command $command): void
{
    if (!$input->getOption('controller-class')) {
        $input->setOption('controller-class', $io->ask('...', self::getDefaultControllerClass()));
    }
}

public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void
{
    $controllerClass = $input->getOption('controller-class') ?: self::getDefaultControllerClass();
}
```

A typed property with no default, assigned only in `interact()` and read in `generate()`,
throws `Typed property ... must not be accessed before initialization` under
`--no-interaction`. That shape is what to grep for.

## Guesses need a silent half

A guesser like `InteractiveSecurityHelper::guessUserClass()` returns silently when the
answer is unambiguous, and prompts otherwise with no default. That prompt cannot run
under `--no-interaction`. Extract the silent half into its own method that returns `null`
instead of prompting, have the `guess*` method call it first, and have `generate()` call
it directly and throw a `RuntimeCommandException` naming the option when it returns
`null`.

## Errors must be `RuntimeCommandException`

`ConsoleErrorSubscriber` renders that type onto stdout with exit code 1. Anything else,
including `\InvalidArgumentException` from `Validator::*`, goes to stderr and is invisible
to a caller capturing stdout.

## Booleans are `VALUE_NONE` options, not string arguments

No maker file declares `strict_types`, so a string fed into a `bool` parameter coerces
silently: `"false"` and `"no"` both become `true`.

## Prefer the generic argument prompt

`MakerCommand::interact()` already prompts for any empty declared argument, using its
description as the question, before your maker's own `interact()` runs. If that's good
enough, skip `setArgumentAsNonInteractive()` and the manual `$io->ask()`, and just return
early when the argument is already set. Reach for the manual version only when the
generic prompt isn't enough: autocompletion, a specific validator, a choice list, or
something that must happen before the question is asked.

## Watch for a second `composer require` in one process

If both `interact()` and `generate()` might install a package, don't call
`installDependencyIfNeeded()` unconditionally from both. Its `class_exists()` guard can't
see a class installed earlier in the same process, so a second call installs the package
again, and the second `composer require` corrupts the DI container cache mid-run. Guard
the second call some other way, such as checking whether the config file the recipe
writes already exists.

## Testing

Add a non-interactive happy path per option: `$runner->runMaker([], '<args> --no-interaction')`.
For values with no sensible default, add a rejection case with `allowedToFail: true`,
asserting the message and that nothing was written. On Windows, `cmd.exe` does not treat
single quotes as quoting, use double quotes in test arguments.

Agents.md

Every maker must also work with --no-interaction. Command::run() skips interact() entirely in that mode, so anything only set there is missing in generate().

The one rule

Never keep a value on a property. Put it on the InputInterface as an option or argument. interact() asks only when the value is missing and writes the answer onto the input. generate() reads the value from the input, never from a property.

public function interact(InputInterface $input, ConsoleStyle $io, Command $command): void
{
    if (!$input->getOption('controller-class')) {
        $input->setOption('controller-class', $io->ask('...', self::getDefaultControllerClass()));
    }
}

public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void
{
    $controllerClass = $input->getOption('controller-class') ?: self::getDefaultControllerClass();
}

A typed property with no default, assigned only in interact() and read in generate(), throws Typed property ... must not be accessed before initialization under --no-interaction. That shape is what to grep for.

Guesses need a silent half

A guesser like InteractiveSecurityHelper::guessUserClass() returns silently when the answer is unambiguous, and prompts otherwise with no default. That prompt cannot run under --no-interaction. Extract the silent half into its own method that returns null instead of prompting, have the guess* method call it first, and have generate() call it directly and throw a RuntimeCommandException naming the option when it returns null.

Errors must be RuntimeCommandException

ConsoleErrorSubscriber renders that type onto stdout with exit code 1. Anything else, including \InvalidArgumentException from Validator::*, goes to stderr and is invisible to a caller capturing stdout.

Booleans are VALUE_NONE options, not string arguments

No maker file declares strict_types, so a string fed into a bool parameter coerces silently: "false" and "no" both become true.

Prefer the generic argument prompt

MakerCommand::interact() already prompts for any empty declared argument, using its description as the question, before your maker's own interact() runs. If that's good enough, skip setArgumentAsNonInteractive() and the manual $io->ask(), and just return early when the argument is already set. Reach for the manual version only when the generic prompt isn't enough: autocompletion, a specific validator, a choice list, or something that must happen before the question is asked.

Watch for a second composer require in one process

If both interact() and generate() might install a package, don't call installDependencyIfNeeded() unconditionally from both. Its class_exists() guard can't see a class installed earlier in the same process, so a second call installs the package again, and the second composer require corrupts the DI container cache mid-run. Guard the second call some other way, such as checking whether the config file the recipe writes already exists.

Testing

Add a non-interactive happy path per option: $runner->runMaker([], '<args> --no-interaction'). For values with no sensible default, add a rejection case with allowedToFail: true, asserting the message and that nothing was written. On Windows, cmd.exe does not treat single quotes as quoting, use double quotes in test arguments.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route