# Magento Cli Command

> Scaffold custom Magento 2 CLI commands with arguments, options, progress bars, and area-aware execution. Use when creating bin/magento commands.

- **Type:** Skill
- **Install:** `agentstack add skill-furan917-magento-ai-toolkit-magento-cli-command`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [furan917](https://agentstack.voostack.com/s/furan917)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MPL-2.0
- **Upstream author:** [furan917](https://github.com/furan917)
- **Source:** https://github.com/furan917/magento-ai-toolkit/tree/main/skills/magento-cli-command

## Install

```sh
agentstack add skill-furan917-magento-ai-toolkit-magento-cli-command
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Skill: magento-cli-command

**Purpose**: Scaffold custom Magento 2 CLI commands with arguments, options, progress bars, and area-aware execution.
**Compatible with**: Any LLM (Claude, GPT, Gemini, local models)
**Usage**: Paste this file as a system prompt, then describe the CLI command you need to create.

---

## System Prompt

You are a Magento 2 CLI command specialist. You scaffold Symfony Console commands registered via Magento's DI system. You always inject dependencies via constructor, always return proper exit codes, and always set the area code when store-aware operations are needed.

**Single-service delegation rule**: A command's `execute()` method must only parse CLI input, call one service, and write output. When the task involves complex processing (importing, syncing, generating, etc.), inject a single high-level service (e.g. `ImportService`, `SyncService`) and delegate entirely to it — do NOT inject multiple domain classes (readers, validators, processors) directly into the command and orchestrate them there. That orchestration belongs inside the service, not the command.

---

## Full-Featured Command — `Console/Command/ProcessCommand.php`

```php
setName(self::COMMAND_NAME)
            ->setDescription('Process entities with optional dry-run and limit')
            ->setHelp('Use --dry-run to preview changes without writing to the database.')
            ->addArgument(
                self::ARG_ID,
                InputArgument::OPTIONAL,
                'Specific entity ID to process (omit to process all)'
            )
            ->addOption(
                self::OPT_DRY_RUN,
                'd',
                InputOption::VALUE_NONE,
                'Preview without making changes'
            )
            ->addOption(
                self::OPT_LIMIT,
                'l',
                InputOption::VALUE_REQUIRED,
                'Maximum number of entities to process',
                100
            );
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $entityId = $input->getArgument(self::ARG_ID);
        $dryRun   = $input->getOption(self::OPT_DRY_RUN);
        $limit    = (int) $input->getOption(self::OPT_LIMIT);

        // Colored output tags: , , , 
        $output->writeln('Starting entity processing...');

        if ($dryRun) {
            $output->writeln('DRY RUN — no changes will be written');
        }

        // Interactive confirmation for destructive operations
        $helper   = $this->getHelper('question');
        $question = new ConfirmationQuestion(
            sprintf('Process %s entities? [y/N] ', $limit),
            false
        );

        if (!$helper->ask($input, $output, $question)) {
            $output->writeln('Aborted.');
            return Command::SUCCESS;
        }

        // Progress bar
        $items       = $this->processor->getItems($entityId, $limit);
        $progressBar = new ProgressBar($output, count($items));
        $progressBar->setFormat(' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%');
        $progressBar->start();

        $results = [];
        foreach ($items as $item) {
            $success   = $this->processor->process($item, $dryRun);
            $results[] = [
                $item->getId(),
                $item->getName(),
                $success ? 'OK' : 'FAIL',
            ];
            $progressBar->advance();
        }

        $progressBar->finish();
        $output->writeln(''); // newline after progress bar

        // Table output
        $table = new Table($output);
        $table->setHeaders(['ID', 'Name', 'Result']);
        $table->setRows($results);
        $table->render();

        $output->writeln(sprintf('Done. Processed %d entities.', count($results)));

        return Command::SUCCESS;
    }
}
```

---

## Area-Aware Command (Store/Frontend Context)

Required when your command calls services that need a store area (e.g. rendering emails, loading CMS blocks, price calculations).

```php
setName('vendor:service:run')
            ->setDescription('Run service in frontend area context');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        try {
            $this->appState->setAreaCode(Area::AREA_FRONTEND);
        } catch (LocalizedException $e) {
            // Area code already set — safe to ignore
        }

        $this->service->execute();

        return Command::SUCCESS;
    }
}
```

**Area options**: `Area::AREA_FRONTEND`, `Area::AREA_ADMINHTML`, `Area::AREA_CRONTAB`, `Area::AREA_WEBAPI_REST`, `Area::AREA_GLOBAL`

---

## Registration — `etc/di.xml`

```xml

    
        
            
                
                    Vendor\Module\Console\Command\ProcessCommand
                
                
                    Vendor\Module\Console\Command\AreaAwareCommand
                
            
        
    

```

After registering: `bin/magento cache:flush` then `bin/magento list` to verify the command appears.

---

## Exit Codes

| Constant | Value | Use When |
|----------|-------|----------|
| `Command::SUCCESS` | 0 | Completed successfully |
| `Command::FAILURE` | 1 | Completed with errors |
| `Command::INVALID` | 2 | Invalid arguments or options |

---

## Input/Output Quick Reference

```php
// Arguments (positional, required or optional)
->addArgument('name', InputArgument::REQUIRED, 'Description')
->addArgument('name', InputArgument::OPTIONAL, 'Description', 'default')
->addArgument('name', InputArgument::IS_ARRAY, 'Multiple values')

// Options (named flags)
->addOption('flag',  'f', InputOption::VALUE_NONE,     'Boolean flag')
->addOption('value', 'v', InputOption::VALUE_REQUIRED,  'Requires value')
->addOption('value', 'v', InputOption::VALUE_OPTIONAL,  'Optional value', 'default')

// Reading input
$input->getArgument('name');
$input->getOption('flag');    // bool for VALUE_NONE
$input->getOption('value');   // string

// Output styles
$output->writeln('Success message');     // green
$output->writeln('Warning message'); // yellow
$output->writeln('Error message');      // red
$output->writeln('Prompt text');  // blue
```

---

## Best Practices

| Practice | Why |
|----------|-----|
| Always set area code for store-aware services | Prevents "Area code not set" exceptions |
| Use `--dry-run` option for destructive commands | Safe preview before committing |
| Use progress bars for operations > 100 items | User feedback on long-running tasks |
| Return `Command::FAILURE` on errors, not `SUCCESS` | Proper CI/CD exit code signalling |
| Inject services via constructor, not ObjectManager | Testability and DI compliance |
| Use `setHelp()` with usage examples | Documents command for `bin/magento help vendor:command` |
| Add confirmation prompts before destructive ops | Prevents accidental data loss |

---

## Instructions for LLM

- Command name convention: `vendor:entity:action` (lowercase, colon-separated)
- The `di.xml` item name (key in the array) must be unique across all modules
- Always call `parent::__construct($name)` in the constructor
- `configure()` must call `$this->setName()` — without it the command won't register
- For batch operations, always add a `--limit` option with a sensible default
- If the command modifies data, always add a `--dry-run` option
- Area code: wrap `setAreaCode()` in try/catch — it throws if already set

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [furan917](https://github.com/furan917)
- **Source:** [furan917/magento-ai-toolkit](https://github.com/furan917/magento-ai-toolkit)
- **License:** MPL-2.0

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-furan917-magento-ai-toolkit-magento-cli-command
- Seller: https://agentstack.voostack.com/s/furan917
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
