These are natural-language guidelines for agents to follow when developing the Decker WordPress plugin.
- Follow WordPress Coding Standards:
- PHP code: 4 spaces indentation, PSR‑12 style where compatible, proper escaping, sanitization, use WP APIs.
- Use English for source code (identifiers, comments, docblocks).
- Use Spanish for user‑facing translations/strings and test assertions to check no untranslated strings remain.
- Use TDD (Test‑Driven Development) with factories to create test fixtures.
- Tests live under
/tests/and use factory classes. - Use
make lint(PHP lint) andmake fix(beautifier) to enforce standards. - Use
make testto run all unit tests. - Use
make check-untranslatedto detect any untranslated Spanish strings. - Before every
git push/ opening a PR: run at leastmake lint,make testandmake check-untranslated(see the pre-push gate below).
- Develop plugin within
@wordpress/envenvironment. - Use Alpine‑based Docker containers if setting up with Docker.
- For Linux commands: assume Ubuntu Server.
- On macOS desktop (when relevant): use Homebrew to install tools.
- Use
vimas terminal editor, notnano.
- In admin or public UI, use Bootstrap 5 and jQuery consistently.
- Keep frontend assets minimal: enqueue properly via WP APIs, use minified versions.
- All PHP functions and methods must have English docblock comments immediately before declaration.
- Prefer simplicity and clarity: avoid overly complex abstractions.
- Load translation strings properly (
__(),_e()), text domain declared in main plugin file. - Keep plugin bootstrap file small (
decker.php), modularize into separate files/classes with specific responsibility.
- Every time you add, change or remove a user-facing string (PHP
__()/_e()/_n()/_x(), JavaScript strings localized viawp_localize_script, etc.) you MUST update the translation catalogues in the same change set — never defer this to a follow-up commit:- Run
make check-untranslated(orcomposer check-untranslated) to regeneratelanguages/decker.pot, refreshlanguages/decker-es_ES.poand rebuild the.mofiles. - Translate every new
msgidinto Spanish (project default user-facing language). Theuntranslatedstep fails the build if anymsgstr ""is left fordecker-es_ES.po, so the PR cannot be considered done untilmsgattrib --untranslated languages/decker-es_ES.pooutputs nothing. - Commit
languages/decker.pot,languages/decker-es_ES.poandlanguages/decker-es_ES.motogether with the code that introduced the strings.
- Run
- Plural strings must use
_n( 'singular', 'plural', $count, 'decker' )and add anmsgid_pluralblock with bothmsgstr[0]andmsgstr[1]translated. - Strings exposed to JavaScript must travel through
wp_localize_script()so they end up inside the.pot; do not hard-code English text in JS files. - Every i18n call that contains a placeholder (
%s,%d,%1$s, …) MUST be preceded by atranslators:comment describing each placeholder. PHPCS (WordPress.WP.I18n.MissingTranslatorsComment) fails CI without it. Use/* translators: ... */(or// translators: ...) directly above the call. Example:When the call is inside an HTML attribute, hoist the result into a PHP variable in a regular/* translators: %d is the number of comments on the task. */ $title = sprintf( _n( '%d comment', '%d comments', $count, 'decker' ), $count );
<?php ... ?>block first, then echo the variable in the attribute — splitting the<?phpblock inside an attribute leaks indentation whitespace into the rendered HTML.
Never push or open a PR without verifying translations. CI runs make check-untranslated (.github/workflows/ci.yml) and fails the job if any Spanish msgstr is empty.
Before git push or gh pr create:
- Search the diff for new/changed
__()/_e()/_n()/_x()strings (including strings passed towp_localize_script()). - Update
languages/decker-es_ES.poin the same commit (Spanishmsgstrfilled in — not left blank), together withlanguages/decker.potandlanguages/decker-es_ES.mo. - Run
make check-untranslatedand confirm it exits 0. - If it fails, fix the empty
msgstrentries (and re-run) before pushing.
Do not treat “tests passed” as enough for a push: PHPUnit does not catch missing .po entries. Untranslated strings are a CI blocker, same as lint failures.
- Align
@paramblocks so all variable names start at the same column, leaving exactly one space between the longest type name and its$variable. Example for a function whose longest type isDateTime:Adding extra spaces before/** * @param int $task_id Target task post ID. * @param int[] $assigned_users Author candidates. * @param DateTime $start_date Earliest plausible date. */
$task_idtriggersSquiz.Commenting.FunctionComment.SpacingAfterParamType— PHPCS expects the minimum spacing that keeps every$variablealigned with the longest type, not more.
Recurring procedures live as skills in .agents/skills/, the path GitHub
Copilot, Codex and other agents read directly. Claude Code reads
.claude/skills/, which contains symlinks to those same directories, not
copies. When adding a skill, create it in .agents/skills/ and link it from
.claude/skills/; never duplicate a SKILL.md.
| Skill | Read it before | Origin |
|---|---|---|
wp-plugin-development |
Touching hooks, activation/uninstall, the Settings API, options, cron or release packaging | WordPress/agent-skills, GPL-2.0-or-later |
wp-rest-api |
Adding or debugging routes: register_rest_route, permission_callback, schema/args, register_meta, show_in_rest (the Decker_Tasks_Rest_* classes) |
idem |
wp-plugin-directory-guidelines |
Editing readme.txt, license headers or plugin naming — this is what make check-plugin enforces |
idem |
blueprint |
Editing blueprint.json or the Playground preview |
idem |
security-audit |
Hunting vulnerabilities and validating findings | cloudflare/security-audit-skill |
All of them are third party and vendored verbatim. Do not reformat or edit them: diverging from upstream makes future updates harder. Fix the problem upstream and re-vendor instead.
skills-lock.json records provenance for skills fetched with a skills
installer; security-audit is the only one so far. The WordPress/agent-skills
set was vendored by hand and is therefore not listed there.
Skills, AGENTS.md and CLAUDE.md are excluded from the release ZIP via
.gitattributes.
- Always load
AGENTS.mdas conventions file: e.g./read AGENTS.mdor via config. - Do not expect Aider to modify
AGENTS.mdorREADME.mdcontents. - Use
/askmode to plan large changes, then use/codeor/architectto apply. - Review every diff Aider produces, especially in architect mode before accepting.
- After planning, say “go ahead” to proceed.
- Avoid adding unnecessary files to the chat—add only those being modified.