About wi-site
wi-site is a development skill for projects built from `wonder-image/new-site` and its derivatives. It guides page, component, and backend work by routing tasks to references, defining code placement, and protecting upstream framework and design-system files.
Key features
- 01Route tasks to relevant references
- 02Set placement rules for site code
- 03Protect upstream dependencies from edits
- 04Follow product and design documents
- 05Classify common site development tasks
Use cases
- 01Add a site page or component
- 02Implement models, resources, or tables
- 03Update site copy and localization
- 04Decide whether a change belongs in the site or framework
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ wonder-image/ skills --skill wi-siteAfter installing, type/wi-sitein Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
references/examples.mdexternal-skills.mdheader-navigation.mdimplementation-playbook.mdproduct-md.mdproject-structure.mdsecurity-and-deploy.mdstyle-and-lib.mdworkflows.mdDetails
From the project READMEWonder Site (new-site based)
Overview
Use this skill inside wonder-image/new-site or any project scaffolded from it. The repo is the runtime owner. The framework lives in vendor/wonder-image/app (Composer, see wi-app for changes there) and the JS/CSS design system lives under assets/lib/wonder-image/dist/ (copied from npm wonder-image/lib). Treat both as upstream — never edit them in place.
Glossary
Shared vocabulary across wi-app and wi-site (identical wording in both skills):
- framework —
wonder-image/app(Composer package, github.com/wonder-image/app). Lives at the repo root when wi-app is active; lives atvendor/wonder-image/app/inside a site. - lib —
wonder-image/lib(npm package, github.com/wonder-image/lib). The JS / CSS design system. Source atnode_modules/wonder-image/src/; compiled copy atassets/lib/wonder-image/dist/. - scaffold —
wonder-image/new-site(github.com/wonder-image/new-site). The site template. The scaffold itself is also a valid site. - site — any project whose
composer.jsondepends onwonder-image/app(i.e. installs the framework undervendor/wonder-image/app). Typically the scaffold or a project derived from it. Canonical term — prefer "site" over older mixed uses like "consumer project" / "consumer app". - module — external Composer package
wonder-image/<slug>discovered via Composer (or filesystem fallback). Ships its own models / resources / routes viamodule.json+ aModuleInterfaceentrypoint. custom/— site-only directory for project pages, components, layouts, routes, config, and helpers. Never present inside the framework.app/Models/app/Resources— site PSR-4 roots (App\Models\.../App\Resources\...). Distinct from the framework'sclass/App/Models/class/App/Resources(Wonder\App\Models\.../Wonder\App\Resources\...).
When to switch to wi-app
Stop and switch to wi-app when any of these signals are true — the work belongs in the framework, not in this site (the frontmatter SKIP block already encodes the router-side check; this is the working-time version):
- the repo's
composer.jsondeclares"name": "wonder-image/app"(you are inside the framework repo, not a site). - the requested change lives under
vendor/wonder-image/app/. Never patch vendor from a site. Either reshape the change to live incustom//app/Models/app/Resources(stays wi-site), or open the change against the framework repo (then wi-app applies). - you need to add or modify a
Model/Resourcebase class, aFormFieldhelper, an element underclass/Elements/, a theme renderer underclass/Themes/{Wonder,Bootstrap}/, a route inapp/config/routes/*, the module discovery flow, the bootstrap order, the permission builder registry atapp/config/app/permission.php, or a shared user-management resource. - the task is "add a new form input type", "change how the framework renders inputs in Wonder vs Bootstrap", "extend the permission builder", "register a new console command source", or any work that defines (rather than uses) framework behavior.
- working in
wonder-image/lib(the JS / CSS design-system source) — that is a different repo entirely; neither wi-site nor wi-app applies.
Non-Negotiable Rules
- Never edit
vendor/,node_modules/, orassets/lib/wonder-image/dist/. The last one is regenerated bynpm installfromwonder-image/lib. - Never patch
vendor/wonder-image/appfrom a site task. If the change belongs there, switch to wi-app. - Never run these Forge commands from this skill:
php forge configphp forge credentialsphp forge provisionphp forge db:initphp forge build
- Every user-facing string goes through
__t(...)with entries inlang/{locale}/*.json(any number of JSON files:pages.json,components.json,emails.json,legal.json, plus any new ones the site needs). URLs go through__r(string $name, array $parameters = [])(preferred — builds the URL from a named route, picks up the active locale, survives route renames). Use__u(string $path)only when there is no named route and you must build a URL from a free path (e.g.__u('contact')). No hardcoded copy or language prefixes in PHP. - Before writing new CSS classes, JS behavior, or UI structure, inspect
wonder-image/liband reuse the existing design system. Full UI rulebook inreferences/style-and-lib.md— read it for any UI / styling / design-system task. The default mode is USE the lib, do not MODIFY it. <wi-card>is retired. Do not write<wi-card>in the site's backend pages: useCardfromwonder-image/app. Existing pages that use it keep working until the lib removes it; replace it when you touch them.- Never hardcode colors (HEX / RGB / HSL), introduce
.wi-*(or any other) prefix-based naming, or build a parallel CSS system. Detect{ASSETS_VERSION}dynamically — do not assume0.0/or any other version. - Prefer external Composer modules
wonder-image/<slug>over project-embedded module code. - Place PSR-4 classes under
app/Modelsandapp/Resourceswith namespaceApp\Models/App\Resources. Place project pages, components, layout overrides, routes, config, and helpers undercustom/. - The canonical model / table flow is
Model::tableSchema()+Model::dataSchema(). Do not invent parallel table definition systems alongside it.
Start Sequence
-
Read
docs/ai/PRODUCT.mdfirst. It defines register (brand vs product),site_type, target users, brand personality, voice/tone, design principles. Everything you do next must be coherent with what it says — placement choices, copy, suggestions of modules, UI direction. Run the Site readiness check inreferences/external-skills.mdonce per session on every site, migrated or not, before deciding whether the file is missing or empty: it moves a rootPRODUCT.mdintodocs/ai/(git mvwhen tracked,mvotherwise, also over an untouched scaffold template with empty sections), adds the.gitignoreanddeploy.ymllines, createsdocs/ai/reports/. Only after the check, judgedocs/ai/PRODUCT.md.If
docs/ai/PRODUCT.mdis missing or its required sections are empty, do NOT proceed with the user's task yet. Run the interview procedure inreferences/product-md.md§ Compilation procedure: ask 2–4 focused questions at a time withAskUserQuestion, save answers intodocs/ai/PRODUCT.mdas they come, and continue interviewing until you have at least 80% project clarity — operationalized as: all 6 required sections filled (Register,Site type,Target users,Brand personality,Voice / tone,Design principles) plus at least one of (Anti-references,Asset paths). Only then proceed with the original task. Reason: the alternative is generic output that the user will have to fix later — the 10–15 minutes spent interviewing pay back on every subsequent decision in the session and in future sessions.The interview is sequential and adaptive: if the user already mentioned something in passing (e.g. "abbiamo un brand di moda"), pre-fill the relevant section and ask for confirmation rather than re-asking from scratch. Full schema in
references/product-md.md; copy-paste template inreferences/examples.md§6.Then read
docs/ai/DESIGN.mdif the task touches UI (pages, components, styling, tokens). The framework generates it from the CSS tokens every time it writesroot.css: read it, never edit it. If it is missing, followreferences/external-skills.md§ Fallback without DESIGN.md. -
Classify the task:
- page or component work
- UI / styling / design-system work
- model, resource, repeater, or table work
- backend-editable content
- permissions, roles, or user areas
- translation, locale URLs, or content text
- module integration
- setup, runtime, or local environment
-
Read only the reference that matches the task (see Task Routing below). For copy-paste scaffolds (Model + Resource skeleton, frontend page,
pages.jsonentry,permissions.phpextension,modules.php), jump straight toreferences/examples.md. -
Decide whether the work belongs in
custom/,app/, an externalwonder-image/<slug>module, or actually in the framework (switch to wi-app). -
Refuse the wrong placement: no direct
vendor/patching, no hand-editednode_modules/orassets/lib/wonder-image/dist/, no parallel user-management pages, no custom CSS insideassets/{ASSETS_VERSION}/css/set-up/.
Task Routing
Brand, copywriting, voice, site type
Read references/product-md.md. docs/ai/PRODUCT.md is the source of truth for register, target users, brand personality, voice/tone, design principles, and site_type (landing / corporate / blog / ecom / rsvp). Copy lives in lang/{locale}/*.json and must respect the voice declared in docs/ai/PRODUCT.md. docs/ai/DESIGN.md is generated by the framework from color.css + root.css: read it, do not edit it; the rules in style-and-lib.md stay authoritative for visual tokens.
Page or component
Read references/implementation-playbook.md and references/style-and-lib.md. Copy-paste skeleton for a frontend page in references/examples.md.
- Prefer
Badge::inline(),Wonder\Elements\Frontend\EmptyState,Wonder\Elements\Frontend\Paginationand the Wonder renderer ofText/RichText(app ≥ v2.4.0-beta.5) to hand-written markup; APIs inwi-app/references/component-catalogue.md§ Frontend list and text components. - For a reusable header driven by one recursive navigation tree, read
references/header-navigation.md. It defines theclassic/megacontract,listdefault, optionalcardpresentation, action links, appearance options, desktop hover behavior, and the mobile cascade. - Pages go under
custom/view/pages/{frontend,backend}/.... - Component overrides mirror the framework path under
custom/view/components/{frontend,backend}/.... - Reuse
\Wonder\View\View::component(...)over manualinclude. - Inspect existing page components before adding new markup.
- Public page? Route through
references/external-skills.md: new public page or section →design-taste-frontend; existing public page to redo →redesign-existing-projects; mockup or screenshot supplied →image-to-code. Backend pages: no external skill.
UI / styling / design system
Read references/style-and-lib.md first. Applies to every task touching buttons, inputs, forms, modals, cards, alerts, badges, typography, images, interactive elements, color tokens, root variables, or custom CSS / JS.
- Default mode: USE the lib, do not MODIFY it. Modifying
wonder-image/librequires an explicit user request. - Reuse existing lib classes and tokens before writing anything new. No
.wi-*(or other) prefix-based naming. No parallel CSS system. No hardcoded colors. - Token files:
assets/{ASSETS_VERSION}/css/set-up/color.cssandroot.css. Custom CSS / JS goes underassets/{ASSETS_VERSION}/css/andassets/{ASSETS_VERSION}/js/— never insideset-up/. - Detect
{ASSETS_VERSION}from the actualassets/directory before reading or writing token files. - Before closing any task that touched public HTML / CSS:
playwright-cliscreenshots at 375 / 768 / 1280 and console, thenweb-design-guidelineson the touched files, as described inreferences/external-skills.md. Backend-only tasks skip both. - End every UI task with the Required Final Report and Pre-Submit Checklist in
references/style-and-lib.md.
External skills
Read references/external-skills.md. It is the only place with the routing table (taste, redesign, image-to-code, web-design-guidelines, playwright-cli), detection and on-demand installation with --global, the precedence of docs/ai/PRODUCT.md + docs/ai/DESIGN.md + style-and-lib.md over external proposals, the report naming in docs/ai/reports/, and the site readiness check. Do not repeat those rules here.
Model, resource, repeater, or table — site postilla
Read references/implementation-playbook.md for the placement workflow, then start from the skeleton in references/examples.md. For the full API contract (method signatures, lifecycle, registry behavior, repeater details), read wi-app/references/model-and-resource.md — install wi-app alongside wi-site to have it available locally.
Steps for a new site Model + Resource:
- Create the Model under
app/Models/<Name>.php, namespaceApp\Models, extending the framework Model base. - Define SQL in
Model::tableSchema(). Define data behavior inModel::dataSchema(). - Create the Resource under
app/Resources/<Name>Resource.php, namespaceApp\Resources, bound to the Model. - Define
formSchema()for backend inputs,permissionSchema()for route gating,navigationSchema()for nav placement. - Use
FormField::repeater(...)+RepeaterColumnfor repeatable rows;CustomPageSchemaonly for non-CRUD pages. - Run
composer dump-autoload, thenphp forge update --localto apply runtime generation.
The canonical flow is Model::tableSchema() + Model::dataSchema(). Do not invent parallel table-definition files alongside it.
Visitor data, hand-written forms, tracking, .htaccess, deploy, backups
Read references/security-and-deploy.md. It covers escaping visitor data in custom backend pages and emails, CSRF in hand-written forms and site routes, SafeRedirect, downloadAsText() exports, GTM-only tracking behind consent, the managed WONDER blocks of .htaccess, database backups and the deploy exclusion proposal. The framework side of the same contracts is wi-app/references/security.md.
Backend-editable content
Read references/implementation-playbook.md. Prefer a real Model + Resource flow. Connect media to existing media resources. Never store editable content in static arrays or loose files.
Permissions, roles, or user areas — site postilla
The full builder API, framework user resources, and runtime $PERMITS export live in wi-app at wi-app/references/permissions-and-users.md. In a site, the only place to touch is:
custom/config/permissions.php— extends or overrides the registry after the base file (app/config/app/permission.phpin the framework) and the module merge have run. Copy-paste skeleton inreferences/examples.md.
Steps to add or override a site permission:
- Open
custom/config/permissions.php. - Extend the builder registry already initialized in
app/config/app/permission.phpand then merged with module permissions. - Reference the resulting permission key from any project
Resource::permissionSchema()and from navigation authority gates. - Do not build parallel user-management pages — user CRUD is centralized in the shared framework resources. If a site truly needs a different user flow, that is a framework-level change → switch to wi-app.
If wi-app is not yet installed locally, run npx skills add wonder-image/skills --skill wi-app to make the full reference available.
Translation, locale URLs, content text
Read references/workflows.md. Sample lang/it/pages.json entry in references/examples.md.
- Strings live in
lang/{locale}/*.json— any number of JSON files. The site shipspages.json,components.json,emails.json,legal.jsonby default; new ones (e.g.lang/{locale}/terms.json) are picked up automatically. - Access translated strings via
__t("path.to.key"). - Build URLs:
- Prefer
__r(string $name, array $parameters = [])— URL from a named route. Works for every route registered inapp/config/routes/orcustom/routes/, including frontend pages, resource CRUD routes, and custom backend routes. Survives slug / path changes because it resolves by name. - Fallback to
__u(string $path)only when no named route exists and you must build a locale-aware URL from a free path string (e.g.<a href="<?= __u('contact') ?>">).
- Prefer
- Legal pages (privacy, cookie, terms) render
LegalDocument::make('privacy')fromwonder-image/app:legal_documentsin the database is the only source,lang/{locale}/legal.jsonis just the seed. Never print legal text from__t('legal...')in a page. - Site texts and legal documents are translated by the client in Set-up → Traduzioni (XLSX/CSV export, previewed import). For translatable content fields, make the site Model implement
TranslatablewithHasTranslationsand read rows withModel::translated($rows); the scheduler translates them automatically. Details invendor/wonder-image/app/docs/app/concetti/traduzioni.md.
Module integration
Read references/project-structure.md and references/workflows.md.
- Prefer external Composer packages
wonder-image/<slug>over embedded code. - Enable modules in
custom/config/modules.php— copy-paste skeleton inreferences/examples.md.
Setup, runtime, or local environment
Read references/workflows.md. From the project root:
composer install(also runsphp forge configvia Composer scripts)npm install(copieswonder-image/libintoassets/lib/wonder-image/dist/)php forge credentials(only when the user explicitly requests Bitwardendev-sharedrecovery; writes secrets into.env)php forge update --local(applies DB and runtime generation)php forge start(runs the local server, may fill missing.env)
Validation
- Run
php -lon every touched PHP file. - Run
composer dump-autoloadwhen PSR-4 classes are added, moved, or renamed. - For integration-sensitive changes:
php forge update --localthenphp forge start. - Re-run
npm installonly when changes depend onassets/lib/wonder-image/dist/fromwonder-image/lib.
Output Expectations
- Name the concrete site paths changed (e.g.
custom/view/pages/frontend/about.php,app/Models/Project.php,lang/it/pages.json). - State explicitly when a requested change actually belongs in the framework (→ wi-app) or in
wonder-image/lib. - List translation file updates, permission/authority changes, and Forge/npm rebuild steps when relevant.
- Refuse, with a one-line reason, any edit to
vendor/,node_modules/,assets/lib/wonder-image/dist/, or any Forge-generated file.