diff --git a/app/layout.tsx b/app/layout.tsx
index 705b549..1c1d24b 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -38,6 +38,8 @@ const structuredData = {
"Scan a GitHub repo to auto-detect stack, frameworks, and tooling",
"Context-aware questions with best-practice suggestions",
"Instant boilerplate generation with smart defaults",
+ "Claude Skill Builder for custom AI capabilities",
+ "Generate Skill.md files for Claude AI",
],
keywords: [
"AI coding guidelines",
@@ -51,6 +53,10 @@ const structuredData = {
"AI repo analyzer",
"GitHub repo scanner for Copilot",
"repo-aware coding guidelines",
+ "Claude Skill Builder",
+ "generate Skill.md file",
+ "Claude custom skills",
+ "AI agent capabilities",
],
};
@@ -83,6 +89,9 @@ export const metadata: Metadata = {
"generate coding standards from GitHub repo",
"repo-aware AI coding guidelines",
"auto-detect framework coding rules",
+ "Claude skills",
+ "Skill.md generator",
+ "custom AI capabilities",
],
authors: [{ name: "DevContext" }],
creator: "DevContext",
diff --git a/app/page.tsx b/app/page.tsx
index 3715200..8972680 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -61,6 +61,9 @@ export default function LandingPage() {
Browse stacks
+
+ Skill builder
+
Launch wizard
diff --git a/app/sitemap.ts b/app/sitemap.ts
index 5ce6b7b..51b5a54 100644
--- a/app/sitemap.ts
+++ b/app/sitemap.ts
@@ -9,12 +9,13 @@ const STATIC_ENTRIES: Array<{
priority: number
changeFrequency: MetadataRoute.Sitemap[number]["changeFrequency"]
}> = [
- { path: "", priority: 1, changeFrequency: "weekly" },
- { path: "/new", priority: 0.9, changeFrequency: "weekly" },
- { path: "/existing", priority: 0.6, changeFrequency: "monthly" },
- { path: "/stacks", priority: 0.7, changeFrequency: "monthly" },
- { path: "/new/stack", priority: 0.8, changeFrequency: "weekly" },
-]
+ { path: "", priority: 1, changeFrequency: "weekly" },
+ { path: "/new", priority: 0.9, changeFrequency: "weekly" },
+ { "path": "/skills", "priority": 0.85, "changeFrequency": "weekly" },
+ { path: "/existing", priority: 0.6, changeFrequency: "monthly" },
+ { path: "/stacks", priority: 0.7, changeFrequency: "monthly" },
+ { path: "/new/stack", priority: 0.8, changeFrequency: "weekly" },
+ ]
export default function sitemap(): MetadataRoute.Sitemap {
const lastModified = new Date()
diff --git a/app/skills/page.tsx b/app/skills/page.tsx
new file mode 100644
index 0000000..e51c582
--- /dev/null
+++ b/app/skills/page.tsx
@@ -0,0 +1,116 @@
+import { Github } from "lucide-react"
+import Link from "next/link"
+import type { Metadata } from "next"
+
+import { Button } from "@/components/ui/button"
+import { SkillBuilderForm } from "@/components/skill-builder-form"
+import { AnimatedBackground } from "@/components/AnimatedBackground"
+import { getAllSkills } from "@/lib/skills"
+
+export const metadata: Metadata = {
+ title: "Claude Skills Marketplace - Free AI Agent Skills Library",
+ description: "Browse and download high-quality Skill.md files for Claude and other AI agents. Enhance your AI with capabilities for Coding, DevOps, Testing, and more.",
+ keywords: ["Claude skills", "skills marketplace", "Skill.md", "AI agent capabilities", "coding skills", "devops skills"],
+ alternates: {
+ canonical: "/skills",
+ },
+}
+
+const structuredData = {
+ "@context": "https://schema.org",
+ "@type": "WebApplication",
+ "name": "Claude Skills Marketplace",
+ "description": "A marketplace of custom Skill.md files for Claude AI to enhance its capabilities.",
+ "url": "https://devcontext.xyz/skills",
+ "applicationCategory": "DeveloperApplication",
+ "operatingSystem": "Web",
+ "offers": {
+ "@type": "Offer",
+ "price": "0",
+ "priceCurrency": "USD"
+ }
+};
+
+export default function SkillsPage() {
+ const skills = getAllSkills();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ Beta
+
+ Skills Marketplace
+
+
+
+ Download ready-to-use Skill.md files or customize them to give Claude new capabilities.
+ Community-driven skills for Frameworks, DevOps, Testing, and Quality Assurance.
+
+
+
+
+
+
+
+
Frequently Asked Questions
+
+
+
What's in the Marketplace?
+
+ You'll find dozens of pre-configured skills covering everything from React Component generation to Docker configurations and Security Audits. All free to use and modify.
+
+
+
+
How do I contribute?
+
+ DevContext is open source! You can contribute new skills by adding a markdown file to the skills/ directory in our GitHub repository.
+
+
+
+
How do I use a Skill.md file?
+
+ Download the file and upload it to your Claude project, or reference it in your AI agent configuration (like local LLMs or Cursor).
+
+
+
+
Can I use these skills in IDEs?
+
+ Yes! Many IDE extensions and AI agents (like Cline, Roo Code, or Cursor) support custom skill definitions. By providing a structured Skill.md, you ensure consistent behavior across different environments.
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/components/Hero.tsx b/components/Hero.tsx
index f128273..539c73e 100644
--- a/components/Hero.tsx
+++ b/components/Hero.tsx
@@ -98,7 +98,7 @@ export function Hero() {
className="mx-auto max-w-2xl text-sm text-muted-foreground md:text-lg"
variants={itemVariants}
>
- Start from scratch with a guided wizard or analyze a public GitHub repo. DevContext detects languages, frameworks, tooling, and tests to generate Copilot instructions, Cursor rules, and onboarding docs you can edit and export.
+ Start from scratch with a guided wizard or analyze a public GitHub repo. DevContext detects languages, frameworks, tooling, and tests to generate Copilot instructions, Cursor rules, onboarding docs, and custom Claude skills you can edit and export.
diff --git a/components/skill-builder-form.tsx b/components/skill-builder-form.tsx
new file mode 100644
index 0000000..f9d8dfe
--- /dev/null
+++ b/components/skill-builder-form.tsx
@@ -0,0 +1,317 @@
+"use client"
+
+import { useState, useEffect } from "react"
+import { Download, Search, Check, FileText, X, Settings2, Eye } from "lucide-react"
+import { motion, AnimatePresence } from "framer-motion"
+import { type Skill } from "@/lib/skills"
+
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Label } from "@/components/ui/label"
+import { Textarea } from "@/components/ui/textarea"
+import { cn } from "@/lib/utils"
+
+interface SkillData {
+ name: string
+ description: string
+ dependencies: string
+ content: string
+}
+
+const DEFAULT_CONTENT = `## Steps
+1. [Step 1]
+2. [Step 2]
+
+## Examples
+User: [Input]
+Assistant: [Output]
+`
+
+interface SkillBuilderFormProps {
+ initialSkills: Skill[]
+}
+
+type Tab = "editor" | "preview"
+
+export function SkillBuilderForm({ initialSkills }: SkillBuilderFormProps) {
+ const [data, setData] = useState({
+ name: "",
+ description: "",
+ dependencies: "",
+ content: DEFAULT_CONTENT,
+ })
+
+ const [preview, setPreview] = useState("")
+ const [searchQuery, setSearchQuery] = useState("")
+ const [selectedSkillId, setSelectedSkillId] = useState(null)
+ const [isDrawerOpen, setIsDrawerOpen] = useState(false)
+ const [activeTab, setActiveTab] = useState("editor")
+
+ const filteredSkills = initialSkills.filter(skill =>
+ skill.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
+ skill.description.toLowerCase().includes(searchQuery.toLowerCase())
+ )
+
+ useEffect(() => {
+ // Generate preview
+ let output = `name: ${data.name || "My Skill"}\n`
+ output += `description: ${data.description || "Skill description"}\n`
+
+ if (data.dependencies) {
+ output += `dependencies: ${data.dependencies}\n`
+ }
+
+ output += `\n${data.content}`
+
+ setPreview(output)
+ }, [data])
+
+ // Prevent body scroll when drawer is open
+ useEffect(() => {
+ if (isDrawerOpen) {
+ document.body.style.overflow = "hidden"
+ } else {
+ document.body.style.overflow = "unset"
+ }
+ return () => {
+ document.body.style.overflow = "unset"
+ }
+ }, [isDrawerOpen])
+
+ const handleChange = (field: keyof SkillData, value: string) => {
+ setData((prev) => ({ ...prev, [field]: value }))
+ }
+
+ const handleDownload = () => {
+ const blob = new Blob([preview], { type: "text/markdown" })
+ const url = URL.createObjectURL(blob)
+ const link = document.createElement("a")
+ link.href = url
+ // Use the skill name for filename, replacing spaces with dashes, or default
+ const safeName = (data.name || "skill").toLowerCase().replace(/[^a-z0-9]+/g, "-")
+ link.download = `${safeName}.md`
+ document.body.appendChild(link)
+ link.click()
+ document.body.removeChild(link)
+ URL.revokeObjectURL(url)
+ }
+
+ const loadTemplate = (skill: Skill) => {
+ setData({
+ name: skill.name,
+ description: skill.description,
+ dependencies: skill.dependencies || "",
+ content: skill.content,
+ })
+ setSelectedSkillId(skill.id)
+ setIsDrawerOpen(true)
+ setActiveTab("editor")
+ }
+
+ const handleCreateNew = () => {
+ setData({
+ name: "",
+ description: "",
+ dependencies: "",
+ content: DEFAULT_CONTENT,
+ })
+ setSelectedSkillId(null)
+ setIsDrawerOpen(true)
+ setActiveTab("editor")
+ }
+
+ const handleCloseDrawer = () => {
+ setIsDrawerOpen(false)
+ setSelectedSkillId(null)
+ }
+
+ return (
+
+
+
+
+
Browse Skills Library
+
Select a skill to customize and download.
+
+
+
+
+ setSearchQuery(e.target.value)}
+ />
+
+
+ Create Custom
+
+
+
+
+
+ {filteredSkills.length > 0 ? (
+ filteredSkills.map((skill) => (
+
loadTemplate(skill)}
+ >
+
+
+ {selectedSkillId === skill.id &&
}
+
+
+ {skill.description}
+
+
+ ))
+ ) : (
+
+ No skills found matching your search.
+
+ )}
+
+
+
+
+ {isDrawerOpen && (
+ <>
+
+
+ {/* Drawer Header */}
+
+
+
+ {selectedSkillId ? "Edit Skill" : "Create New Skill"}
+
+
+ Customize metadata and content before downloading.
+
+
+
+
+
+
+
+ {/* Tabs / Toolbar */}
+
+
+ setActiveTab("editor")}
+ className={cn(
+ "flex items-center gap-2 px-3 py-1.5 text-sm font-medium rounded-md transition-all",
+ activeTab === "editor"
+ ? "bg-background shadow text-foreground"
+ : "text-muted-foreground hover:text-foreground"
+ )}
+ >
+
+ Editor
+
+ setActiveTab("preview")}
+ className={cn(
+ "flex items-center gap-2 px-3 py-1.5 text-sm font-medium rounded-md transition-all",
+ activeTab === "preview"
+ ? "bg-background shadow text-foreground"
+ : "text-muted-foreground hover:text-foreground"
+ )}
+ >
+
+ Preview
+
+
+
+
+
+ Download
+
+
+
+ {/* Drawer Content */}
+
+ {activeTab === "editor" ? (
+
+
+
+
+
Description (max 200 chars)
+
+
+
+ Markdown Body
+
+
+ ) : (
+
+ {preview}
+
+ )}
+
+
+ >
+ )}
+
+
+ )
+}
diff --git a/components/ui/collapsible.tsx b/components/ui/collapsible.tsx
new file mode 100644
index 0000000..0a71997
--- /dev/null
+++ b/components/ui/collapsible.tsx
@@ -0,0 +1,12 @@
+"use client"
+
+
+import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"
+
+const Collapsible = CollapsiblePrimitive.Root
+
+const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger
+
+const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent
+
+export { Collapsible, CollapsibleTrigger, CollapsibleContent }
diff --git a/components/ui/label.tsx b/components/ui/label.tsx
new file mode 100644
index 0000000..04da1b0
--- /dev/null
+++ b/components/ui/label.tsx
@@ -0,0 +1,23 @@
+"use client"
+
+import * as React from "react"
+import { cva, type VariantProps } from "class-variance-authority"
+import { cn } from "@/lib/utils"
+
+const labelVariants = cva(
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
+)
+
+const Label = React.forwardRef<
+ HTMLLabelElement,
+ React.LabelHTMLAttributes & VariantProps
+>(({ className, ...props }, ref) => (
+
+))
+Label.displayName = "Label"
+
+export { Label }
diff --git a/components/ui/textarea.tsx b/components/ui/textarea.tsx
new file mode 100644
index 0000000..dbf3e09
--- /dev/null
+++ b/components/ui/textarea.tsx
@@ -0,0 +1,23 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+export type TextareaProps = React.TextareaHTMLAttributes
+
+const Textarea = React.forwardRef(
+ ({ className, ...props }, ref) => {
+ return (
+
+ )
+ }
+)
+Textarea.displayName = "Textarea"
+
+export { Textarea }
diff --git a/file-templates/skill-template.md b/file-templates/skill-template.md
new file mode 100644
index 0000000..ae80c89
--- /dev/null
+++ b/file-templates/skill-template.md
@@ -0,0 +1,9 @@
+name: {{name}}
+description: {{description}}
+{{#if dependencies}}
+dependencies: {{dependencies}}
+{{/if}}
+
+{{#if content}}
+{{content}}
+{{/if}}
diff --git a/lib/skills.ts b/lib/skills.ts
new file mode 100644
index 0000000..9caad40
--- /dev/null
+++ b/lib/skills.ts
@@ -0,0 +1,49 @@
+import fs from 'fs'
+import path from 'path'
+import matter from 'gray-matter'
+
+const skillsDirectory = path.join(process.cwd(), 'skills')
+
+export interface Skill {
+ id: string
+ name: string
+ description: string
+ dependencies?: string
+ content: string
+}
+
+export function getAllSkills(): Skill[] {
+ // Create directory if it doesn't exist
+ if (!fs.existsSync(skillsDirectory)) {
+ return []
+ }
+
+ const fileNames = fs.readdirSync(skillsDirectory)
+ const allSkillsData = fileNames
+ .filter((fileName) => fileName.endsWith('.md'))
+ .map((fileName) => {
+ const id = fileName.replace(/\.md$/, '')
+ const fullPath = path.join(skillsDirectory, fileName)
+ const fileContents = fs.readFileSync(fullPath, 'utf8')
+ const { data, content } = matter(fileContents)
+
+ return {
+ id,
+ name: data.name || id,
+ description: data.description || '',
+ dependencies: data.dependencies || '',
+ content: content.trim(),
+ }
+ })
+
+ // Sort skills by name
+ return allSkillsData.sort((a, b) => {
+ if (a.name < b.name) {
+ return -1
+ }
+ if (a.name > b.name) {
+ return 1
+ }
+ return 0
+ })
+}
diff --git a/package-lock.json b/package-lock.json
index f415a3f..9873c31 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,10 +8,12 @@
"name": "devcontext",
"version": "0.1.0",
"dependencies": {
+ "@radix-ui/react-collapsible": "^1.1.12",
"@radix-ui/react-slot": "^1.2.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"framer-motion": "^11.18.2",
+ "gray-matter": "^4.0.3",
"jszip": "^3.10.1",
"lucide-react": "^0.544.0",
"mixpanel-browser": "^2.70.0",
@@ -2017,6 +2019,42 @@
"node": ">=18"
}
},
+ "node_modules/@radix-ui/primitive": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
+ "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==",
+ "license": "MIT"
+ },
+ "node_modules/@radix-ui/react-collapsible": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz",
+ "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-compose-refs": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
@@ -2032,6 +2070,86 @@
}
}
},
+ "node_modules/@radix-ui/react-context": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
+ "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-id": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
+ "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-presence": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
+ "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-primitive": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
+ "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.2.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-slot": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
@@ -2050,6 +2168,58 @@
}
}
},
+ "node_modules/@radix-ui/react-use-controllable-state": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
+ "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-effect-event": "0.0.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-effect-event": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
+ "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-layout-effect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
+ "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@rolldown/pluginutils": {
"version": "1.0.0-beta.35",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.35.tgz",
@@ -2889,7 +3059,7 @@
"version": "19.1.9",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.9.tgz",
"integrity": "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"peer": true,
"peerDependencies": {
@@ -5230,6 +5400,19 @@
"url": "https://opencollective.com/eslint"
}
},
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "license": "BSD-2-Clause",
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/esquery": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
@@ -5296,6 +5479,18 @@
"node": ">=12.0.0"
}
},
+ "node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "license": "MIT",
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -5677,6 +5872,43 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/gray-matter": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
+ "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==",
+ "license": "MIT",
+ "dependencies": {
+ "js-yaml": "^3.13.1",
+ "kind-of": "^6.0.2",
+ "section-matter": "^1.0.0",
+ "strip-bom-string": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/gray-matter/node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "license": "MIT",
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/gray-matter/node_modules/js-yaml": {
+ "version": "3.14.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
+ "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
"node_modules/has-bigints": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
@@ -6051,6 +6283,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -6502,6 +6743,15 @@
"json-buffer": "3.0.1"
}
},
+ "node_modules/kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/language-subtag-registry": {
"version": "0.3.23",
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
@@ -7998,6 +8248,19 @@
"integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==",
"license": "MIT"
},
+ "node_modules/section-matter": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
+ "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
+ "license": "MIT",
+ "dependencies": {
+ "extend-shallow": "^2.0.1",
+ "kind-of": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
@@ -8253,6 +8516,12 @@
"node": ">=0.10.0"
}
},
+ "node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+ "license": "BSD-3-Clause"
+ },
"node_modules/stable-hash": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz",
@@ -8420,6 +8689,15 @@
"node": ">=4"
}
},
+ "node_modules/strip-bom-string": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
+ "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/strip-indent": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
diff --git a/package.json b/package.json
index fbcc411..bb03276 100644
--- a/package.json
+++ b/package.json
@@ -14,10 +14,12 @@
"test:e2e": "playwright test"
},
"dependencies": {
+ "@radix-ui/react-collapsible": "^1.1.12",
"@radix-ui/react-slot": "^1.2.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"framer-motion": "^11.18.2",
+ "gray-matter": "^4.0.3",
"jszip": "^3.10.1",
"lucide-react": "^0.544.0",
"mixpanel-browser": "^2.70.0",
diff --git a/skills/accessibility-audit.md b/skills/accessibility-audit.md
new file mode 100644
index 0000000..f6706d8
--- /dev/null
+++ b/skills/accessibility-audit.md
@@ -0,0 +1,25 @@
+---
+name: Accessibility (a11y) Check
+description: Review code for WCAG accessibility compliance.
+dependencies: ""
+---
+
+## Guidelines
+- Ensure all images have \`alt\` text.
+- Verify color contrast (minimum 4.5:1 for text).
+- Check heading hierarchy (h1 -> h2 -> h3).
+- Verify interactive elements have aria-labels if no text.
+- Ensure keyboard navigability.
+
+## Checklist
+- [ ] Images have descriptive alt text?
+- [ ] Forms have labels connected to inputs?
+- [ ] Buttons are reachable by Tab key?
+- [ ] Focus states are visible?
+- [ ] Semantic HTML is used (nav, main, footer)?
+
+## Example Issues
+User: check this snippet
+Assistant:
+1. \`\` should be a \`
\` for keyboard access.
+2. \` \` is missing \`alt\` tag.
diff --git a/skills/angular-component.md b/skills/angular-component.md
new file mode 100644
index 0000000..5de67b0
--- /dev/null
+++ b/skills/angular-component.md
@@ -0,0 +1,46 @@
+---
+name: Angular Component Generator
+description: Scaffold a standalone Angular component with best practices (SCSS, typed inputs).
+dependencies: "@angular/core, @angular/common"
+---
+
+## Guidelines
+- Follow the Angular Style Guide.
+- Use standalone components.
+- Use typed inputs and outputs.
+- Implement OnPush change detection.
+
+## Template
+\`\`\`typescript
+import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+@Component({
+ selector: 'app-custom-card',
+ standalone: true,
+ imports: [CommonModule],
+ template: \`
+
+ \`,
+ styles: [\`
+ .card { border: 1px solid #ccc; padding: 1rem; border-radius: 4px; }
+ .highlighted { border-color: blue; }
+ \`],
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class CustomCardComponent {
+ @Input({ required: true }) title!: string;
+ @Input() isHighlighted = false;
+ @Output() onAction = new EventEmitter();
+}
+\`\`\`
diff --git a/skills/api-endpoint-nextjs.md b/skills/api-endpoint-nextjs.md
new file mode 100644
index 0000000..3fc5130
--- /dev/null
+++ b/skills/api-endpoint-nextjs.md
@@ -0,0 +1,47 @@
+---
+name: Next.js API Route (App Router)
+description: Create a type-safe Next.js Route Handler.
+dependencies: "next, zod"
+---
+
+## Guidelines
+- Use \`NextResponse\`.
+- Use \`zod\` for request validation.
+- Handle errors gracefully.
+- Check authentication if needed.
+
+## Template
+\`\`\`typescript
+import { NextResponse } from "next/server";
+import { z } from "zod";
+
+const schema = z.object({
+ email: z.string().email(),
+ role: z.enum(["admin", "user"]),
+});
+
+export async function POST(request: Request) {
+ try {
+ const body = await request.json();
+ const result = schema.safeParse(body);
+
+ if (!result.success) {
+ return NextResponse.json(
+ { error: "Invalid request", details: result.error.flatten() },
+ { status: 400 }
+ );
+ }
+
+ // Perform database operation here
+ // const user = await db.user.create({ ... })
+
+ return NextResponse.json({ success: true, data: result.data });
+ } catch (error) {
+ console.error("API Error:", error);
+ return NextResponse.json(
+ { error: "Internal Server Error" },
+ { status: 500 }
+ );
+ }
+}
+\`\`\`
diff --git a/skills/bug-analysis.md b/skills/bug-analysis.md
new file mode 100644
index 0000000..2e37f51
--- /dev/null
+++ b/skills/bug-analysis.md
@@ -0,0 +1,19 @@
+---
+name: Bug Analysis & Fix
+description: Analyze error logs/descriptions and propose fixes.
+dependencies: ""
+---
+
+## Process
+1. Reproduce: Understand the steps to trigger the bug.
+2. Isolate: Identify the component or function responsible.
+3. Root Cause: Why is it happening? (Race condition, null pointer, logic error).
+4. Fix: Propose a solution that handles the root cause, not just a patch.
+
+## Request Format
+User: Here is the stack trace and the code snippet.
+Assistant:
+**Analysis**: The error `Cannot read properties of undefined (reading 'map')` occurs on line 12.
+**Root Cause**: The API response `users` is sometimes null if no users are found.
+**Fix**: Add a default value or optional chaining.
+\`users?.map(...)\` or \`const safeUsers = users || [];\`
diff --git a/skills/code-style.md b/skills/code-style.md
new file mode 100644
index 0000000..ad562b6
--- /dev/null
+++ b/skills/code-style.md
@@ -0,0 +1,19 @@
+---
+name: Code Style Enforcer
+description: Standardize code style and formatting rules for consistency.
+dependencies: ""
+---
+
+## Principles
+- Clarity over cleverness
+- Consistent naming conventions
+- Early returns for guard clauses
+
+## Naming Conventions
+- specific_variable_names (snake_case for Python)
+- camelCaseVariableNames (camelCase for JS/TS)
+- PascalCaseComponentNames (PascalCase for React components)
+
+## Examples
+User: How should I name this variable?
+Assistant: Since this is a boolean flag in TypeScript, use \`is\` or \`has\` prefix, e.g., \`isValidUser\` or \`hasPermission\`.
diff --git a/skills/commit-message.md b/skills/commit-message.md
new file mode 100644
index 0000000..0af2232
--- /dev/null
+++ b/skills/commit-message.md
@@ -0,0 +1,22 @@
+---
+name: Commit Message Formatter
+description: Format commit messages using Conventional Commits.
+dependencies: ""
+---
+
+## Format
+\`(): \`
+
+## Types
+- \`feat\`: New feature.
+- \`fix\`: Bug fix.
+- \`docs\`: Documentation only.
+- \`style\`: Formatting, missing semi colons, etc.
+- \`refactor\`: Code change that neither fixes a bug nor adds a feature.
+- \`test\`: Adding missing tests.
+- \`chore\`: Build process or aux updates.
+
+## Examples
+- \`feat(auth): add google oauth login\`
+- \`fix(api): handle null user response\`
+- \`docs(readme): update installation steps\`
diff --git a/skills/design-system-tokens.md b/skills/design-system-tokens.md
new file mode 100644
index 0000000..6d6fdc6
--- /dev/null
+++ b/skills/design-system-tokens.md
@@ -0,0 +1,26 @@
+---
+name: Design System Tokens
+description: Manage and explain design tokens (colors, spacing, typography).
+dependencies: ""
+---
+
+## Concept
+Use semantic names (what it is used for) over primitive names (what it looks like).
+
+## Format (CSS Variables)
+\`\`\`css
+:root {
+ /* Primitive */
+ --blue-500: #3b82f6;
+
+ /* Semantic */
+ --color-primary: var(--blue-500);
+ --color-text-body: #1f2937;
+ --spacing-unit: 4px;
+ --spacing-md: calc(var(--spacing-unit) * 4); /* 16px */
+}
+\`\`\`
+
+## Usage
+- Don't use hex codes in components.
+- Use \`var(--color-primary)\`.
diff --git a/skills/dockerfile-generator.md b/skills/dockerfile-generator.md
new file mode 100644
index 0000000..7d750e3
--- /dev/null
+++ b/skills/dockerfile-generator.md
@@ -0,0 +1,35 @@
+---
+name: Dockerfile Generator
+description: Create optimized multi-stage Dockerfiles for various apps.
+dependencies: ""
+---
+
+## Best Practices
+- Use multi-stage builds to reduce image size.
+- Use explicit tag versions for base images (`node:18-alpine`).
+- Run as non-root user.
+- Layer ordering (copy package.json -> install -> copy source).
+
+## Template (Node.js)
+\`\`\`dockerfile
+# Stage 1: Build
+FROM node:18-alpine AS builder
+WORKDIR /app
+COPY package*.json ./
+RUN npm ci
+COPY . .
+RUN npm run build
+
+# Stage 2: Production
+FROM node:18-alpine AS runner
+WORKDIR /app
+ENV NODE_ENV=production
+COPY --from=builder /app/public ./public
+COPY --from=builder /app/.next ./.next
+COPY --from=builder /app/node_modules ./node_modules
+COPY --from=builder /app/package.json ./package.json
+
+USER node
+EXPOSE 3000
+CMD ["npm", "start"]
+\`\`\`
diff --git a/skills/documentation.md b/skills/documentation.md
new file mode 100644
index 0000000..530a578
--- /dev/null
+++ b/skills/documentation.md
@@ -0,0 +1,28 @@
+---
+name: Docstring Generator
+description: Generate comprehensive documentation for functions and classes.
+dependencies: ""
+---
+
+## Goal
+Produce high-quality documentation comments for all exported functions and classes.
+
+## Format
+For TypeScript/JavaScript, use JSDoc:
+/**
+ * Short description.
+ *
+ * @param {Type} name - Description
+ * @returns {Type} Description
+ */
+
+## Examples
+User: Document this function
+Assistant:
+/**
+ * Calculates the total sum of an array of numbers.
+ *
+ * @param {number[]} numbers - The list of numbers to sum.
+ * @returns {number} The total sum.
+ */
+function sum(numbers: number[]): number { ... }
diff --git a/skills/fastapi-route.md b/skills/fastapi-route.md
new file mode 100644
index 0000000..0ed74a3
--- /dev/null
+++ b/skills/fastapi-route.md
@@ -0,0 +1,38 @@
+---
+name: FastAPI Route Generator
+description: Create a Python FastAPI API endpoint with Pydantic models.
+dependencies: "fastapi, pydantic"
+---
+
+## Guidelines
+- Use Pydantic models for request/response schemas.
+- Use dependency injection for DB sessions or services.
+- Include proper status codes and error handling.
+
+## Template
+\`\`\`python
+from fastapi import APIRouter, HTTPException, status
+from pydantic import BaseModel, EmailStr
+
+router = APIRouter()
+
+class UserCreate(BaseModel):
+ email: EmailStr
+ full_name: str | None = None
+ age: int
+
+class UserResponse(UserCreate):
+ id: int
+
+@router.post("/users/", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
+async def create_user(user: UserCreate):
+ # Simulate DB lookup
+ if user.email == "exists@example.com":
+ raise HTTPException(
+ status_code=400,
+ detail="Email already registered"
+ )
+
+ # Simulate saving
+ return {**user.dict(), "id": 123}
+\`\`\`
diff --git a/skills/github-action.md b/skills/github-action.md
new file mode 100644
index 0000000..d4fa0d2
--- /dev/null
+++ b/skills/github-action.md
@@ -0,0 +1,37 @@
+---
+name: GitHub Action Workflow
+description: Create GitHub Actions for CI/CD pipelines.
+dependencies: ""
+---
+
+## Components
+- Triggers (`on: push`, `pull_request`).
+- Jobs (build, test, deploy).
+- Steps (checkout, setup-node, run scripts).
+
+## Template (CI)
+\`\`\`yaml
+name: CI
+
+on:
+ push:
+ branches: ["main"]
+ pull_request:
+ types: [opened, synchronize]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v3
+ with:
+ node-version: 18
+ cache: 'npm'
+ - name: Install dependencies
+ run: npm ci
+ - name: Lint
+ run: npm run lint
+ - name: Test
+ run: npm test
+\`\`\`
diff --git a/skills/kubernetes-manifest.md b/skills/kubernetes-manifest.md
new file mode 100644
index 0000000..91758f8
--- /dev/null
+++ b/skills/kubernetes-manifest.md
@@ -0,0 +1,52 @@
+---
+name: Kubernetes Manifest
+description: Generate K8s Deployment and Service YAMLs.
+dependencies: ""
+---
+
+## Basics
+- Deployment: Defines Pods, Replicas, Container specs.
+- Service: Exposes Pods (ClusterIP, NodePort, LoadBalancer).
+- ConfigMap/Secret: Environment variables.
+
+## Template
+\`\`\`yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: my-app
+ labels:
+ app: my-app
+spec:
+ replicas: 3
+ selector:
+ matchLabels:
+ app: my-app
+ template:
+ metadata:
+ labels:
+ app: my-app
+ spec:
+ containers:
+ - name: my-app
+ image: myregistry/my-app:v1
+ ports:
+ - containerPort: 8080
+ resources:
+ limits:
+ memory: "512Mi"
+ cpu: "500m"
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: my-app-service
+spec:
+ selector:
+ app: my-app
+ ports:
+ - protocol: TCP
+ port: 80
+ targetPort: 8080
+ type: ClusterIP
+\`\`\`
diff --git a/skills/nginx-config.md b/skills/nginx-config.md
new file mode 100644
index 0000000..56554c6
--- /dev/null
+++ b/skills/nginx-config.md
@@ -0,0 +1,28 @@
+---
+name: Nginx Configuration
+description: Create Nginx server blocks for reverse proxy or static serving.
+dependencies: ""
+---
+
+## Common directives
+- \`listen\`: Port.
+- \`server_name\`: Domain.
+- \`location\`: Routing rules.
+- \`proxy_pass\`: Reverse proxy.
+
+## Template (Reverse Proxy)
+\`\`\`nginx
+server {
+ listen 80;
+ server_name example.com;
+
+ location / {
+ proxy_pass http://localhost:3000;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection 'upgrade';
+ proxy_set_header Host $host;
+ proxy_cache_bypass $http_upgrade;
+ }
+}
+\`\`\`
diff --git a/skills/performance-optimization.md b/skills/performance-optimization.md
new file mode 100644
index 0000000..fd71b00
--- /dev/null
+++ b/skills/performance-optimization.md
@@ -0,0 +1,32 @@
+---
+name: Performance Optimization
+description: Identify bottlenecks and optimize React/Node code.
+dependencies: ""
+---
+
+## Areas to Inspect
+- React: Unnecessary re-renders, large bundles, missing memoization.
+- Node/DB: N+1 queries, missing indexes, heavy synchronous computation.
+- Network: Large payloads, waterfall requests.
+
+## Checklist
+- [ ] Is data fetching parallelized where possible?
+- [ ] Are heavy computations memoized (useMemo)?
+- [ ] Are images optimized/lazy loaded?
+- [ ] Is code splitting implemented?
+
+## Refactoring Pattern
+Bad:
+\`\`\`js
+props.items.forEach(item => {
+ // Database call inside loop (N+1)
+ await db.getDetails(item.id);
+})
+\`\`\`
+
+Good:
+\`\`\`js
+// Batch fetch
+const itemIds = props.items.map(i => i.id);
+const details = await db.getDetailsForIds(itemIds);
+\`\`\`
diff --git a/skills/playwright-e2e.md b/skills/playwright-e2e.md
new file mode 100644
index 0000000..01ea9e1
--- /dev/null
+++ b/skills/playwright-e2e.md
@@ -0,0 +1,36 @@
+---
+name: Playwright E2E Tests
+description: Write end-to-end tests using Playwright.
+dependencies: "@playwright/test"
+---
+
+## Guidelines
+- Use page objects where complex interactions occur.
+- Test user-visible behavior (clicks, navigation).
+- Use distinct locators (test-id preferred).
+
+## Template
+\`\`\`typescript
+import { test, expect } from '@playwright/test';
+
+test.describe('Login Flow', () => {
+ test('should allow user to login', async ({ page }) => {
+ await page.goto('/login');
+
+ await page.fill('input[name="email"]', 'user@example.com');
+ await page.fill('input[name="password"]', 'password');
+ await page.click('button[type="submit"]');
+
+ await expect(page).toHaveURL('/dashboard');
+ await expect(page.getByText('Welcome back')).toBeVisible();
+ });
+
+ test('should show error on invalid credentials', async ({ page }) => {
+ await page.goto('/login');
+ await page.fill('input[name="email"]', 'wrong@example.com');
+ await page.click('button[type="submit"]');
+
+ await expect(page.getByRole('alert')).toContainText('Invalid credentials');
+ });
+});
+\`\`\`
diff --git a/skills/react-component.md b/skills/react-component.md
new file mode 100644
index 0000000..75f2ddc
--- /dev/null
+++ b/skills/react-component.md
@@ -0,0 +1,29 @@
+---
+name: React Component
+description: Scaffold a new React component with best practices.
+dependencies: "react, lucide-react, clsx, tailwind-merge"
+---
+
+## Structure
+- Use functional components with named exports.
+- Use explicit return types.
+- Destructure props.
+- Use 'cn' utility for class merging.
+
+## Template
+\`\`\`tsx
+import { cn } from "@/lib/utils"
+
+interface MyComponentProps {
+ className?: string
+ children?: React.ReactNode
+}
+
+export function MyComponent({ className, children }: MyComponentProps) {
+ return (
+
+ {children}
+
+ )
+}
+\`\`\`
diff --git a/skills/readme-generator.md b/skills/readme-generator.md
new file mode 100644
index 0000000..091895a
--- /dev/null
+++ b/skills/readme-generator.md
@@ -0,0 +1,44 @@
+---
+name: README Generator
+description: Create a comprehensive README.md for a project.
+dependencies: ""
+---
+
+## Sections to Include
+- Project Title & Badges.
+- Description (What problem does it solve?).
+- Tech Stack.
+- Installation & Running.
+- Usage / Features.
+- Contributing.
+- License.
+
+## Template
+\`\`\`markdown
+# Project Name
+
+
+
+Brief description of the project.
+
+## Features
+- Feature A
+- Feature B
+
+## Getting Started
+
+### Prerequisites
+- Node.js >= 18
+
+### Installation
+\`\`\`bash
+npm install
+npm run dev
+\`\`\`
+
+## Contributing
+Pull requests are welcome. For major changes, please open an issue first.
+
+## License
+[MIT](LICENSE)
+\`\`\`
diff --git a/skills/release-notes.md b/skills/release-notes.md
new file mode 100644
index 0000000..6b007da
--- /dev/null
+++ b/skills/release-notes.md
@@ -0,0 +1,25 @@
+---
+name: Release Notes Generator
+description: Generate release notes from a list of changes.
+dependencies: ""
+---
+
+## Structure
+- Version Number & Date.
+- **Breaking Changes** (Highlight these!).
+- **Features**: New capabilities.
+- **Bug Fixes**: Resolved issues.
+- **Internal**: Refactors or dependency updates.
+
+## Example
+### v2.1.0 (2025-01-27)
+
+**Features**
+- Added dark mode support to all pages.
+- New "Skills Marketplace" launched.
+
+**Bug Fixes**
+- Fixed crash on Safari when resizing window.
+
+**Breaking Changes**
+- Deprecated \`getUserV1\`, please use \`getUserV2\`.
diff --git a/skills/security-audit.md b/skills/security-audit.md
new file mode 100644
index 0000000..99c829d
--- /dev/null
+++ b/skills/security-audit.md
@@ -0,0 +1,26 @@
+---
+name: Security Audit Helper
+description: Analyze code for common security vulnerabilities (OWASP Top 10).
+dependencies: ""
+---
+
+## Scope
+- Injection (SQL, NoSQL, Command)
+- Broken Authentication
+- Sensitive Data Exposure
+- XSS (Cross-Site Scripting)
+
+## Instructions
+1. Identify input sources (params, changes, body).
+2. Check if inputs are sanitized/validated.
+3. Look for hardcoded secrets.
+4. Verify authorization checks on sensitive actions.
+
+## Examples
+User: Audit this function
+Assistant:
+Potential Issue:
+\`const query = "SELECT * FROM users WHERE name = '" + userName + "'";\`
+Risk: SQL Injection.
+Fix: Use parameterized queries:
+\`const query = "SELECT * FROM users WHERE name = ?";\`
diff --git a/skills/svelte-component.md b/skills/svelte-component.md
new file mode 100644
index 0000000..c587d04
--- /dev/null
+++ b/skills/svelte-component.md
@@ -0,0 +1,37 @@
+---
+name: Svelte Component Generator
+description: Scaffold a Svelte 5 component (Runes mode).
+dependencies: "svelte"
+---
+
+## Guidelines
+- Use Svelte 5 syntax (Runes) if applicable, or standard Svelte 3/4.
+- Use \`$props()\` and \`$state()\` for Svelte 5.
+- Scoped styles by default.
+
+## Template (Svelte 5)
+\`\`\`svelte
+
+
+
+
{title}
+
Value: {count} (2x: {doubled})
+
Update
+
+
+
+\`\`\`
diff --git a/skills/technical-specs.md b/skills/technical-specs.md
new file mode 100644
index 0000000..3b52744
--- /dev/null
+++ b/skills/technical-specs.md
@@ -0,0 +1,19 @@
+---
+name: Technical Spec writer
+description: Draft technical specifications for new features.
+dependencies: ""
+---
+
+## Sections
+1. **Background**: Context and problem statement.
+2. **Goals**: What are we trying to achieve? (Non-goals too).
+3. **Proposed Solution**: High-level approach.
+4. **Data Model**: Schema changes.
+5. **API Changes**: Endpoints modified/added.
+6. **UI/UX**: Component hierarchy or mockups described.
+7. **Risks/Alternatives**: What could go wrong?
+
+## Example
+**Goal**: Add user avatars.
+**Data Model**: Add \`avatar_url\` string to \`users\` table.
+**API**: Update \`POST /user/profile\` to accept file upload or URL.
diff --git a/skills/tsconfig-generator.md b/skills/tsconfig-generator.md
new file mode 100644
index 0000000..096b5fc
--- /dev/null
+++ b/skills/tsconfig-generator.md
@@ -0,0 +1,42 @@
+---
+name: TSConfig Generator
+description: Create or update tsconfig.json for different environments.
+dependencies: "typescript"
+---
+
+## Options
+- \`target\`: JS version output.
+- \`module\`: Module system (ESNext, CommonJS).
+- \`strict\`: Enable strict type checking.
+- \`lib\`: Library files (DOM, ES2020).
+
+## Template (Strict Next.js)
+\`\`\`json
+{
+ "compilerOptions": {
+ "target": "es5",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve",
+ "incremental": true,
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ],
+ "paths": {
+ "@/*": ["./*"]
+ }
+ },
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
+ "exclude": ["node_modules"]
+}
+\`\`\`
diff --git a/skills/unit-testing.md b/skills/unit-testing.md
new file mode 100644
index 0000000..504e082
--- /dev/null
+++ b/skills/unit-testing.md
@@ -0,0 +1,25 @@
+---
+name: Unit Testing
+description: Generate robust unit tests for your code.
+dependencies: "jest, vitest, @testing-library/react"
+---
+
+## Guidelines
+- Test behavior, not implementation details.
+- Use descriptive test names ("should do X when Y").
+- Arrange, Act, Assert pattern.
+- Mock external dependencies.
+
+## Checklist
+- [ ] Happy path tested?
+- [ ] Error states tested?
+- [ ] Edge cases (empty arrays, nulls) tested?
+
+## Example
+\`\`\`ts
+describe("calculator", () => {
+ it("should add two numbers correctly", () => {
+ expect(add(1, 2)).toBe(3)
+ })
+})
+\`\`\`
diff --git a/skills/vue-component.md b/skills/vue-component.md
new file mode 100644
index 0000000..8b7c4a6
--- /dev/null
+++ b/skills/vue-component.md
@@ -0,0 +1,51 @@
+---
+name: Vue 3 Component Generator
+description: Create a Vue 3 component using Composition API and TypeScript.
+dependencies: "vue"
+---
+
+## Guidelines
+- Use \`
+
+
+
+
{{ title }}
+
Count: {{ count }} (Double: {{ doubleCount }})
+
Increment
+
+
+
+
+\`\`\`