Create a UI component named $ARGUMENTS that is indistinguishable from code already in this repo. If $ARGUMENTS is empty, ask for the component name and stop; do not invent one.
Decide placement first
Find where components live before writing anything. Glob for existing component files (.tsx/.jsx/.vue/.svelte under src/, app/, components/, ui/, lib/). Pick the directory whose components are closest in kind to $ARGUMENTS (a form control goes with form controls, a layout piece with layout pieces); if kinds are mixed in one flat folder, use that folder. State the chosen path and why in one line before creating the file.
If a component of the same name already exists at that path, stop and ask whether to overwrite, rename, or extend it — never silently clobber it.
Detect conventions
Read 3-5 existing components in or nearest to the chosen directory. Extract, don't assume:
- Framework and version: React, Vue, Svelte, Solid, Angular. Check
package.jsonand file extensions. - Language: TypeScript vs JS. Match
tsconfigstrictness; if props are typed elsewhere, type these too. - Styling: Tailwind, CSS Modules, styled-components, vanilla-extract, plain CSS, or a design-system package. Reuse existing tokens/utility classes and
cn/clsxhelpers — never hardcode colors or spacing that a token already covers. - Component shape: function vs class, default vs named export,
forwardRefusage,'use client'directives, arrow vsfunctiondeclaration, file/folder layout (Component.tsx+index.ts+ co-located test, or a flat file). - State/data: local hooks vs a store (Redux/Zustand/Pinia/signals), how server data is fetched (React Query, RSC, loaders).
- Test setup: runner (Vitest/Jest), library (Testing Library, Playwright CT), file naming (
.test.tsx/.spec.tsx), and where mocks live.
If the repo has no components yet (greenfield), set the defaults instead of mirroring: read package.json to pick the framework already installed; use TypeScript with strict types if a tsconfig exists, else the repo's JS flavor; style with the styling dep already in package.json (Tailwind/CSS Modules/plain CSS in that order of preference if several qualify); named function-component export, props as a typed interface, PascalCase.tsx file with a co-located test. List each default you chose in the report.
Build the component
- Place the file at the path decided above, using the repo's exact naming case for
$ARGUMENTS. - Define a typed props interface/type. Prefer required props; give optional props sane defaults. Reuse shared types over redefining them. No
any. - Forward
refand spread remaining...propsto the root element only if existing components do. - Compose from the project's primitives (existing
Button,Spinner,Card, icons) instead of raw elements when they exist. - Add loading, empty, and error states only when the component fetches or receives async/collection data. For a purely presentational component, skip them rather than inventing states it never has.
- Accessibility floor, not just parity: interactive elements are real controls or have correct
role+aria-*, every input has an associated label, focus is visible and keyboard-operable, and images/icons carry alt oraria-hidden. Match the repo's patterns where they meet this bar; exceed them where they don't, rather than copying a weaker baseline.
Test
Write one test file matching the project's runner and conventions. Cover: it renders with minimal required props, one interaction or state variant, and (if present) the loading and error branches. Use queries the repo already uses (roles/labels over test-ids unless test-ids are the norm). No snapshot-only tests.
Verify and report
Run the project's typecheck/lint and the new test; fix failures before finishing. Do not weaken tsconfig or lint rules to pass. Then report exactly these fields:
- Files: paths created or modified.
- Placement: chosen directory and the one-line reason.
- Props: the full prop names with types and which are required.
- Mirrored: the existing components you patterned each decision on.
- Chosen defaults: any convention set because no precedent existed (empty if all were mirrored).
- Checks: typecheck, lint, and test commands run and their pass/fail result.
Rules
- Never introduce a new styling system, state library, or test framework — use what the repo already has (in greenfield, use only deps already in
package.json). - Never add dependencies without flagging it explicitly and confirming it isn't already available.
- Never leave
TODOs, placeholder copy, or commented-out code in the delivered component.