prestashop-module-development — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited prestashop-module-development (Agent Skill) and scored it 96/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 1 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Use this skill for PrestaShop module development tasks such as:
Read: references/module-structure.md
Key rules:
PrestaShop\Module\Read: references/module-class-and-installer.md
Key rules:
require_once __DIR__ . '/vendor/autoload.php'; after the _PS_VERSION_ guardConfiguration:: calls directly in install() — delegate to src/Install/Installer.phpInstaller::installTabs() / uninstallTabs()getContent() must only redirect to the Symfony route, never render HTMLhookActionShopDataDuplication and widget methods like getWidgetVariables) must be delegated to the Repository or Manager class via $this->get('service.id')$this->has() + null check in admin context; use plain $this->get() + null check in front-office context. NEVER use `ContainerFinder` — it is unnecessary. See references/module-class-and-installer.md → Guard patterns section.Read: references/configuration-page.md
Key rules:
FrameworkBundleAdminControllerDataConfiguration, FormDataProvider, FormType, Controllerconfig/components/ sub-folders (imported by config/admin/services.yml) and config/routes.ymlRead: references/database-and-entities.md For translatable entities with Grid: read references/entity-doctrine.md
@ORM\Table() with no name= parameterprefix_mymodule_items, prefix_mymodule_items_lang) — to group tables together and avoid conflicts with PS core tablesNOT NULL DEFAULT '' use string $field = ''; columns declared NULL use ?string $field = null'' for NOT NULL string fields: $row->setName((string) ($value ?? '')). Never pass the raw form value directly to a setter on a NOT NULL columnMetadataListener or Doctrine event listeners for table naming(int), use bound parametersInstaller SQL schema queries (CREATE TABLE, DROP TABLE) which have no Repository equivalent.SymfonyContainer::getInstance() returns null in the pr:mo Symfony console context (global $kernel is never set). All Doctrine ORM calls silently do nothing at install time. See references/module-class-and-installer.md → FixturesInstaller section.LIMIT 1 in the SQL string passed to it; causes a MariaDB syntax error.Read: references/services-split.md
Key rules:
config/admin/services.yml and config/front/services.yml are needed; a root-level config/services.yml is never required and should not existconfig/admin/services.yml is loaded by admin kernel only — import ../common.yml + admin components (never common.yml without the ../ prefix)config/common.yml components (Doctrine-level, no PrestaShopBundle deps)PrestaShopBundle-dependent services go in config/admin/services.ymlconfig/components/ — never one flat services.ymlpublic:). Avoid _defaults: public: true as a blanket: it is against Symfony best practices and causes a fatal error in PrestaShop's Symfony version when combined with parent: servicespublic cannot be inherited from _defaults when parent is set (PrestaShop's Symfony version enforces this)$this->get() calls fail silentlyRead: references/security.md
(int) + pSQL() on every value, or use DbQuery builder$_FILES-compatible array (including type, size, error) to ImageManager::validateUpload()Read: references/hooks-and-front-office.md
Installer, not in install() directlyhookDisplayBackOfficeHeaderWidgetInterface for front office widgetsRead: references/theme-template-injection.md
ThemeTemplateInjector (service, reusable) + ThemeTemplateInstaller (install orchestrator)scandir(_PS_ALL_THEMES_DIR_) insteadtrue — theme injection must never block module installRead: references/translations.md
$this->trans('Text', 'Modules.Mymodule.Admin') (never $this->trans('Text', [], 'Domain') — passing [] as domain and a string as $parameters causes a fatal type error)'Text'|trans({}, 'Modules.Mymodule.Admin') in TwigisUsingNewTranslationSystem(): true in the module classRead: references/legacy-conversion.md
Common conversions: HelperForm → Symfony form, jQuery UI sortable → Grid PositionColumn, ModuleAdminController → FrameworkBundleAdminController.
Read: references/services-and-di.md
CRITICAL: Never use legacy static calls in services/controllers:
Context::getContext() — inject $context: "@=service('prestashop.adapter.legacy.context').getContext()" insteadConfiguration::get() / updateValue() — inject @prestashop.adapter.legacy.configuration insteadContext::getContext()->getTranslator() — inject @translator insteadKey rules:
config/components/ sub-folders (imported by config/admin/services.yml)$this->get('service.id') in Symfony controllers@=) for computed constructor arguments (context, language ID, shop ID)#### Symfony Console Commands
Read: references/services-and-di.md → Symfony Console Commands section
CRITICAL: Commands must be registered in config/admin/services.yml (NOT common.yml or front/services.yml):
# config/admin/services.yml
mymodule.command.my_command:
class: Vendor\MyModule\Command\MyCommand
arguments: ["@mymodule.service.my_service"]
tags:
- { name: console.command, command: modulename:action }Key rules:
modulename:action format (e.g., wsautocartrules:create, ws_keepdblight:cleandb)0 for success, 1 for failure (NOT Command::SUCCESS/FAILURE constants)SymfonyStyle for rich console output (tables, progress bars, styled messages)--limit options for batch operations to enable testing with small datasets$this->get()Read: references/cart-rules.md
Complete guide for creating and managing PrestaShop cart rules (discount vouchers) programmatically:
Key patterns:
123456789ABCDEFGHIJKLMNPQRSTUVWXYZ (no O/0 to avoid confusion, same as PrestaShop admin.js)CartRule::getIdByCode($code) before creationname for all active languages via Language::getLanguages(true)$cartRule->id_customer for customer-specific vouchersdate_from and date_to required (format: Y-m-d H:i:s)reduction_percent, reduction_amount, free_shipping, or gift_productquantity, quantity_per_user, priority, highlight, partial_use, activefalse (no restriction); set specific restrictions as neededCommon use cases documented:
Read: references/grid-system.md
Full pattern for building CRUD list pages with the PS Grid system:
GridDefinitionFactory — columns (PositionColumn, ToggleColumn, ActionColumn), filters, row actionsQueryBuilder — Doctrine DBAL query with sorting, pagination, and filtersFilters — default sort/limit settingsconfig/components/grid/ (factory, query, data, grid, position) + 1 Twig FilesystemLoader%kernel.project_dir% is the PS root (parent of app/), so modules/ is a direct child. Never use %kernel.project_dir%/../modules/routes.yml (index, search, toggle, update-position)indexAction, searchAction, toggleStatus, updatePositionAction)ws-entity-grid-skeleton, grid ID replaced via sed)php bin/console pr:mo install mymoduleAI agent rule — NEVER SKIP EITHER STEP. Read references/validation.md for full instructions.vendor/websenso/prestashop-module-devtools/bin/lotrExpected: 🎉 All commands completed successfully! Executed: 6/6
php bin/console pr:mo install mymoduleExpected: L'action Install sur le module … a réussi.
Read: references/debugging.md
Common failure areas:
references/debugging.md — all symptom/cause/fix tables (install, config page, Grid, InputBag, ImageManager, lotr steps)The following files are bundled with this skill in the ps9-core-ai/ directory. Read them for deep understanding of PS9 core architecture, conventions, and patterns.
standards, architecture layers (Core/Adapter/Bundle/Legacy), CQRS pattern, branching policy, and the full index of domain and component contexts.
.ai/ folder itself: how contexts,skills, and pointer files are organized and how AI tools discover them.
Note for skill maintainers: These files are static snapshots from the official PrestaShop repository. To update them, skill maintainers can run lotr --install from a module directory. This is not a runtime operation — the files are pre-bundled and version-controlled with the skill.If your project or organisation defines a steering layer (layered context rules for coding standards, architecture conventions, and project-specific overrides), load the steering files before starting any task.
Finding the resolver — search in this order:
steering/resolver.md at the module root (custom installation)vendor/websenso/prestashop-module-devtools/steering/resolver.md — canonical path when the devtools are installed as a Composer package (same package that provides vendor/websenso/prestashop-module-devtools/bin/lotr)vendor/*/*/steering/resolver.md — scan all vendor subfolders for a steering/resolver.md file (use the first match found)If none exists, skip steering silently and apply only the skill defaults.
Typical steering structure (paths relative to wherever the resolver is found):
steering/resolver.md ← load order and conflict rules
steering/company/ ← organisation-wide standards
steering/languages/php/coding-standards.md ← PHP conventions
steering/frameworks/prestashop/ ← PrestaShop-specific rulesLoad steering files from lowest to highest priority (company → language → framework → project). Later layers override earlier ones.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.