grill-me
Interview the user relentlessly about a plan or design until reaching shared understanding,…
Full-stack extension skeleton and registration pattern. Use this skill when creating an extension that spans both API and Admin — the top-level component with Api.Extension and Admin.Extension entry points, shared domain layer, BuildParam declarations, and package structure.
$ npx -y skills add webiny/webiny-js --skill full-stack-architect --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/full-stack-architectContext preview
The summary Claude sees to decide when to auto-load this skill.
Full-stack extension skeleton and registration pattern. Use this skill when creating an extension that spans both API and Admin — the top-level component with Api.Extension and Admin.Extension entry points, shared domain layer, BuildParam declarations, and package structure.
name: webiny-full-stack-architect description: > Full-stack extension skeleton and registration pattern. Use this skill when creating an extension that spans both API and Admin — the top-level component with Api.Extension and Admin.Extension entry points, shared domain layer, BuildParam declarations, and package structure. References webiny-api-architect and webiny-admin-architect for layer-specific details.
A full-stack extension bundles **API** and **Admin** into a single package with a shared domain layer. The top-level component registers both sides via `<Api.Extension>` and `<Admin.Extension>`, which point to separate entry-point files. Each side follows its own layered architecture pattern — see **webiny-api-architect** and **webiny-admin-architect** skills for details.
This skill applies to both **extension developers** (working in `extensions/`) and **core developers** (working in `packages/`). The architecture patterns are the same — only the import convention and registration mechanism differ.
| | Extensions (`extensions/`) | Core (`packages/`) | | ----------------------- | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | | **Imports** | `webiny/api`, `webiny/admin`, `webiny/admin/ui` | `@webiny/feature/api`, `@webiny/app-admin`, `@webiny/admin-ui` | | **Catalog paths** | Use the `Import:` path | Use the `Source:` path | | **Registration** | `<Api.Extension src={...}>` / `<Admin.Extension src={...}>` in `webiny.config.tsx` | `createFeature` registered directly by the package's module initializer | | **Entry point export** | Files targeted by Extension `src` MUST use `export default` | No restriction — features are registered programmatically | | **Top-level component** | Required — composes `<Api.Extension>` + `<Admin.Extension>` | Not applicable — each package registers its own features |
Detect which context you're in by checking the file path: `extensions/` → extension mode, `packages/` → core mode.
> **Admin extensions CANNOT be directly mounted in `webiny.config.tsx` or in any child component tree without going through `<Admin.Extension />`.**
The same rule applies to API extensions — they must go through `<Api.Extension />`.
These entry-point components are the **only** way to register code that runs inside the Admin app or the API runtime. They use the `src` prop to point to a file that will be loaded in the correct execution environment (browser for Admin, Lambda for API). Bypassing these entry points will fail at runtime because the Admin and API contexts (DI containers, routers, GraphQL registries, etc.) are not available outside their respective runtimes.
**YOU MUST include the full file path with the `.ts` or `.tsx` extension in every `src` prop.** For example, use `src={"/extensions/lead/src/index.ts"}`, NOT `src={"/extensions/lead"}`. Omitting the file extension will cause a build failure.
**YOU MUST use `export default` for the `createImplementation()` call** when the file is targeted directly by an Extension `src` prop. Using a named export (`export const Foo = SomeFactory.createImplementation(...)`) will cause a build failure. Named exports are only valid inside files registered via `createFeature`.
// CORRECT — always use entry-point components
<Api.Extension src={import.meta.dirname + "/api/Extension.js"} />
<Admin.Extension src={import.meta.dirname + "/admin/Extension.js"} />
// WRONG — never mount admin/api code directly
<MyAdminComponent /> // Will not have access to Admin DI container
<MyApiFeature /> // Will not have access to API DI containermy-extension/ ├── src/ │ ├── index.ts # Single public export │ ├── MyExtension.tsx # Top-level component (registers Api + Admin) │ ├── shared/ # Shared between API and Admin │ │ ├── constants.ts # Model IDs, permission names, etc. │ │ └── types.ts # Shared types │ ├── api/ # API-side code → see webiny-api-architect skill │ │ ├── Extension.ts │ │ ├── domain/ │ │ ├── features/ │ │ └── graphql/ │ └── admin/ # Admin-side code → see webiny-admin-architect skill │ ├── Extension.tsx │ ├── features/ │ └── presentation/
The top-level component is the single entry point that consumers use. It registers both the API and Admin extensions:
// src/MyExtension.tsx
import React from "react";
import { Api, Admin } from "webiny/extensions";
export const MyExtension = () => {
return (
<>
{/* API extensions — runs in Lambda */}
<Api.Extension src={import.meta.dirname + "/api/Extension.js"} />
{/* Admin extensions — runs in browser */}
<Admin.Extension src={import.meta.dirname + "/admin/Extension.js"} />
</>
);
};Conditional rendering can wrap the entry points (e.g., feature flags, config parameters):
<Infra.Env.Is name={"prod"}>
<Api.Extension src={import.meta.dirname + "/api/Extension.js"} />
<Admin.Extension src={import.meta.dirname + "/admin/Extension.js"} />
</Infra.Env.Is>The `shared/` directory contains types and value objects used by both API and Admin:
// src/shared/constants.ts
export const MY_MODEL_ID = "myModel";
// src/shared/MyEntity.ts
export interface MyEntityValues {
name: sOpen-source content platform. Self-hosted on AWS serverless. Built as a TypeScript framework you extend with code, not a closed product you configure through a UI. Runs on Lambda, DynamoDB, S3, and CloudFront inside your own AWS account. Scales automatically.
Repo: webiny/webiny-js
Interview the user relentlessly about a plan or design until reaching shared understanding,…
Turn a PRD into a multi-phase implementation plan using tracer-bullet vertical slices, saved…
Webiny-only. Run all checks required before packages are ready for publish: deps, build,…
Use when running tests. Shows how to run tests for a single package, including OpenSearch…
Generate, refresh, and maintain Webiny MCP server skills from source documentation and…
Create a PRD through user interview, codebase exploration, and module design, then submit as…