PluginProbe
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF / trunk
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF vtrunk
2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.9 2.2.8 trunk 1.10 1.3.3 1.3.4 1.3.5 1.3.5.1 1.3.5.2 1.3.6 1.3.6.1 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.5 All 103 releases
← All changes | AGENTS.md +107 -286 2.3.1 → trunk View file →
@@ -1,343 +1,157 @@
1 -# Imagify – AI Coding & Architecture Guidelines
1 +# Imagify — project instructions for AI agents
2 2
3 -This file defines NON-NEGOTIABLE rules for any AI-assisted work
4 -(Claude Code, ChatGPT, JetBrains AI Assistant, Cursor, etc.)
5 -in this repository.
3 +Project Configuration values below override a pipeline's derived defaults. Behaviour — how agents
4 +run, dispatch, or report — belongs to the pipeline, not to this file.
6 5
7 -Skills define behavioral guidance.
8 -AGENTS.md defines mandatory guardrails.
9 -If a conflict exists, AGENTS.md prevails.
10 -
11 -The objective is to keep Imagify:
12 -
13 -- WordPress.org compliant
14 -- Architecturally consistent
15 -- Secure
16 -- Maintainable
17 -- Review-friendly
18 -
19 -This document applies to ALL automated or AI-generated changes.
20 -
21 6 ---
22 7
23 -# 1. Project Overview
8 +## Project Configuration
24 9
25 -Imagify is a single-edition WordPress plugin for image optimization.
10 +| Variable | Value |
11 +|---|---|
12 +| `REPO` | `wp-media/imagify-plugin` |
13 +| `SLUG` / `TEXT_DOMAIN` | `imagify` |
14 +| `BASE_BRANCH` | `develop` |
15 +| Protected branches | `develop`, `master` — never commit directly |
16 +| Branch naming | `<prefix>/<issue>-<slug>`; prefix `fix` (bugs), `enhancement` (features, incl. `feat` commits), `test` |
17 +| Test (full / unit / integration) | `composer run-tests` / `composer test-unit` / `composer test-integration` |
18 +| Test (one group) | `vendor/bin/phpunit --configuration Tests/Integration/phpunit.xml.dist --group <Name>` |
19 +| Lint / auto-fix | `composer phpcs` / `composer phpcbf` |
20 +| Static analysis | `composer run-stan` |
21 +| Build frontend | `npm run build` |
22 +| Local env up / down / seed | `bash bin/dev-up.sh` / `bash bin/dev-down.sh` / `bash bin/dev-seed.sh` |
23 +| E2E runner | `bash bin/test-e2e.sh` (`--headed`, `--ui`, or a spec path) |
24 +| Local URL | `http://localhost:8888` — admin `admin` / `password` |
25 +| Settings page | `/wp-admin/options-general.php?page=imagify` |
26 +| Key option | `imagify_settings` (API key + config) |
27 +| PR template | `.github/PULL_REQUEST_TEMPLATE.md` |
26 28
27 -- **Repo:** `wp-media/imagify-plugin`
28 -- **Plugin slug:** `imagify`
29 -- **PHP namespace root:** `Imagify\`
30 -- **PSR-4 root:** `classes/`
29 +`.env.local` at the repo root (gitignored) holds `IMAGIFY_TESTS_API_KEY=<key>`. The same value must
30 +exist as a GitHub secret for CI optimization tests.
31 31
32 -There is no FREE/PRO split. The codebase has two layers:
33 -
34 -- `classes/` — modern PSR-4 code, namespace `Imagify\`, `declare(strict_types=1)` required. **New features go here.**
35 -- `inc/classes/` — legacy classmap code, `Imagify_` prefix. **Do not add new classes here; migrate out instead.**
36 -
37 -When modifying architecture:
38 -- Prefer the modern `classes/` layer for all new work.
39 -- Follow service provider + subscriber pattern for wiring.
40 -
41 32 ---
42 33
43 -# 2. Technology Stack
34 +## Traps
44 35
45 -- PHP 7.3+ (strict types, PSR-4 autoloading via Composer)
46 -- WordPress plugin APIs (hooks, options, WP-CLI, AJAX)
47 -- League Container (DI container + service providers + event subscribers)
48 -- ActionScheduler (async background jobs)
49 -- Strauss (Composer dependency namespace prefixing → `Imagify\Dependencies\`)
50 -- JavaScript / Grunt (`_dev/` pipeline → `assets/`)
51 -- Playwright + TypeScript (E2E testing under `Tests/e2e/`)
36 +Things that fail in ways you will not notice.
52 37
38 +- **Run `composer install` before any test or lint command.** Strauss namespace-prefixing is a
39 + Composer post-install hook. Without it, PHPCS and PHPUnit cannot resolve `Imagify\Dependencies\*`
40 + and fail with misleading autoload errors.
41 +- **`WordPress.Security.NonceVerification.Missing` and `.Recommended` are deliberately suppressed**
42 + in `phpcs.xml`. Do not add `phpcs:ignore` for them and do not restructure code to satisfy them.
43 +- **`assets/` is build output.** Edit `_dev/` and rebuild, or the next build discards your work.
44 +- **There is no JavaScript unit test runner** (no Jest, no Vitest). Never invent `npm test`. Frontend
45 + verification is `npm run build` plus Playwright; otherwise report JS tests as `N/A`.
46 +- **Optimization behaviour sits behind license, API-key and quota guards.** Before reporting that a
47 + feature works or is broken, run `bash bin/dev-seed.sh` and confirm the key landed:
48 + `npx @wordpress/env run cli wp option get imagify_settings --format=json | grep -c '"api_key":"[^"]\+'`
49 + Only once the key is present (result `1`) may you treat a guard as a genuine blocker. Never report a
50 + behavioural pass or failure *through* a blocked guard — report "cannot verify" with the guard's
51 + `file:line`. Guard locations are in the `e2e` skill.
52 +- **A PR's number is not its issue number.** Read it back from the `gh pr create` output.
53 +- **PHP-rendered admin UI is a frontend change.** `wp_admin_notice()`,
54 + `add_action( 'admin_notices', ... )` and `add_settings_error()` need frontend scoping and testing
55 + despite living in PHP.
53 56
54 -# 3. Code Structure
55 -
56 -```
57 -classes/ New PHP code (PSR-4, Imagify\ namespace)
58 -inc/ Legacy PHP includes (procedural, no namespace)
59 -inc/classes/ Legacy class files migrating toward classes/
60 -assets/ Compiled frontend assets (do not edit directly)
61 -_dev/ Frontend source (JS, SCSS, Grunt config)
62 -views/ PHP view templates
63 -Tests/ PHPUnit tests
64 -Tests/e2e/ Playwright E2E tests (TypeScript)
65 -bin/ CLI scripts (dev-up, dev-down, dev-seed, test-e2e, build-knowledge-graph)
66 -docs/ Documentation (E2E_TESTING.md, etc.)
67 -.aiassistant/ Skill files for AI assistants
68 -.claude/agents/ Claude Code sub-agents (qa-engineer, e2e-qa-tester)
69 -```
70 -
71 57 ---
72 58
73 -# 4. Coding Standards & Static Analysis
59 +## Architecture
74 60
75 -Source of truth:
61 +Single-edition plugin — no FREE/PRO split. Namespace root `Imagify\`, PSR-4 root `classes/`.
76 62
77 -- Composer scripts (`composer.json`)
78 -- PHPCS ruleset (`phpcs.xml`)
79 -- PHPStan config (`phpstan.neon.dist`)
80 -- WordPress Plugin Check: https://github.com/WordPress/plugin-check/
81 -- CI pipeline rules
63 +- `classes/` — modern PSR-4, `declare(strict_types=1)` required. **New features go here.**
64 +- `inc/classes/` — legacy classmap, `Imagify_` prefix, migrating toward `classes/`. **Add nothing here.**
82 65
83 -Imagify must remain compatible with WordPress.org validation rules.
66 +In new `classes/` code:
84 67
85 -Any change affecting public APIs, output, security, metadata, or
86 -plugin bootstrap behavior must be evaluated against WordPress Plugin Check expectations.
68 +- No new singletons or `InstanceGetterTrait` usage. The trait is still used in `classes/Plugin.php`,
69 + `classes/Bulk/Bulk.php` and elsewhere — that is legacy precedent, not a pattern to copy.
70 +- No bare `add_action()` / `add_filter()`. Register hooks through a `Subscriber` implementing
71 + `SubscriberInterface`, listed in `ServiceProvider::get_subscribers()`.
72 +- Service providers live at `classes/*/ServiceProvider.php` and are registered in
73 + `config/providers.php`.
74 +- No global state, and no UI logic coupled to infrastructure logic. The legacy `inc/` layer is
75 + procedural and full of both — do not pattern-match from it.
87 76
88 -AI MUST:
77 +Nonce action naming: `imagify_<feature>_<action>`.
89 78
90 -- Read `composer.json` first and use the defined scripts (e.g. `phpcs`, `phpcbf`, `run-stan`, `test-unit`, `test-integration`) instead of inventing commands.
91 -- Auto-discover PHPCS configuration and follow it as the single source of truth.
79 +DI container is Strauss-prefixed: `Imagify\Dependencies\League\Container\Container` — a plain
80 +`use League\Container\Container;` is wrong here. Async work uses ActionScheduler, not wp-cron.
92 81
93 -## 4.1 Tooling Auto-Discovery (MANDATORY)
82 +Frontend source is `_dev/` (Grunt, `gruntfile.js`); `_dev/` also carries its own `bud.config.js`.
94 83
95 -Before making changes that affect standards or formatting, the agent MUST locate and respect the repository configuration files.
96 -
97 -### Required reads (in this order)
98 -1. `composer.json` — use scripts defined in `"scripts"` whenever possible; prefer the exact commands used by CI; do not invent lint/test commands.
99 -2. PHPCS ruleset (first match wins): `phpcs.xml`, `phpcs.xml.dist`
100 -3. Static analysis configs (if present): `phpstan.neon.dist`
101 -
102 -### Execution rules
103 -- Do NOT hardcode PHPCS standards.
104 -- Do NOT assume WordPress-Core or WordPress-Extra unless defined in the ruleset.
105 -
106 -If no PHPCS configuration exists, stop and ask.
107 -
108 84 ---
109 85
110 -# 5. Architectural Integrity
86 +## Coding standards
111 87
112 -AI must NOT:
88 +Source of truth: `composer.json` scripts, `phpcs.xml`, `phpstan.neon.dist`, CI. Never hardcode PHPCS
89 +standards or invent lint commands.
113 90
114 -- Introduce global state.
115 -- Add new singletons or `InstanceGetterTrait` usage in `classes/`.
116 -- Bypass dependency injection patterns used in the project.
117 -- Couple UI logic to infrastructure logic.
118 -- Add new classes to `inc/classes/`.
91 +Imagify must stay WordPress.org-compatible
92 +([Plugin Check](https://github.com/WordPress/plugin-check/)). Evaluate any change to public APIs,
93 +output, security, metadata, or bootstrap behaviour against it.
119 94
120 -Follow existing patterns:
95 +- PHP 7.4+, strict types in all new `classes/` files.
96 +- Text domain `imagify`: `esc_html__( 'Label', 'imagify' )`.
97 +- Authorization: use the project's registered capability (`'bulk-optimize'`, `'manage'`, …) in
98 + `current_user_can()`, never the coarse `manage_options`.
99 +- No jQuery in new or modified JavaScript — native DOM APIs only, no inline handlers, no unsafe
100 + `innerHTML`. Pass nonces via `wp_localize_script`.
101 +- Remote responses from the Imagify API are untrusted input and are this plugin's main attack
102 + surface. Validate and escape everything that comes back before storing or echoing it.
121 103
122 -- Service providers (`classes/*/ServiceProvider.php`)
123 -- Subscribers (`classes/*/Subscriber.php` implementing `SubscriberInterface`)
124 -- Container-based wiring (`config/providers.php`)
125 -- Strict types in all new `classes/` files
126 -
127 104 ---
128 105
129 -# 6. Testing & Validation
106 +## Testing
130 107
131 -For every change:
108 +Prefer **integration tests** (`Tests/Integration/`, annotated `@group FeatureName`) — they exercise
109 +real WordPress context, DI wiring and hook execution. Unit tests only for pure logic with no WP
110 +globals, container or hooks.
132 111
133 -1. Ensure no new PHPCS violations.
134 -2. Ensure static analysis still passes.
135 -3. Avoid altering unrelated test behavior.
136 -4. Do not delete tests unless clearly obsolete.
112 +Scale scope to risk: LOW = the relevant `--group`; MEDIUM = `composer test-unit` plus that group;
113 +HIGH = `composer run-tests`.
137 114
138 -If modifying templates:
139 -- Validate escaping correctness.
140 -- Ensure no functional regressions.
115 +Not scope violations: generated files (`*.min.js`, `*.min.css`), lockfiles, tests mirroring changed
116 +source, auto-formatter output.
141 117
142 118 ---
143 119
144 -# 7. E2E Testing
120 +## Commits and PRs
145 121
146 -Two Claude Code sub-agents in `.claude/agents/` support QA workflows:
122 +- Conventional Commits: `type(scope): short description`. Each commit passes PHPCS and static
123 + analysis before being made.
124 +- Pipeline-authored commits carry a `Co-Authored-By: <model> <[email protected]>` trailer so
125 + automated work stays auditable. Human-authored commits do not.
126 +- Do not squash unrelated changes. Do not amend commits already pushed.
127 +- Outside a pipeline working a specific ticket, only *suggest* commits — do not run `git commit` or
128 + `git push`.
129 +- PR title: `Closes #<N>: <short title>` — never a Conventional-Commit prefix; that is for commits.
130 +- The PR body needs a standalone `Closes #<N>` line, not buried in prose — that is what auto-closes.
131 +- Apply the `Made by AI` label to every AI-created PR and issue.
132 +- Split work vertically: each PR one complete behaviour including its tests. Never a backend PR plus
133 + a separate frontend PR for one feature, even when separate agents did the work.
134 +- Do not run large automated refactors or reorganize files without being asked. The legacy-to-modern
135 + migration is ongoing; "cleaning up while I'm here" is not in scope.
147 136
148 -| Agent | Use when |
149 -|-------|----------|
150 -| `qa-engineer` | Validating a PR against its ticket spec (strategy selection, test report) |
151 -| `e2e-qa-tester` | Driving the browser via Playwright, converting flows to spec files |
152 -
153 -Full E2E testing documentation: [`docs/E2E_TESTING.md`](docs/E2E_TESTING.md)
154 -
155 -The test directory is `Tests/e2e/` (capital T, consistent with the existing `Tests/` PHPUnit directory).
156 -
157 -The E2E suite runs in CI via `.github/workflows/e2e.yml`. The `IMAGIFY_TESTS_API_KEY` GitHub secret must be configured for optimization tests to run.
158 -
159 137 ---
160 138
161 -# 8. Local Development
139 +## On-demand references
162 140
163 -```bash
164 -# Start the local WordPress environment (Docker via wp-env)
165 -bash bin/dev-up.sh
141 +- **Browser testing** — admin URLs, page objects, environment variables, local running:
142 + [`docs/E2E_TESTING.md`](docs/E2E_TESTING.md)
143 +- **QA procedure** — tiers, spec conventions, guard locations: the `e2e` skill (`.claude/skills/e2e/`)
144 +- **Code structure** — use the installed pipeline's knowledge-graph skill if it provides one. A local
145 + builder also exists: `node bin/build-knowledge-graph.js` writes `.aiassistant/graph/` (gitignored).
146 + Do not mix the two graphs in one session; if neither is current, use grep rather than stopping.
166 147
167 -# Stop (preserves data) / full wipe
168 -bash bin/dev-down.sh
169 -bash bin/dev-down.sh --clean
170 -
171 -# Seed test data (idempotent)
172 -bash bin/dev-seed.sh
173 -
174 -# Run E2E tests locally (sources .env.local for API key automatically)
175 -bash bin/test-e2e.sh
176 -bash bin/test-e2e.sh --headed # watch the browser
177 -bash bin/test-e2e.sh --ui # Playwright interactive UI
178 -bash bin/test-e2e.sh specs/smoke # single spec
179 -```
180 -
181 -Create `.env.local` at the repo root (gitignored) with:
182 -```
183 -IMAGIFY_TESTS_API_KEY=your-key-here
184 -```
185 -
186 -- Site: `http://localhost:8888`
187 -- Admin: `http://localhost:8888/wp-admin` — `admin` / `password`
188 -
189 148 ---
190 149
191 -# 9. AI Working Protocol
150 +## Priority order
192 151
193 -AI must work in small, incremental changes.
152 +When these conflict, earlier wins:
194 153
195 -After each logical change set:
196 -- explain what changed
197 -- explain why
198 -- list potential edge cases
199 -
200 -AI must NOT:
201 -
202 -- Perform massive automated refactors without approval.
203 -- Reorganize files without explicit instruction.
204 -- Rewrite entire classes when a minimal fix is sufficient.
205 -
206 -## 9.1 Git Commit & Push Policy
207 -
208 -By default, AI may only **suggest** commit messages and must not run `git commit` or `git push`.
209 -
210 -**Exception — Issue Workflow:** When operating under the issue-workflow skill (triggered by `/task <number>`, `issue <number>`, or `#<number>`), the agent MAY:
211 -
212 -1. Run atomic `git commit` calls — one commit per logical, self-contained change set.
213 -2. Run `git push` exactly once after all commits are ready, to publish the branch.
214 -3. Create a GitHub Pull Request using the prepared PR draft.
215 -4. Monitor PR CI status checks until all pass or a failure is detected.
216 -
217 -Atomic commit rules:
218 -- Each commit must pass PHPCS and static analysis before being committed.
219 -- Commit message format: `type(scope): short description` (Conventional Commits).
220 -- No `Co-Authored-By` lines in commits.
221 -- Do not squash unrelated changes into a single commit.
222 -- Do not amend commits that have already been pushed.
223 -
224 -
225 -# 10. PR Hygiene
226 -
227 -Changes must:
228 -
229 -- Be minimal and scoped.
230 -- Have clear intent.
231 -- Avoid noise in diff.
232 -- Avoid unrelated formatting changes.
233 -
234 -
235 -# 11. Security First
236 -
237 -Always assume:
238 -
239 -- User input is untrusted.
240 -- Remote API responses are untrusted.
241 -- Stored values may be tampered with.
242 -
243 -Never:
244 -
245 -- Store sensitive values in plain text without review.
246 -- Introduce unsafe serialization.
247 -- Echo unescaped dynamic data.
248 -
249 -
250 -# 12. When in Doubt
251 -
252 -Stop.
253 -Explain the ambiguity.
254 -Ask for clarification.
255 -
256 -Architectural integrity is more important than speed.
257 -
258 -
259 -# 13. Sub-Agents
260 -
261 -Reusable specialist agents live in `.aiassistant/agents/`. Claude Code discovers them via the `.claude/agents` symlink; other tools can read them directly from `.aiassistant/agents/`.
262 -
263 -| Agent | File | Invoke when |
264 -|-------|------|-------------|
265 -| `qa-engineer` | `.aiassistant/agents/qa-engineer.md` | Validating a PR against its ticket spec — reads acceptance criteria, runs functional/browser/analysis strategies, produces a structured test report |
266 -| `e2e-qa-tester` | `.aiassistant/agents/e2e-qa-tester.md` | Driving the browser via Playwright, walking through "How to test" steps, converting validated flows into Playwright spec files under `Tests/e2e/` |
267 -
268 -The `qa-engineer` agent delegates browser flows to `e2e-qa-tester` automatically when the change involves admin UI.
269 -
270 -
271 -# 14. Skills Activation
272 -
273 -The repository defines AI Skills under `.aiassistant/skills/`.
274 -
275 -Agents MUST activate the relevant skill depending on the task:
276 -
277 -| Task | Skill |
278 -|------|-------|
279 -| Template or UI changes | WordPress Compliance |
280 -| Structural or architectural changes | Imagify Architecture |
281 -| Service modifications | Both skills |
282 -| Codebase exploration / dependency tracing | Knowledge Graph |
283 -| Working on a GitHub issue | Issue Workflow |
284 -
285 -## 13.1 Knowledge Graph
286 -
287 -A pre-built dependency graph is available at `.aiassistant/graph/dependency-graph.json`.
288 -
289 -Before exploring the codebase structure (finding a class, tracing dependencies, exploring namespaces), **read this file first**. It contains:
290 -- `nodes`: per-file namespace, declared symbols, and imports.
291 -- `symbol_index`: maps every fully-qualified PHP class/interface/trait/enum to its file.
292 -
293 -Run `node bin/build-knowledge-graph.js` to refresh after structural changes (`--full` to force rebuild).
294 -
295 -
296 -## 13.2 Session Learnings
297 -
298 -Lessons learned from past pipeline runs. Injected into every agent dispatch by the orchestrator.
299 -
300 -### E2E — Screenshots must show the target element
301 -
302 -**Rule:** Always call `locator.scrollIntoViewIfNeeded()` before `page.screenshot()`. Use the shared helper `screenshotElement()` from `Tests/e2e/fixtures/screenshot.ts` instead of calling `page.screenshot()` directly.
303 -
304 -**Why:** A screenshot taken at page-load position captures the top of the page, not the feature being tested. Screenshots showing unrelated content (e.g. General Settings header instead of the target button) provide zero QA evidence and mislead reviewers.
305 -
306 -**How to apply:** In every Playwright spec, import `screenshotElement` from `../fixtures/screenshot` and pass the target locator as the third argument. Verify each screenshot visually shows the element it documents before committing.
307 -
308 -### E2E — Never use `test.skip()` as a fallback for missing seed data
309 -
310 -**Rule:** If a required UI element is not visible due to missing seed data, use a hard `expect(...).toBe(true)` assertion, not `test.skip()`.
311 -
312 -**Why:** `test.skip()` causes the test suite to report green with zero assertions — CI passes but nothing is tested. A hard fail surfaces the missing seed as a real problem.
313 -
314 -**How to apply:** Check element visibility after navigation. If not visible, fail with a descriptive message that includes the seed command needed to fix the environment.
315 -
316 -
317 -# 15. Repository Specs
318 -
319 -The repository may define task-specific implementation specs under `.aiassistant/specs/`.
320 -
321 -Specs provide detailed guidance for recurring technical problems
322 -(e.g. PHPCS warnings, architecture migrations, WordPress compliance patterns).
323 -
324 -When a relevant spec exists, agents must follow it in addition to AGENTS.md and the applicable skills.
325 -
326 -
327 -# AI Task Priority
328 -
329 -When executing tasks, agents must prioritize:
330 -
331 154 1. Security
332 155 2. WordPress.org compliance
333 156 3. Architectural integrity
334 157 4. Backward compatibility
@@ -342,6 +156,4 @@
342 156 3. Architectural integrity
343 157 4. Backward compatibility
344 158 5. Minimal diffs
345 159 6. Performance
346 -
347 -AGENTS.md remains the final authority.