Agent skill
code-review
Provides code review rules, anti-patterns, scoring rubric, and duplication detection heuristics for the code-reviewer agent. Contains pattern catalog of all existing Zaidan UI components, hooks, and utilities. Defines standard component structure, review checklist, and output format. Use when reviewing SolidJS component code, checking for anti-patterns, or validating against Zaidan conventions.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/code-review-carere-zaidan
SKILL.md
Zaidan Code Review Rules
Single source of truth for all code review rules, anti-patterns, scoring, and duplication detection in the Zaidan project. This is a KNOWLEDGE SKILL -- it provides review rules as reusable context. The code-reviewer agent references these tables and checklists when reviewing component code.
IMPORTANT: This skill is a knowledge resource. It does NOT perform reviews itself. Instead, it provides the rules, catalogs, and heuristics that the code-reviewer agent will reference when executing reviews. If called manually, explain what this skill covers and redirect the user to the code-reviewer agent, then stop.
Coverage: This skill defines the complete review framework including:
- Component pattern catalog (all 53 UI components, 2 hooks, 3 utilities)
- Standard component structure checklist
- Duplication detection heuristics (7 categories)
- Anti-pattern detection rules (10 categories)
- Scoring rubric (PASS / WARN / FAIL)
- Review output format specification
Section 1: Purpose and Usage
This skill serves as the single source of truth for the code-reviewer agent. It is loaded automatically when the agent begins a review session and provides:
- Pattern Catalog -- A comprehensive inventory of all existing Zaidan UI components, hooks, and utilities so the reviewer can detect duplication and reuse opportunities.
- Structure Checklist -- The canonical component structure that all Zaidan components must follow, used as the review baseline.
- Duplication Heuristics -- Rules for detecting code duplication across imports, patterns, hooks, utilities, cross-component similarities, block internals, and CSS/style strings.
- Anti-Pattern Rules -- Specific patterns that must be flagged during review, including React remnants, SolidJS violations, and Zaidan convention violations.
- Scoring Rubric -- How to classify review findings into PASS, WARN, or FAIL.
- Output Format -- The exact JSON schema and summary line format the reviewer must produce.
NOTE: The component catalog below is a snapshot. At review time, the code-reviewer agent MUST glob src/registry/kobalte/ui/*.tsx and src/registry/kobalte/hooks/*.ts to validate against the actual filesystem, since components may be added or removed.
Section 2: Component Pattern Catalog
UI Components (src/registry/kobalte/ui/)
| Component | File | Key Exports | Primitive |
|---|---|---|---|
| Accordion | accordion.tsx |
Accordion, AccordionItem, AccordionTrigger, AccordionContent |
Kobalte (@kobalte/core/accordion) |
| Alert | alert.tsx |
Alert, AlertTitle, AlertDescription, AlertAction, alertVariants |
Kobalte (@kobalte/core/alert) |
| AlertDialog | alert-dialog.tsx |
AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger |
Kobalte (@kobalte/core/alert-dialog) |
| AspectRatio | aspect-ratio.tsx |
AspectRatio, AspectRatioProps |
Native |
| Avatar | avatar.tsx |
Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage |
Kobalte (@kobalte/core/image) |
| Badge | badge.tsx |
Badge, badgeVariants |
Kobalte (@kobalte/core/badge) |
| Breadcrumb | breadcrumb.tsx |
Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, BreadcrumbEllipsis |
Kobalte (polymorphic only) |
| Button | button.tsx |
Button, ButtonProps, buttonVariants |
Kobalte (@kobalte/core/button) |
| ButtonGroup | button-group.tsx |
ButtonGroup, ButtonGroupText, ButtonGroupSeparator, buttonGroupVariants |
Native |
| Calendar | calendar.tsx |
Calendar, CalendarProps, CustomCellProps |
Corvu (@corvu/calendar) |
| Card | card.tsx |
Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent |
Native |
| Carousel | carousel.tsx |
CarouselApi, Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext, useCarousel |
Native (embla-carousel) |
| Chart | chart.tsx |
ChartContainer, ChartConfig, ChartContainerProps, useChart, chartTooltipDefaults, chartLegendDefaults, chartGridDefaults, chartXAxisDefaults, chartYAxisDefaults, chartColors, createChartColorConfig |
Native (echarts) |
| Checkbox | checkbox.tsx |
Checkbox, CheckboxLabel |
Kobalte (@kobalte/core/checkbox) |
| Collapsible | collapsible.tsx |
Collapsible, CollapsibleTrigger, CollapsibleContent |
Kobalte (@kobalte/core/collapsible) |
| Combobox | combobox.tsx |
Combobox, ComboboxContent, ComboboxControl, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxSection, ComboboxSectionLabel, ComboboxSeparator, ComboboxTrigger |
Kobalte (@kobalte/core/combobox) |
| Command | command.tsx |
Command, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandShortcut, CommandSeparator |
Native (cmdk-solid) |
| ContextMenu | context-menu.tsx |
ContextMenu, ContextMenuTrigger, ContextMenuContent, ContextMenuItem, ContextMenuCheckboxItem, ContextMenuRadioItem, ContextMenuLabel, ContextMenuSeparator, ContextMenuShortcut, ContextMenuGroup, ContextMenuPortal, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuRadioGroup |
Kobalte (@kobalte/core/context-menu) |
| Dialog | dialog.tsx |
Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger |
Kobalte (@kobalte/core/dialog) |
| Drawer | drawer.tsx |
Drawer, DrawerOverlay, DrawerTrigger, DrawerClose, DrawerContent, DrawerHeader, DrawerFooter, DrawerTitle, DrawerDescription |
Corvu (@corvu/drawer) |
| DropdownMenu | dropdown-menu.tsx |
DropdownMenu, DropdownMenuPortal, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent |
Kobalte (@kobalte/core/dropdown-menu) |
| Empty | empty.tsx |
Empty, EmptyHeader, EmptyTitle, EmptyDescription, EmptyContent, EmptyMedia |
Native |
| Field | field.tsx |
Field, FieldLabel, FieldDescription, FieldError, FieldGroup, FieldLegend, FieldSeparator, FieldSet, FieldContent, FieldTitle, fieldVariants |
Native |
| HoverCard | hover-card.tsx |
HoverCard, HoverCardTrigger, HoverCardContent |
Kobalte (@kobalte/core/hover-card) |
| Input | input.tsx |
Input, InputProps |
Native |
| InputGroup | input-group.tsx |
InputGroup, InputGroupAddon, InputGroupButton, InputGroupText, InputGroupInput, InputGroupTextarea, InputGroupProps, InputGroupAddonProps, InputGroupButtonProps, InputGroupTextProps, InputGroupInputProps, InputGroupTextareaProps |
Native |
| InputOTP | input-otp.tsx |
InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator, InputOTPProps, InputOTPGroupProps, InputOTPSlotProps, InputOTPSeparatorProps |
Corvu (@corvu/otp-field) |
| Item | item.tsx |
Item, ItemMedia, ItemContent, ItemActions, ItemGroup, ItemSeparator, ItemTitle, ItemDescription, ItemHeader, ItemFooter, itemVariants, itemMediaVariants |
Native |
| Kbd | kbd.tsx |
Kbd, KbdGroup |
Native |
| Label | label.tsx |
Label |
Native |
| Menubar | menubar.tsx |
Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger |
Kobalte (@kobalte/core/menubar) |
| NativeSelect | native-select.tsx |
NativeSelect, NativeSelectOptGroup, NativeSelectOption |
Native |
| NavigationMenu | navigation-menu.tsx |
NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuTrigger, navigationMenuTriggerStyle |
Kobalte (@kobalte/core/navigation-menu) |
| Pagination | pagination.tsx |
Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious |
Native |
| Popover | popover.tsx |
Popover, PopoverAnchor, PopoverArrow, PopoverCloseButton, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger |
Kobalte (@kobalte/core/popover) |
| Progress | progress.tsx |
Progress, ProgressTrack, ProgressIndicator, ProgressLabel, ProgressValue |
Kobalte (polymorphic only) |
| RadioGroup | radio-group.tsx |
RadioGroup, RadioGroupItem |
Kobalte (polymorphic only) |
| Resizable | resizable.tsx |
ResizablePanelGroup, ResizablePanel, ResizableHandle |
Corvu (@corvu/resizable) |
| Select | select.tsx |
Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue |
Kobalte (@kobalte/core/select) |
| Separator | separator.tsx |
Separator, SeparatorProps |
Kobalte (@kobalte/core/separator) |
| Sheet | sheet.tsx |
Sheet, SheetTrigger, SheetClose, SheetContent, SheetHeader, SheetFooter, SheetTitle, SheetDescription |
Kobalte (@kobalte/core/dialog) |
| Sidebar | sidebar.tsx |
Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, useSidebar, SidebarProps |
Kobalte (polymorphic only) |
| Skeleton | skeleton.tsx |
Skeleton |
Native |
| Slider | slider.tsx |
Slider |
Kobalte (polymorphic only) |
| Sonner | sonner.tsx |
Toaster |
Native (solid-sonner) |
| Spinner | spinner.tsx |
Spinner |
Native |
| Switch | switch.tsx |
Switch |
Kobalte (@kobalte/core/switch) |
| Table | table.tsx |
Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption |
Native |
| Tabs | tabs.tsx |
Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants |
Kobalte (polymorphic only) |
| Textarea | textarea.tsx |
Textarea, TextareaProps |
Native |
| Toggle | toggle.tsx |
Toggle, ToggleProps, toggleVariants |
Kobalte (@kobalte/core/toggle-button) |
| ToggleGroup | toggle-group.tsx |
ToggleGroup, ToggleGroupItem, ToggleGroupProps |
Kobalte (polymorphic only) |
| Tooltip | tooltip.tsx |
Tooltip, TooltipTrigger, TooltipContent |
Kobalte (@kobalte/core/tooltip) |
Hooks (src/registry/kobalte/hooks/)
| Hook | File | Purpose |
|---|---|---|
useColorMode |
use-color-mode.ts |
Reads color mode (light/dark) from ColorModeContext. Must be used within ColorModeProvider. |
useIsMobile |
use-mobile.ts |
Reactive mobile breakpoint detection (768px). Uses createEffect + matchMedia + onCleanup. |
Shared Utilities (src/lib/utils.ts)
| Utility | File | Purpose |
|---|---|---|
cn() |
src/lib/utils.ts |
Merges Tailwind CSS classes via clsx + twMerge. The canonical class merging function. |
getStorage() |
src/lib/utils.ts |
Isomorphic cookie storage factory (server/client) using @solid-primitives/storage. |
flattenTocUrls() |
src/lib/utils.ts |
Flattens nested TOC entries into a flat list of URL fragments for scroll spy. |
Section 3: Standard Component Structure Checklist
Every Zaidan component MUST follow these conventions. Use this checklist during review.
3.1 Props Pattern
- Interactive components using a Kobalte/Corvu primitive: Use
PolymorphicProps<T, PrimitiveProps<T>>with generic<T extends ValidComponent = "element">and intersect withPick<ComponentProps<T>, "class">(and"children"if accessing children). - Simple components without primitive: Use
ComponentProps<"element">directly. - Custom props: Intersect with a literal object type:
& { showCloseButton?: boolean }.
Example (interactive):
type DialogOverlayProps<T extends ValidComponent = "div"> = PolymorphicProps<
T,
DialogPrimitive.DialogOverlayProps<T>
> & Pick<ComponentProps<T>, "class">;
Example (simple):
type DialogHeaderProps = ComponentProps<"div">;
3.2 Props Handling
- Extract
class(and any custom props) viasplitProps:const [local, others] = splitProps(props, ["class"]); - Merge defaults via
mergePropsBEFOREsplitPropswhen defaults exist:const mergedProps = mergeProps({ showCloseButton: true } as Props, props); - Type assertion on the
splitPropscall when using generics:splitProps(props as FooProps, [...]) - Spread
{...others}last on the JSX element.
3.3 data-slot Attribute
- EVERY semantic element MUST have a
data-slotattribute. - Naming convention:
component-namefor root,component-subpartfor children. - Examples:
data-slot="button",data-slot="dialog-trigger",data-slot="accordion-content-inner". - Interactive elements (buttons, triggers, inputs) REQUIRE
data-slot(FAIL if missing). - Non-interactive wrappers (layout divs) SHOULD have
data-slot(WARN if missing).
3.4 CVA Variants
- Define at module level (top of file, outside component function).
- Always include
defaultVariants. - CSS class names MUST use
z-prefix:z-button,z-button-variant-default,z-button-size-sm. - Apply via
cn(variants({ ... }), local.class).
Example:
const buttonVariants = cva("z-button inline-flex ...", {
variants: {
variant: { default: "z-button-variant-default", ... },
size: { default: "z-button-size-default", ... },
},
defaultVariants: { variant: "default", size: "default" },
});
3.5 Class Merging
- ALWAYS use
cn()from@/lib/utilsto merge classes. - Pattern:
class={cn("base-classes", local.class)}-- user'sclassprop comes LAST. - NEVER use raw
clsx()ortwMerge()directly in components. - NEVER hardcode class strings without wrapping in
cn()if aclassprop could be merged.
3.6 Compound Component Exports
- ALL sub-parts MUST be named and exported.
- Export via a single
export { ... }block at end of file. - Include type exports where useful:
export { Button, type ButtonProps, buttonVariants }. - Root component name matches the filename (PascalCase):
button.tsxexportsButton.
3.7 SolidJS Patterns
- Use
<Show when={...}>for conditional rendering (NEVER{condition && <El />}). - Use
<For each={...}>for list rendering (NEVER{items.map(...)}). - Use
<Dynamic component={...}>for runtime component selection. - NEVER directly destructure props -- always use
splitProps. - Signals and stores are reactive -- do not access
.value; call the signal:signal().
Section 4: Duplication Detection Heuristics
The code-reviewer agent MUST check for these 7 categories of duplication.
4.1 Import-Based Duplication
If a file imports directly from a @kobalte/core/* or @corvu/* package for a primitive that an existing Zaidan component already wraps, flag as a potential reuse opportunity.
Detection: Scan import statements for:
@kobalte/core/dialog-- already wrapped byDialogandSheet@kobalte/core/dropdown-menu-- already wrapped byDropdownMenu@kobalte/core/alert-dialog-- already wrapped byAlertDialog@kobalte/core/popover-- already wrapped byPopover@kobalte/core/tooltip-- already wrapped byTooltip@kobalte/core/accordion-- already wrapped byAccordion@kobalte/core/button-- already wrapped byButton@kobalte/core/checkbox-- already wrapped byCheckbox@kobalte/core/select-- already wrapped bySelect@kobalte/core/combobox-- already wrapped byCombobox@kobalte/core/context-menu-- already wrapped byContextMenu@kobalte/core/hover-card-- already wrapped byHoverCard@kobalte/core/menubar-- already wrapped byMenubar@kobalte/core/navigation-menu-- already wrapped byNavigationMenu@kobalte/core/switch-- already wrapped bySwitch@kobalte/core/separator-- already wrapped bySeparator@kobalte/core/toggle-button-- already wrapped byToggle@kobalte/core/collapsible-- already wrapped byCollapsible@kobalte/core/image-- already wrapped byAvatar@kobalte/core/badge-- already wrapped byBadge@kobalte/core/alert-- already wrapped byAlert@corvu/drawer-- already wrapped byDrawer@corvu/resizable-- already wrapped byResizable@corvu/otp-field-- already wrapped byInputOTP@corvu/calendar-- already wrapped byCalendar
Exception: Files within src/registry/kobalte/ui/ themselves are the wrappers and should import primitives directly.
4.2 Pattern-Based Duplication
If code manually constructs a UI pattern that matches an existing Zaidan component, flag it:
| Manual Pattern | Existing Component |
|---|---|
| Modal/overlay with backdrop + content panel | Dialog or AlertDialog |
| Slide-in panel from edge | Sheet or Drawer |
| Floating content on hover/click | Popover, HoverCard, or Tooltip |
| Dropdown with items on click | DropdownMenu |
| Button next to each other with separators | ButtonGroup |
| Breadcrumb navigation with links/separators | Breadcrumb |
| Right-click context menu | ContextMenu |
| Collapsible section with trigger | Collapsible or Accordion |
| Tab navigation with panels | Tabs |
| Toggle/switch control | Switch or Toggle |
| Select/combobox with options | Select or Combobox |
| Command palette with search | Command |
| Progress bar with track/indicator | Progress |
| Slider with thumb/track | Slider |
4.3 Hook-Based Duplication
If code creates a local reactive pattern that duplicates an existing hook, flag it:
| Local Pattern | Existing Hook |
|---|---|
createEffect + onCleanup with matchMedia for breakpoint detection |
useIsMobile (src/registry/kobalte/hooks/use-mobile.ts) |
useContext reading color mode / theme from context |
useColorMode (src/registry/kobalte/hooks/use-color-mode.ts) |
Manual createSignal + createEffect for debounce |
find in https://primitives.solidjs.community/package/scheduled#debounce |
4.4 Utility-Based Duplication
Flag any of these patterns:
| Anti-Pattern | Correct Usage |
|---|---|
clsx(...) used directly in a component |
Use cn() from @/lib/utils |
twMerge(...) used directly in a component |
Use cn() from @/lib/utils |
clsx(...) + twMerge(...) composed inline |
Use cn() from @/lib/utils |
| Manual class string concatenation | Use cn() from @/lib/utils |
4.5 Cross-Component Duplication
When reviewing a batch of components, compare:
- Export signatures: If two components export nearly identical sub-part names (e.g., both export
FooContent,FooHeader,FooFooter,FooTitle,FooDescription), check if one should compose the other. - CVA variant definitions: If two components define variants with the same variant names and similar class strings, consider extracting a shared variant.
- Tailwind class compositions: If the same long class string appears across multiple components, consider extracting to a shared
z-prefixed class or a CVA variant.
4.6 Block-Internal Duplication
For blocks (components composed of multiple files), check if:
- Components within the block duplicate logic that should be extracted to a shared block utility.
- Multiple files import the same set of sibling components -- may indicate a missing shared module.
- Context/provider patterns are duplicated instead of shared.
4.7 CSS/Style Duplication
Flag near-identical Tailwind class strings across components:
- Use Levenshtein similarity > 80% as the threshold for flagging.
- Focus on class strings longer than 30 characters (short utility classes are expected to repeat).
- Exclude
z-prefixed theme classes from this check (they are designed to be reused via CSS).
Section 5: Anti-Patterns
The following patterns MUST be flagged during review. Each is tagged with its severity.
5.1 React Remnants (FAIL)
| Pattern | Detection | Fix |
|---|---|---|
className attribute or prop |
Grep for className |
Replace with class |
forwardRef usage |
Grep for forwardRef |
Remove entirely (not needed in SolidJS) |
import * as React from "react" |
Grep for from "react" |
Remove; use SolidJS imports |
useEffect |
Grep for useEffect |
Replace with createEffect |
useState |
Grep for useState |
Replace with createSignal |
useRef |
Grep for useRef |
Replace with let ref: HTMLElement or variable |
useCallback |
Grep for useCallback |
Remove (not needed in SolidJS) |
useMemo |
Grep for useMemo |
Replace with createMemo |
React.ReactNode |
Grep for ReactNode |
Replace with JSX.Element |
React.ComponentProps |
Grep for React.ComponentProps |
Replace with ComponentProps from solid-js |
5.2 SolidJS Violations (FAIL)
| Pattern | Detection | Fix |
|---|---|---|
| Direct destructuring of props | Props accessed via { class, children, ...rest } |
Use splitProps(props, ["class", "children"]) |
Missing splitProps when accessing props |
Component reads props.class and spreads {...props} |
Extract via splitProps, spread {...others} |
{condition && <Element />} |
Grep for && in JSX context |
Use <Show when={condition}> |
{items.map(item => ...)} |
Grep for .map( in JSX context |
Use <For each={items}> |
Accessing signal with .value |
Grep for .value on signals |
Call signal as function: signal() |
5.3 Zaidan Convention Violations
| Pattern | Severity | Detection | Fix |
|---|---|---|---|
Missing data-slot on interactive element |
FAIL | Check <button>, <input>, <a>, Kobalte triggers/close buttons |
Add data-slot="component-name" |
Missing data-slot on non-interactive wrapper |
WARN | Check <div>, <span>, <section> elements |
Add data-slot="component-subpart" |
class prop not extracted via splitProps |
FAIL | class in JSX without splitProps |
Use splitProps(props, ["class"]) |
class prop not merged via cn() |
FAIL | class={local.class} without cn() |
Use class={cn("base", local.class)} |
Hardcoded class strings without cn() wrapper |
WARN | Static class="..." on elements that accept a class prop |
Wrap in cn() if the component accepts a class prop |
| Inline hook definitions duplicating registry hooks | WARN | Local createEffect+matchMedia or useContext(ColorModeContext) |
Import from @/registry/kobalte/hooks/* |
Manual event listener without onCleanup |
FAIL | addEventListener without corresponding onCleanup(() => removeEventListener(...)) |
Add onCleanup to remove the listener |
Missing defaultVariants in CVA |
WARN | cva() call without defaultVariants key |
Add defaultVariants |
| Non-polymorphic interactive component | WARN | Interactive component using ComponentProps instead of PolymorphicProps when it wraps a Kobalte primitive |
Use PolymorphicProps<T, PrimitiveProps<T>> |
| Missing compound component exports | WARN | File defines multiple component parts but only exports the root | Export all sub-parts |
Section 6: Scoring Rubric
PASS
No issues found, or only trivial style preferences that do not affect correctness, accessibility, or consistency. Examples:
- Minor whitespace differences
- Optional comment style preferences
- Alternative but valid import grouping
WARN
Minor issues that do not affect functionality but should be addressed for consistency. Examples:
- Missing optional
data-sloton a non-interactive wrapper element - Import order nit (imports are valid but not in canonical order)
- Potential but uncertain reuse opportunity (e.g., a pattern that MIGHT duplicate an existing component but could be intentionally different)
- Missing
defaultVariantsin a CVA definition - Non-polymorphic interactive component that could benefit from polymorphism
- Missing compound component exports (only root exported)
FAIL
Critical issues that MUST be fixed before the component can be merged. Examples:
- Any React remnant (
className,forwardRef,useEffect,useState,useRef,useCallback,useMemo,React.ReactNode) - Missing
splitPropswhen props are accessed and spread - Direct primitive import (
@kobalte/core/*,@corvu/*) when a Zaidan wrapper exists (outside ofsrc/registry/kobalte/ui/) - Broken type safety (incorrect generic constraints, missing type assertions)
- Missing required
data-sloton interactive elements (buttons, triggers, inputs, links) - Duplicated utility function that exists in
@/lib/utils - Manual event listener without
onCleanup - Direct props destructuring instead of
splitProps
Section 7: Review Output Format
Per-File Review Result (JSON Schema)
{
"file": "src/path/to/file.tsx",
"score": "PASS" | "WARN" | "FAIL",
"issues": [
{
"line": 42,
"severity": "FAIL" | "WARN",
"category": "react-remnant" | "solidjs-violation" | "convention-violation" | "duplication" | "type-safety",
"message": "Description of the issue",
"suggestion": "How to fix it",
"fixed": true | false
}
],
"summary": "Brief overall assessment of this file"
}
Per-Component Aggregate Result (JSON Schema)
{
"component": "ComponentName",
"primitive": "Kobalte" | "Corvu" | "Native",
"files": {
"reviewed": 3,
"total": 3
},
"score": "PASS" | "WARN" | "FAIL",
"issues": {
"total": 5,
"fail": 2,
"warn": 3,
"fixed": 1
},
"fileResults": [ /* array of per-file results */ ],
"duplicationFlags": [
{
"type": "import-based" | "pattern-based" | "hook-based" | "utility-based" | "cross-component" | "block-internal" | "css-style",
"description": "What was detected",
"existingComponent": "Name of existing component/hook/utility",
"severity": "WARN" | "FAIL"
}
]
}
REVIEW Summary Line
For sync command parsing, the final review output MUST include a summary line in this exact format:
REVIEW: {PASS|WARN|FAIL} | Component: <name> | Primitive: <primitive> | Files: <reviewed>/<total> | Issues: <count> | Fixed: <count>
Examples:
REVIEW: PASS | Component: Button | Primitive: Kobalte | Files: 1/1 | Issues: 0 | Fixed: 0
REVIEW: WARN | Component: CustomCard | Primitive: Native | Files: 2/2 | Issues: 3 | Fixed: 1
REVIEW: FAIL | Component: DataTable | Primitive: Kobalte | Files: 5/5 | Issues: 7 | Fixed: 2
The aggregate score is determined by the highest severity across all files:
- If any file has a FAIL issue, the aggregate is FAIL.
- If no FAIL but any WARN, the aggregate is WARN.
- Otherwise, PASS.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?