
Umbraco Review Checks
- 282 installs
- 26 repo stars
- Updated August 1, 2026
- umbraco/umbraco-cms-backoffice-skills
Helps with ai & agent building tasks.
About
umbraco-review-checks is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- umbraco-review-checks
- AI & Agent Building
- AI-coding skill
Umbraco Review Checks by the numbers
- 282 all-time installs (skills.sh)
- Ranked #2,337 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/umbraco/umbraco-cms-backoffice-skills --skill umbraco-review-checksAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 282 |
|---|---|
| repo stars | ★ 26 |
| Last updated | August 1, 2026 |
| Repository | umbraco/umbraco-cms-backoffice-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Umbraco Extension Review Checks
Reference skill containing all review checks for the umbraco-extension-reviewer agent.
Check Categories
| Category | File | Checks |
|---|---|---|
| Code Quality | code-quality-checks.md | CQ-1 to CQ-9 |
| Architecture | architecture-checks.md | AR-1 to AR-6 |
| UI Patterns | ui-pattern-checks.md | UI-1 to UI-7 |
Quick Reference
| ID | Check | Severity | Auto-Fix |
|---|---|---|---|
| Code Quality | |||
| CQ-1 | Extension Type Usage | Critical | Yes |
| CQ-2 | Manifest Registration | High | No |
| CQ-3 | Element Implementation | Medium | Partial |
| CQ-4 | Context API Usage | High | No |
| CQ-5 | State Management | Medium | No |
| CQ-6 | Localization | Medium | Partial |
| CQ-7 | Naming Conventions | Low | No |
| CQ-8 | Conditions | Low | No |
| CQ-9 | Property Editor Schema Alias | Critical | No |
| Architecture | |||
| AR-1 | Direct API Client Access | High | No |
| AR-2 | No Workspace Context | High | No |
| AR-3 | Source Pattern Verification | Medium | No |
| AR-4 | Inconsistent Persistence | Medium | No |
| AR-5 | Missing Repository Layer | High | No |
| AR-6 | Circular Context Dependencies | Critical | No |
| UI Patterns | |||
| UI-1 | Custom Error Handling | High | Partial |
| UI-2 | Layout Component Issues | High | No |
| UI-3 | Non-UUI Component Usage | Medium | Partial |
| UI-4 | Enum/Select Handling | Medium | Partial |
| UI-5 | Missing Loading States | Low | No |
| UI-6 | Accessibility Issues | Medium | No |
| UI-7 | Inline Styles | Low | Partial |
Usage
Read the relevant category file(s) based on extension type:
| Extension Type | Load Files |
|---|---|
| Dashboard | All three |
| Workspace | All three |
| Property Editor | code-quality, ui-pattern |
| Entity Action | code-quality only |
| Context/Repository | code-quality, architecture |
Related Skills
| Pattern Area | Skill |
|---|---|
| Repository pattern | umbraco-repository-pattern |
| Workspace context | umbraco-workspace |
| Notifications | umbraco-notifications |
| Context API | umbraco-context-api |
| Localization | umbraco-localization |
Source References
UUI Library
For UI pattern checks, refer to the UUI (Umbraco UI) library for component best practices.
Check locally first - The UUI source may be available in the workspace (e.g., Umbraco.UI/packages/). Use Glob to search for it.
Online resources:
- Storybook: https://uui.umbraco.com/
- GitHub: https://github.com/umbraco/Umbraco.UI
Umbraco CMS Source
For architecture and pattern checks, compare against Umbraco CMS source implementations.
Check locally first - The Umbraco CMS source may be available in the workspace (e.g., Umbraco-CMS/src/Umbraco.Web.UI.Client/). Use Glob to search for reference implementations.
Online resources:
- GitHub: https://github.com/umbraco/Umbraco-CMS
When reviewing, prefer local source over web fetches for accuracy and speed.
Architecture Checks
AR-1: Direct API Client Access
Severity: High | Auto-Fix: No
UI elements should not call API services directly. Use the repository pattern.
// BAD - Direct API call in UI element
export class MyDashboardElement extends UmbLitElement {
async connectedCallback() {
const response = await MyService.getAll();
this._items = response.data;
}
}
// GOOD - Using repository via context
export class MyDashboardElement extends UmbLitElement {
constructor() {
super();
this.consumeContext(MY_WORKSPACE_CONTEXT, (context) => {
this.#workspaceContext = context;
this.observe(context.items, (items) => { this._items = items; });
});
}
}Detection: *Service.get*(), tryExecute(), tryExecuteAndNotify() in .element.ts files
Reference: umbraco-repository-pattern skill
---
AR-2: No Workspace Context
Severity: High | Auto-Fix: No
Workspace elements must use workspace context for data management.
// BAD - Data loading directly in element
export class MyWorkspaceElement extends UmbLitElement {
async connectedCallback() {
const id = this.getRouteParam('id');
this._data = await this.#repository.get(id);
}
}
// GOOD - Using workspace context
export class MyWorkspaceElement extends UmbLitElement {
constructor() {
super();
this.consumeContext(MY_WORKSPACE_CONTEXT, (context) => {
this.#workspaceContext = context;
this.observe(context.data, (data) => { this._data = data; });
});
}
}Detection: Data loading in element connectedCallback, save handlers in elements
Reference: umbraco-workspace skill
---
AR-3: Source Pattern Verification
Severity: Medium | Auto-Fix: No
Extensions should follow patterns established in Umbraco source code.
| Extension Type | Reference Pattern |
|---|---|
| Dashboard | src/packages/*/dashboards/ |
| Property Editor | src/packages/*/property-editors/ |
| Workspace | src/packages/*/workspace/ |
| Collection | src/packages/*/collection/ |
| Tree | src/packages/*/tree/ |
Detection: Compare file structure, class hierarchy, manifest structure against core
---
AR-4: Inconsistent Persistence
Severity: Medium | Auto-Fix: No
Save/persistence patterns should follow Umbraco conventions.
// BAD - Save in wrong location
render() {
return html`
<uui-button @click=${() => this.#repository.save(this._data)}>Save</uui-button>
`;
}
// GOOD - Workspace context handles persistence
async #handleSubmit() {
await this.#workspaceContext.submit();
}Detection: Direct repository calls in render methods, missing error handling after save
---
AR-5: Missing Repository Layer
Severity: High | Auto-Fix: No
Extensions with data persistence should implement the repository pattern.
// BAD - Direct service usage
export class MyFeature {
async getData() {
return await MyDataService.get();
}
}
// GOOD - Repository layer
export class MyDataRepository extends UmbControllerBase {
async requestById(id: string) {
return this.#source.get(id);
}
}Detection: Direct service calls without repository wrapper
Reference: umbraco-repository-pattern skill
---
AR-6: Circular Context Dependencies
Severity: Critical | Auto-Fix: No
Context dependencies must not form cycles.
// BAD - Circular dependency
// context-a.ts
consumeContext(CONTEXT_B, (b) => { ... });
// context-b.ts
consumeContext(CONTEXT_A, (a) => { ... });Detection: Map context consume relationships, detect cycles
Code Quality Checks
CQ-1: Extension Type Usage
Severity: Critical | Auto-Fix: Yes
Extensions must use proper Umbraco types, not generic Lit/Web Component patterns.
// BAD
@customElement('my-element')
export class MyElement extends LitElement { }
// GOOD
@customElement('my-element')
export class MyElement extends UmbLitElement { }Detection: Elements extending LitElement instead of UmbLitElement
Auto-Fix: Replace LitElement with UmbLitElement, add import from @umbraco-cms/backoffice/lit-element
---
CQ-2: Manifest Registration
Severity: High | Auto-Fix: No
Extensions must be properly registered in manifests.
// BAD - No manifest registration
export class MyDashboard extends UmbLitElement { }
// GOOD - Registered in manifest
export const manifests: Array<ManifestDashboard> = [
{
type: 'dashboard',
alias: 'My.Dashboard',
name: 'My Dashboard',
element: () => import('./my-dashboard.element.js'),
}
];Detection: Elements without corresponding manifest entries
Reference: umbraco-dashboard, umbraco-workspace skills
---
CQ-3: Element Implementation
Severity: Medium | Auto-Fix: Partial
Elements must follow Umbraco patterns for lifecycle and rendering.
// BAD - Direct property manipulation
this.data = newData;
// GOOD - Reactive property
@state()
private _data?: MyData;Detection: Missing @state() or @property() decorators on reactive properties
Auto-Fix: Add @state() decorator to private reactive properties
---
CQ-4: Context API Usage
Severity: High | Auto-Fix: No
Extensions must use Context API for shared state and services.
// BAD - Direct service instantiation
const service = new MyService();
// GOOD - Context consumption
this.consumeContext(UMB_NOTIFICATION_CONTEXT, (context) => {
this._notificationContext = context;
});Detection: Direct service instantiation instead of context consumption
Reference: umbraco-context-api skill
---
CQ-5: State Management
Severity: Medium | Auto-Fix: No
State must be managed reactively using Umbraco patterns.
// BAD - Manual state updates
this.items = await this.fetchItems();
this.requestUpdate();
// GOOD - Observable state
this.observe(
this._workspaceContext.data,
(data) => { this._data = data; }
);Detection: Manual requestUpdate() calls, missing observe() usage
Reference: umbraco-state-management skill
---
CQ-6: Localization
Severity: Medium | Auto-Fix: Partial
User-facing text must use localization.
// BAD - Hardcoded strings
html`<uui-button>Save</uui-button>`
// GOOD - Localized
html`<uui-button><umb-localize key="general_save"></umb-localize></uui-button>`Detection: Hardcoded user-facing strings in templates
Auto-Fix: Wrap known strings with <umb-localize> for common terms
Reference: umbraco-localization skill
---
CQ-7: Naming Conventions
Severity: Low | Auto-Fix: No
Extensions must follow Umbraco naming conventions.
| Type | File Pattern | Class Pattern | Alias Pattern |
|---|---|---|---|
| Element | *.element.ts | *Element | - |
| Context | *.context.ts | *Context | - |
| Controller | *.controller.ts | *Controller | - |
| Repository | *.repository.ts | *Repository | - |
| Manifest | manifests.ts | - | Vendor.Name |
Detection: Files/classes not following naming patterns
---
CQ-8: Conditions
Severity: Low | Auto-Fix: No
Extensions using conditions must reference valid condition types.
// BAD - Invalid condition
conditions: [{ alias: 'Umb.Condition.DoesNotExist' }]
// GOOD - Valid condition
conditions: [{ alias: 'Umb.Condition.SectionUserPermission' }]Detection: Unknown condition aliases in manifests
Reference: umbraco-conditions skill
---
CQ-9: Property Editor Schema Alias
Severity: Critical | Auto-Fix: No
Property editor UIs must reference schema aliases that exist on the server.
// BAD - Custom alias without C# implementation
meta: {
propertyEditorSchemaAlias: 'MyPackage.CustomSchema' // 404 error!
}
// GOOD - Built-in schema
meta: {
propertyEditorSchemaAlias: 'Umbraco.Plain.String'
}Detection: propertyEditorSchemaAlias value not in built-in list:
Umbraco.Plain.StringUmbraco.IntegerUmbraco.DecimalUmbraco.Plain.JsonUmbraco.DateTimeUmbraco.TrueFalseUmbraco.TextBoxUmbraco.TextArea
If custom alias used, verify corresponding C# DataEditor exists in project.
Reference: umbraco-property-editor-ui, umbraco-property-editor-schema skills
UI Pattern Checks
UI-1: Custom Error Handling
Severity: High | Auto-Fix: Partial
Use Umbraco notification system, not browser alerts or custom error divs.
// BAD
alert('Something went wrong!');
html`<div class="error">${this._errorMessage}</div>`
// GOOD
this._notificationContext?.peek('danger', {
data: { message: 'Something went wrong!' }
});Detection: alert(), window.alert(), custom error divs/spans
Auto-Fix: Replace simple alert() calls with notification context (requires context to be consumed)
Reference: umbraco-notifications skill
---
UI-2: Layout Component Issues
Severity: High | Auto-Fix: No
Workspace elements should use <umb-workspace-editor> for proper layout.
// BAD - Save button in content area
render() {
return html`
<div>
<form>...</form>
<uui-button @click=${this.#save}>Save</uui-button>
</div>
`;
}
// GOOD - Using workspace editor
render() {
return html`
<umb-workspace-editor alias="My.Workspace">
<!-- content goes here -->
</umb-workspace-editor>
`;
}Detection: Save buttons outside workspace editor, custom header/footer implementations
Reference: umbraco-workspace skill
---
UI-3: Non-UUI Component Usage
Severity: Medium | Auto-Fix: Partial
Use UUI components instead of native HTML elements.
| Native HTML | UUI Replacement |
|---|---|
<button> | <uui-button> |
<input type="text"> | <uui-input> |
<input type="checkbox"> | <uui-checkbox> |
<select> | <uui-select> or <uui-combobox> |
<textarea> | <uui-textarea> |
<table> | <uui-table> |
<dialog> | Use Umbraco modal system |
Detection: Native form elements in templates
Auto-Fix: Suggest UUI replacements (binding syntax may differ)
---
UI-4: Enum/Select Handling
Severity: Medium | Auto-Fix: Partial
Enums must be properly handled on both backend and frontend.
Backend (C#):
// BAD - Enum serializes as integer
public MyEnum Status { get; set; }
// GOOD - Enum serializes as string
[JsonConverter(typeof(JsonStringEnumConverter))]
public MyEnum Status { get; set; }Frontend (TypeScript):
// BAD - Native select
html`<select><option value="draft">Draft</option></select>`
// GOOD - UUI select
html`<uui-select .options=${[{ name: 'Draft', value: 'draft' }]}></uui-select>`Detection: Enum properties without JsonStringEnumConverter, native <select> elements
---
UI-5: Missing Loading States
Severity: Low | Auto-Fix: No
Async operations should show loading indicators.
// BAD - No loading state
async connectedCallback() {
this._data = await this.#loadData();
}
// GOOD - Loading state
@state() private _loading = true;
async connectedCallback() {
this._loading = true;
this._data = await this.#loadData();
this._loading = false;
}
render() {
if (this._loading) return html`<uui-loader></uui-loader>`;
return html`<div>${this._data?.name}</div>`;
}Detection: Async data loading without loading state
---
UI-6: Accessibility Issues
Severity: Medium | Auto-Fix: No
Extensions must be accessible.
// BAD - Missing labels
html`<uui-input .value=${this._value}></uui-input>`
// BAD - Non-interactive element with click
html`<div @click=${this.#handleClick}>Click me</div>`
// GOOD
html`
<uui-label for="my-input">Name</uui-label>
<uui-input id="my-input" .value=${this._value}></uui-input>
`Detection: Form inputs without labels, click handlers on non-interactive elements
---
UI-7: Inline Styles
Severity: Low | Auto-Fix: Partial
Avoid inline styles; use CSS classes or UUI styling.
// BAD
html`<div style="color: red; margin: 10px;">Error</div>`
// GOOD
static styles = css`
.error { color: var(--uui-color-danger); }
`;
render() {
return html`<div class="error">Error</div>`;
}Detection: style="..." attributes in templates
Auto-Fix: Extract inline styles to static styles block