DevOps & Infra
migrate-to-skeleton - Claude MCP Skill
Migrate Legacy Component to Skeleton Architecture
SEO Guide: Enhance your AI agent with the migrate-to-skeleton tool. This Model Context Protocol (MCP) server allows Claude Desktop and other LLMs to migrate legacy component to skeleton architecture... Download and configure this skill to unlock new capabilities for your AI workflow.
Documentation
SKILL.md# Migrate Legacy Component to Skeleton Architecture
## Argument: $ARGUMENTS
The argument specifies which component to migrate (e.g. `card`, `tooltip`, `alert`).
---
## Role
You are a **Senior Software Architect and Developer** with strong experience in component-based frontend architecture.
Prioritize:
- **Clean Architecture**: clear layer separation, Single Responsibility, Dependency Inversion.
- **Maintainability**: code that remains understandable long-term.
- **Readability**: consistent naming, low cognitive load.
- **Traceability**: no special-case logic without explicit reason.
- **Reduction**: remove dead code and unnecessary abstractions.
Work methodically: analyze, plan, implement, validate.
---
## Task
Refactor component **`$ARGUMENTS`** so it conforms to the Skeleton Blueprint architecture and current internals implementation.
---
## Working Directories
- **Skeleton** (`packages/components/src/components/_skeleton/`) = **read-only** reference.
- **Component directory** (`packages/components/src/components/$ARGUMENTS/`) = **workspace**.
---
## Source of Truth
Use these in this order:
1. **Current implementation code** in:
- `packages/components/src/components/_skeleton/web-components/skeleton/component.tsx`
- `packages/components/src/internal/functional-components/skeleton/api.tsx`
- `packages/components/src/internal/functional-components/skeleton/controller.ts`
- `packages/components/src/internal/functional-components/skeleton/component.tsx`
- `packages/components/src/internal/functional-components/base-controller.ts`
- `packages/components/src/internal/functional-components/base-web-component.ts`
- `packages/components/src/internal/functional-components/generic-types.ts`
2. [`ARC42.md`](packages/components/src/components/_skeleton/ARC42.md) as architecture narrative.
If ARC42 text and implementation differ, follow implementation.
---
## Procedure
### Phase 1: Analysis
1. Read **all** files in `packages/components/src/components/$ARGUMENTS/`.
2. Read the skeleton and base internals listed above.
3. Create a **gap analysis** table:
| Aspect | Legacy (Current) | Skeleton (Target) | Action Required |
| ----------- | ---------------- | --------------------------------------------------------------- | --------------- |
| Inheritance | ... | `BaseWebComponent<Api>` or `BaseWebComponent.stateLess` pattern | ... |
| Controller | ... | `BaseController<Api>` | ... |
| Props | ... | `internal/props` definitions + prop triangle | ... |
| Rendering | ... | Stateless FC + bare `<Host>` | ... |
### Phase 2: Props First (Do This Before Controller Refactor)
1. Collect all existing `@Prop()` declarations.
2. Reuse existing prop definitions from `packages/components/src/internal/props/` where possible.
3. For new props, add one file per prop in `packages/components/src/internal/props/`.
4. Define prop behavior using existing prop helper patterns (`createPropDefinition`, `normalize`, `validate`).
5. Export new props in `packages/components/src/internal/props/index.ts`.
### Phase 3: Refactor by Layers
1. **API** (`packages/components/src/internal/functional-components/$ARGUMENTS/api.tsx`)
- Define `propsConfig` with `required` and/or `optional` arrays (`PropsConfigShape`).
- Derive API type using `ApiFromConfig`.
- Only declare needed API sections (`Callbacks`, `Emitters`, `Listeners`, `Methods`, `Refs`, `States`).
2. **Controller** (`packages/components/src/internal/functional-components/$ARGUMENTS/controller.ts`)
- Extend `BaseController<Api>`.
- Constructor signature: `constructor(stateAccess: StateAccess<Api>)`.
- Call `super(stateAccess, propsConfig)`.
- Implement `componentWillLoad(props: ResolvedInputProps<Api>)`.
- Use `propDefinition.apply(value, callback)` in watchers.
- Use arrow properties for handlers/ref setters; prototype methods for lifecycle/watchers/methods.
3. **Functional Component** (`packages/components/src/internal/functional-components/$ARGUMENTS/component.tsx`)
- Stateless renderer with `FunctionalComponentProps<Api>`.
- Build BEM classes via `bem.forBlock('kol-$ARGUMENTS')`.
- No side effects and no state mutation.
4. **Web Component** (`packages/components/src/components/$ARGUMENTS/component.tsx`)
- `@Component({ tag: 'kol-$ARGUMENTS', shadow: true })`.
- Extend `BaseWebComponent<Api>` and implement `WebComponentInterface<Api>`.
- Create controller with `new Controller(this.stateAccess)`.
- For every `@Prop()`: add matching `@Watch()` and initialize in `componentWillLoad()` (prop triangle).
- Render with bare `<Host>` and pass normalized props via `this.ctrl.getRenderProp('key')`.
5. **Tests** (co-located next to `component.tsx`)
- `snapshot.spec.tsx` via `executeSnapshotTests`.
- `interaction.e2e.ts` only when interaction behavior justifies it.
### Phase 4: Remove Legacy Residue
- Delete orphaned files and obsolete wrappers.
- Remove unused imports/types/commented code.
- Ensure no unreferenced migration leftovers remain.
### Phase 5: Validation
Run from repo root:
```bash
pnpm format
pnpm lint
pnpm --filter @public-ui/components test:unit
```
If you changed build-specific configuration or packaging behavior, additionally run:
```bash
pnpm --filter @public-ui/components build
```
Do not cancel running commands.
---
## State Access Pattern (Current)
Controllers receive bundled state access:
```typescript
export type StateAccess<Api extends ComponentApi> = {
setState: SetStateFn<Api>;
getState: GetStateFn<Api>;
};
```
Preferred web component pattern:
```typescript
export class KolMyComponent extends BaseWebComponent<MyApi> {
private readonly ctrl = new MyController(this.stateAccess);
}
export class MyController extends BaseController<MyApi> {
public constructor(stateAccess: StateAccess<MyApi>) {
super(stateAccess, myPropsConfig);
}
}
```
Stateless/sentinel pattern for composed or legacy controllers:
```typescript
private readonly ctrl = new MyController(BaseWebComponent.stateLess);
```
`BaseWebComponent.stateLess` throws on state access by design. Use it only for controllers that never call `setState`/`getState`.
---
## Conventions
- `shadow: true` for web components.
- No `class` attribute on `<Host>`.
- Underscored external props (`_name`, `_label`).
- Tests co-located with component files.
- No new barrel files.
- ARIA reference IDs (`aria-controls`, `aria-labelledby`, `aria-describedby`, `aria-owns`) must be unique per instance, e.g.:
- `private readonly myId = \`prefix-${nonce()}\``from`utils/dev.utils`.
- Do not add `data-testid` to component markup; use stable BEM selectors in tests.
---
## Common Pitfalls
### 1. Incomplete Prop Triangle
Every `@Prop()` needs all three:
- declaration
- matching `@Watch()`
- initialization forwarding in `componentWillLoad()`
### 2. Host Class Anti-Pattern
Do not add `class="kol-..."` to `<Host>`.
### 3. Unused `@State()`
Only keep `@State()` fields that are actually read and updated for reactive UI.
### 4. Event Listener Leaks
Do not register inline listeners with new function references in lifecycle hooks.
Use stable arrow-property handlers.
### 5. Inline Ad-Hoc Prop Types
Do not define normalization/validation inline in components.
Use dedicated definitions in `src/internal/props/`.
### 6. Wrong Sentinel Assumption
Do not use `noopStateAccess` (not part of current implementation).
Use `BaseWebComponent.stateLess`.
### 7. JSDoc Type Noise in TS
Do not add redundant `@param {}` / `@returns {}` JSDoc type annotations in TypeScript.
---
## Pre-Review Checklist
- [ ] Gap analysis completed and used as migration plan
- [ ] API uses `PropsConfigShape` + `ApiFromConfig`
- [ ] Controller extends `BaseController<Api>` and receives `StateAccess<Api>`
- [ ] Web component uses `new Controller(this.stateAccess)` or justified `BaseWebComponent.stateLess`
- [ ] Prop triangle complete for every `@Prop()`
- [ ] Functional component is stateless
- [ ] `<Host>` has no redundant class attribute
- [ ] No dead code or orphaned files
- [ ] Tests co-located and updated
- [ ] Validation commands completed successfully
---
## Output
When finished, provide:
1. **Gap analysis**
2. **Deleted files** with justification
3. **New/modified files** grouped by architecture layer
4. **Completed pre-review checklist**
5. **Validation result** (commands + status)Signals
Information
- Repository
- public-ui/kolibri
- Author
- public-ui
- Last Sync
- 5/10/2026
- Repo Updated
- 5/9/2026
- Created
- 3/21/2026
Reviews (0)
No reviews yet. Be the first to review this skill!
Related Skills
upgrade-nodejs
Upgrading Bun's Self-Reported Node.js Version
cursorrules
CrewAI Development Rules
cn-check
Install and run the Continue CLI (`cn`) to execute AI agent checks on local code changes. Use when asked to "run checks", "lint with AI", "review my changes with cn", or set up Continue CI locally.
CLAUDE
CLAUDE.md
Related Guides
Bear Notes Claude Skill: Your AI-Powered Note-Taking Assistant
Learn how to use the bear-notes Claude skill. Complete guide with installation instructions and examples.
Mastering tmux with Claude: A Complete Guide to the tmux Claude Skill
Learn how to use the tmux Claude skill. Complete guide with installation instructions and examples.
OpenAI Whisper API Claude Skill: Complete Guide to AI-Powered Audio Transcription
Learn how to use the openai-whisper-api Claude skill. Complete guide with installation instructions and examples.