grill-me
Interview the user relentlessly about a plan or design until reaching shared understanding,…
Admin-side permission UI registration and DI-backed permission checking. Use this skill when adding permission controls to the admin UI — schema-based auto-generated forms, injectable permissions via createPermissionsAbstraction/ createPermissionsFeature, typed hooks
$ npx -y skills add webiny/webiny-js --skill admin-permissions --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/admin-permissionsContext preview
The summary Claude sees to decide when to auto-load this skill.
Admin-side permission UI registration and DI-backed permission checking. Use this skill when adding permission controls to the admin UI — schema-based auto-generated forms, injectable permissions via createPermissionsAbstraction/ createPermissionsFeature, typed hooks
name: webiny-admin-permissions description: > Admin-side permission UI registration and DI-backed permission checking. Use this skill when adding permission controls to the admin UI — schema-based auto-generated forms, injectable permissions via createPermissionsAbstraction/ createPermissionsFeature, typed hooks (createUsePermissions), the HasPermission component (createHasPermission), and the Security.Permissions component props. Covers both simple apps and complex multi-entity permission schemas.
Permissions follow three layers: **domain** (schema), **features** (DI artifacts + registration), and **presentation** (hooks, components, UI config). The framework auto-generates the permission UI from a schema and provides injectable permission checking via the DI container.
Define the schema in `src/domain/permissionsSchema.ts`:
import { createPermissionSchema } from "webiny/admin/security";
export const SM_PERMISSIONS_SCHEMA = createPermissionSchema({
prefix: "sm",
fullAccess: true,
entities: [
{
id: "product",
title: "Products",
permission: "sm.product",
scopes: ["full", "own"],
actions: [
{ name: "rwd" },
{ name: "pw" },
{ name: "import", label: "Import products" },
{ name: "export", label: "Export products" }
]
},
{
id: "category",
title: "Categories",
permission: "sm.category",
scopes: ["full"],
actions: [{ name: "rwd" }]
},
{
id: "settings",
title: "Settings",
permission: "sm.settings",
scopes: ["full"]
}
]
});| Field | Type | Required | Description | | ---------------- | -------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `prefix` | `string` | Yes | Permission prefix (e.g., `"sm"`) | | `fullAccess` | `true \| object` | Yes | `true` for standard full access. Pass an object with custom boolean flags for full-access extras (e.g., `{ canForceUnlock: true }`). | | `readOnlyAccess` | `boolean` | No | Whether to show a "Read-only access" option | | `entities` | `EntityDefinition[]` | No | Entity definitions. Omit for binary full/no access. |
| Field | Type | Required | Description | | ------------ | -------------------------------------- | -------- | ---------------------------------------------- | | `id` | `string` | Yes | Unique identifier for form field naming | | `title` | `string` | No | Display title. Falls back to `id`. | | `permission` | `string` | Yes | Permission name emitted (e.g., `"sm.product"`) | | `scopes` | `("full" \| "own")[]` | Yes | Available access scopes | | `actions` | `ActionDefinition[]` | No | Actions on this entity | | `dependsOn` | `{ entity: string; requires: string }` | No | Dependency on another entity |
Child entities can depend on a parent. If the parent lacks the required action, the child is pruned from output. `"own"` scope cascades to dependents.
{
id: "review",
permission: "sm.review",
scopes: ["full", "own"],
actions: [{ name: "rwd" }],
dependsOn: { entity: "product", requires: "r" }
}Omit `entities` for binary full/no access:
export const MA_PERMISSIONS_SCHEMA = createPermissionSchema({
prefix: "ma",
fullAccess: true
});---
import { createPermissionsAbstraction } from "webiny/admin/security";
import type { Permissions } from "webiny/admin/security";
import { SM_PERMISSIONS_SCHEMA } from "~/domain/permissionsSchema.js";
export const SmPermissions = createPermissionsAbstraction(SM_PERMISSIONS_SCHEMA);
export namespace SmPermissions {
export type Interface = Permissions<typeof SM_PERMISSIONS_SCHEMA>;
}import { createPermissionsFeature } from "webiny/admin/security";
import { SM_PERMISSIONS_SCHEMA } from "~/domain/permissionsSchema.js";
import { SmPermissions } from "./abstractions.js";
export const SmPermissionsFeature = createPermissionsFeature(SM_PERMISSIONS_SCHEMA, SmPermissions);Register the feature and the permission UI in your extension component:
import { AdminConfig, RegisterFeature } from "webiny/admin/security";
import { ReactComponent as Icon } from "@webiny/icons/shield.svg";
import { SM_PERMISSIONS_SCHEMA } from "~/domain/permissionsSchema.js";
import { SmPermissionsFeature } from "~/features/permissions/feature.js";
const { Security } = AdminConfig;
export const Extension = () => {
return (
<>
<RegisterFeature feature={SmPermissionsFeaturOpen-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…