Building and Publishing Your Own Skills
Your team has a component pattern that every React file must follow: interface-first, hooks at the top, handlers in the middle, JSX at the bottom. A naming convention for API routes. A commit message format. A deployment checklist. You explain these patterns to the AI at the start of every session. Worse, every developer on the team explains them slightly differently, so the AI produces inconsistent output depending on who is prompting.
A custom skill captures these conventions in a structured, shareable format. Install it once and every AI session — for every developer on the team — follows the same rules. When a convention changes, update the skill in one place and every developer gets the update.
What You’ll Walk Away With
Section titled “What You’ll Walk Away With”- The complete skill file structure:
SKILL.md,rules/, andinstall.md - How to write effective
SKILL.mdinstructions that the AI follows consistently - Local testing workflow before publishing
- Publishing a skill to GitHub and listing it on skills.sh
- Maintenance and versioning strategies for long-lived skills
Why Build a Custom Skill
Section titled “Why Build a Custom Skill”Framework skills from the marketplace (React best practices, Next.js patterns) cover general knowledge. They do not know about your specific project:
- Your file naming conventions
- Your error handling middleware stack
- Your deployment process and environment variables
- Your testing patterns and coverage requirements
- Your PR template and code review expectations
A custom skill fills this gap. It encodes the project-specific knowledge that exists in your team’s collective memory and makes it available to the AI automatically.
Skill File Structure
Section titled “Skill File Structure”A skill is a GitHub repository with a specific directory layout. The skills CLI reads this structure when installing.
my-team-skill/ SKILL.md # Primary instructions the AI reads rules/ # Additional rule files (optional) architecture.md # Architecture-specific rules testing.md # Testing-specific rules deployment.md # Deployment-specific rules install.md # Post-install instructions for the developer README.md # Marketplace description and documentationSKILL.md — The Core Instructions
Section titled “SKILL.md — The Core Instructions”SKILL.md is the main file the AI reads. Everything in this file becomes part of the agent’s context. Write it as direct instructions to the AI.
# Acme Corp Development Conventions
## Component Structure
When creating React components, use this exact structure:
```tsx// src/components/FeatureName/FeatureName.tsxinterface FeatureNameProps { id: string; onAction?: () => void;}
export function FeatureName({ id, onAction }: FeatureNameProps) { // 1. Hooks const [state, setState] = useState(false); const data = useQuery(['feature', id]);
// 2. Handlers const handleClick = () => onAction?.();
// 3. Early returns for loading/error states if (data.isLoading) return <FeatureNameSkeleton />; if (data.error) return <ErrorBoundary error={data.error} />;
// 4. Main render return ( <div data-testid="feature-name"> {/* component JSX */} </div> );}```
Rules:- One component per file- Directory name matches component name (PascalCase)- Props interface in same file, named `ComponentNameProps`- Named exports only, never default exports- Always include data-testid for testing
## API Routes
```typescript// src/pages/api/resource-name.tsimport { withAuth } from '~/lib/middleware';import { validate } from '~/lib/validation';import { ResourceSchema } from '~/lib/schemas';
export const POST = withAuth(async ({ request, locals }) => { const body = await validate(request, ResourceSchema); const result = await createResource(locals.runtime.env.DB, body); return Response.json(result, { status: 201 });});```
Rules:- Always validate with Zod schemas before processing- Always wrap authenticated endpoints with `withAuth`- Use `Response.json()` not `new Response(JSON.stringify(...))`- Return appropriate HTTP status codes (201 for creation, 204 for deletion)
## Error Handling
- Use `AppError` from `~/lib/errors` for all error responses- Never throw plain strings or generic Error objects- Log with structured context: `logger.error('message', { userId, action, error })`- Never expose stack traces or internal details in API responsesrules/ — Supplementary Rule Files
Section titled “rules/ — Supplementary Rule Files”The rules/ directory contains additional instruction files for specific concerns. These are included alongside SKILL.md when the skill is installed.
## Testing Conventions
Every component gets a colocated test file: `FeatureName.test.tsx`
Use this test structure:
```tsximport { render, screen, fireEvent } from '@testing-library/react';import { FeatureName } from './FeatureName';
describe('FeatureName', () => { it('renders without crashing', () => { render(<FeatureName id="test-1" />); expect(screen.getByTestId('feature-name')).toBeInTheDocument(); });
it('calls onAction when clicked', () => { const onAction = vi.fn(); render(<FeatureName id="test-1" onAction={onAction} />); fireEvent.click(screen.getByRole('button')); expect(onAction).toHaveBeenCalledOnce(); });});```
Rules:- Test behavior, not implementation details- Use `data-testid` selectors, not CSS class selectors- Mock external dependencies, not internal functions- Each test file must pass independently (no shared state between tests)install.md — Post-Install Instructions
Section titled “install.md — Post-Install Instructions”install.md tells the developer what to do after installing the skill. This is displayed by the skills CLI after installation completes.
# Post-Install Setup
This skill requires the following project dependencies:
```bashnpm install -D @testing-library/react vitest```
## Configuration
Add to your `vitest.config.ts`:
```typescriptexport default defineConfig({ test: { environment: 'happy-dom', setupFiles: ['./tests/setup.ts'], },});```
## Verification
Run this command to verify the skill is working:
```bashnpx skills list```
Then ask the AI: "Create a sample component following all project conventions."Review the output to confirm it matches the patterns defined in the skill.Creating Your Skill Step by Step
Section titled “Creating Your Skill Step by Step”-
Create a GitHub repository. Name it descriptively:
acme/coding-conventions,acme/react-patterns, oracme/deployment-workflow. -
Create the file structure.
Terminal window mkdir -p my-skill/rulestouch my-skill/SKILL.md my-skill/install.md my-skill/README.md -
Write SKILL.md. Follow the guidelines above. Be specific, use real examples from your codebase, and prioritize conventions the AI gets wrong most often.
-
Add supplementary rules. If your skill covers multiple concerns (architecture, testing, deployment), split them into
rules/files for organization. -
Write install.md. List any dependencies the developer needs to install and any configuration required for the skill to work properly.
-
Write README.md. This is the public face of your skill on the marketplace. Include:
- What the skill teaches the AI
- What tech stack it applies to
- Installation command
- Example prompts that demonstrate the skill in action
-
Push to GitHub.
Terminal window cd my-skillgit init && git add . && git commit -m "Initial skill release"git remote add origin https://github.com/acme/coding-conventions.gitgit push -u origin main -
Test locally before publishing.
Testing Your Skill Locally
Section titled “Testing Your Skill Locally”Before publishing, verify the skill works correctly in each tool.
# Install from your repo (even before publishing to marketplace)npx skills add acme/coding-conventions
# Verify files were createdls .cursor/rules/
# Open Cursor and test with a prompt# "Create a new API endpoint for user profile updates# following all project conventions."Check that the AI:
- Uses the component structure from your SKILL.md
- Follows the error handling pattern you specified
- Creates test files in the format you defined
- Uses the import ordering you documented
# Install from your reponpx skills add acme/coding-conventions
# Verify files were createdls .claude/skills/
# Test in a Claude Code sessionclaude "Create a new API endpoint for user profile updatesfollowing all project conventions."Verify the same checklist. Also check that Claude Code discovers and applies rules from the rules/ subdirectory.
# Install from your reponpx skills add acme/coding-conventions
# Verify instructions were updatedcat .codex/instructions.md
# Test with a Codex taskcodex "Create a new API endpoint for user profile updatesfollowing all project conventions."Since Codex runs autonomously, pay extra attention to whether the output matches your conventions without any interactive correction.
Testing Checklist
Section titled “Testing Checklist”After generating code with the skill installed, verify:
- File naming matches your convention
- Component structure matches the template in SKILL.md
- Import ordering is correct
- Error handling follows your pattern
- Test files are created with the right structure
- API routes use your middleware pattern
- No conventions from SKILL.md were ignored
Writing Effective Instructions
Section titled “Writing Effective Instructions”Be Specific, Not Aspirational
Section titled “Be Specific, Not Aspirational”The AI cannot follow “write clean, maintainable code.” It can follow “use named exports, add JSDoc to public functions, and prefix private methods with an underscore.”
Bad: “Follow best practices for error handling.”
Good: “Wrap all database calls in try/catch. On failure, throw new AppError('RESOURCE_NOT_FOUND', 404) with the appropriate error code and HTTP status. Never throw plain strings.”
Prioritize the Non-Obvious
Section titled “Prioritize the Non-Obvious”The AI already knows how to write TypeScript. It does not know that your team prefers interface over type for object shapes, or that your API routes must always call validateRequest before processing. Focus on what makes your project different.
Show, Don’t Just Tell
Section titled “Show, Don’t Just Tell”Every instruction should have a concrete code example. The AI follows examples more reliably than prose descriptions.
Stay Under 2,000 Words
Section titled “Stay Under 2,000 Words”Long skills get diluted. The AI processes the beginning of the skill more attentively than the end. Put the highest-impact conventions first.
Use Explicit Override Language
Section titled “Use Explicit Override Language”If your skill contradicts general framework patterns, say so explicitly:
## ExportsAlways use named exports. Never use default exports.(This overrides the common React pattern of default-exporting components.)Publishing to skills.sh
Section titled “Publishing to skills.sh”The skills.sh marketplace indexes public GitHub repositories that follow the skill format.
-
Add GitHub topics. Go to your repository settings and add these topics:
agent-skills,ai-skills, and relevant technology tags (react,typescript,nextjs). -
Ensure your README is complete. The marketplace displays your README. Include:
- Skill description
- Tech stack it applies to
- Installation command:
npx skills add your-org/your-skill - Example prompts
- Screenshot or code sample showing the skill in action
-
Submit to skills.sh. Follow the submission process on the skills.sh website. After review, your skill appears in search results.
-
Promote your skill. Share on dev communities, include in blog posts, and reference in your project documentation.
For Internal (Private) Skills
Section titled “For Internal (Private) Skills”If your conventions are proprietary:
- Private GitHub repository. The skills CLI installs from private repos if the developer has GitHub access configured.
- Direct file commit. Skip the skills CLI entirely and commit the instruction files directly to your project’s
.cursor/rules/,.claude/skills/, orCLAUDE.md. - Private npm package. Package the skill as an npm package on your company’s private registry.
Maintaining Skills Over Time
Section titled “Maintaining Skills Over Time”Versioning
Section titled “Versioning”Tag releases when you make significant changes:
git tag v1.0.0git push origin v1.0.0Developers can pin a specific version:
npx skills add acme/coding-conventions@v1.0.0Updating When Conventions Change
Section titled “Updating When Conventions Change”When your team changes a convention, update the skill in the same PR. This keeps the skill and the codebase in sync:
# Update the skill filesvim SKILL.md
# Commit alongside the code changegit add SKILL.md src/lib/errors.tsgit commit -m "refactor: switch error handling to Result type
Updated SKILL.md to reflect the new error handling pattern."Deprecating Old Patterns
Section titled “Deprecating Old Patterns”When a pattern changes, document both the old and new pattern so the AI handles migration correctly:
## Error Handling
Use the `Result` type pattern for all service functions:
```typescripttype Result<T> = { ok: true; data: T } | { ok: false; error: AppError };```
**Deprecated:** The previous pattern used thrown `AppError` exceptions. If youencounter this in existing code, refactor to the Result pattern when modifyingthe file.When This Breaks
Section titled “When This Breaks”Skill installs but the AI ignores certain conventions. The instruction is probably too vague. Ask the AI directly: “What does my skill say about error handling?” If it cannot articulate the rule clearly, rewrite the instruction with a concrete example.
Skill works for one tool but not another. The skills CLI installs to different directories per tool. Verify the files exist in the correct location: .cursor/rules/ for Cursor, .claude/skills/ for Claude Code, .codex/instructions.md for Codex.
Example code in the skill has syntax errors. The AI copies code examples literally. If the example has a typo or references a non-existent import, the AI reproduces the error. Test every code example by pasting it into your project.
Skill is too long and the AI ignores the bottom half. Move the most important conventions to the top of SKILL.md. If the skill exceeds 2,000 words, split it into a focused SKILL.md and supplementary rules/ files.
Team members get different AI behavior despite the same skill. One developer may have personal rules that override the team skill. Check for conflicts between personal configuration (global rules) and project configuration (committed skills).
Marketplace submission is rejected. Ensure your README is complete, the repository is public, the file structure is correct, and the skill provides genuinely useful instructions (not just “write good code”).