Back to Documentation

Skill Format

Structure, frontmatter, and best practices for writing effective skills

Skills are markdown files (SKILL.md) with optional YAML frontmatter. The AI reads these instructions to understand how to work with a technology.

A well-structured skill helps the AI provide better, more accurate assistance. Think of it as writing documentation specifically designed for AI consumption.

Frontmatter

The frontmatter is YAML metadata at the top of your skill file, wrapped in ---:

---
name: Supabase Best Practices
description: Database, auth, and realtime patterns for Supabase
version: 2.1.0
author: supabase
tags: [database, auth, postgres, realtime, backend]
---

Fields

FieldRequiredDescription
nameYesHuman-readable name for the skill
descriptionYesBrief description of what the skill teaches
versionYesSemantic version (e.g., 1.0.0)
authorNoAuthor or organization name
tagsNoArray of keywords for discovery

Recommended Structure

While skills can be structured however you like, this structure has proven effective:

1. Overview

Start with a brief overview of what the technology does and when to use it.

## Overview

Supabase is an open source Firebase alternative providing:
- PostgreSQL database with instant REST and GraphQL APIs
- Authentication with Row Level Security
- Real-time subscriptions
- Edge Functions for serverless compute
- Storage for large files

Use Supabase when you need a full backend with minimal setup.

2. Setup / Getting Started

How to initialize and configure the technology.

## Setup

### Installation
```bash
npm install @supabase/supabase-js
```

### Client Initialization
```typescript
import { createClient } from '@supabase/supabase-js'

const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
```

3. Best Practices

Core patterns and idioms the AI should follow.

## Best Practices

### Always Use TypeScript Types
Generate and use database types for type safety:

```typescript
// Generate types: npx supabase gen types typescript
import { Database } from './database.types'

const supabase = createClient<Database>(url, key)

// Now queries are fully typed
const { data } = await supabase
  .from('users')
  .select('id, email, created_at')
  .single()
// data is typed as { id: string; email: string; created_at: string } | null
```

### Use Row Level Security (RLS)
Never rely on client-side authorization. Always use RLS policies:

```sql
-- Enable RLS
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;

-- Users can only read their own posts
CREATE POLICY "Users can read own posts"
  ON posts FOR SELECT
  USING (auth.uid() = user_id);
```

4. Common Gotchas

Mistakes to avoid and why.

## Common Gotchas

### Don't Expose Service Role Key
The service role key bypasses RLS. Never use it in client code:

```typescript
// BAD - service key in browser
const supabase = createClient(url, process.env.SUPABASE_SERVICE_KEY!)

// GOOD - anon key in browser
const supabase = createClient(url, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!)

// Service key only in server-side code (API routes, server actions)
```

### Handle Auth State Changes
Don't assume auth state is static:

```typescript
// BAD - only checks once
const user = supabase.auth.getUser()

// GOOD - subscribes to changes
supabase.auth.onAuthStateChange((event, session) => {
  if (event === 'SIGNED_OUT') {
    // Handle logout
  }
})
```

5. Security Considerations

Security best practices specific to this technology.

## Security Considerations

### Validate All Inputs
Even with RLS, validate data before insertion:

```typescript
// In an API route or server action
import { z } from 'zod'

const PostSchema = z.object({
  title: z.string().min(1).max(200),
  content: z.string().min(1).max(10000),
})

export async function createPost(input: unknown) {
  const validated = PostSchema.parse(input)

  const { data, error } = await supabase
    .from('posts')
    .insert(validated)
    .select()
    .single()
}
```

Writing Effective Skills

  • Be specific and actionable

    Tell the AI exactly what to do. "Always use RLS" is vague; showing the exact SQL policy syntax is actionable.

  • Include complete, working code examples

    Every code snippet should be copy-pasteable and functional. Include imports, types, and error handling.

  • Explain the "why"

    Don't just show patterns - explain why they're important. This helps the AI make better decisions in novel situations.

  • Show good and bad examples

    Contrast incorrect patterns with correct ones. Label them clearly so the AI knows which to avoid.

  • Keep it focused

    One skill per technology. A React skill shouldn't include generic TypeScript patterns - let users install both if needed.

  • Cover edge cases

    Document error handling, loading states, empty states, and other scenarios the AI might encounter.

  • Use consistent formatting

    Use clear headers, consistent code block languages, and organized sections. This helps both AI and humans parse the content.

Anti-patterns to Avoid

  • Vague instructions

    "Write clean code" or "Follow best practices" without specifics isn't helpful.

  • Incomplete code snippets

    Missing imports, undefined variables, or truncated examples confuse the AI.

  • Outdated information

    Deprecated APIs or old patterns teach the AI bad habits. Keep skills current.

  • Too broad scope

    A skill covering "full-stack development" is too broad. Focus on one technology.

  • No context for when to apply

    Always explain when a pattern applies. The AI needs to know context to make good decisions.

Complete Example

Here's a complete, minimal skill file you can use as a starting template:

---
name: My Technology Skill
description: Best practices for working with My Technology
version: 1.0.0
author: your-username
tags: [my-tech, backend, api]
---

# My Technology Skill

## Overview

My Technology is a tool for [describe what it does]. Use it when you need to [describe use cases].

Key features:
- Feature 1
- Feature 2
- Feature 3

## Setup

### Installation

```bash
npm install my-technology
```

### Basic Configuration

```typescript
import { MyTech } from 'my-technology'

const client = new MyTech({
  apiKey: process.env.MY_TECH_API_KEY!,
})
```

## Best Practices

### Always Do This

Explain why this pattern is important.

```typescript
// Good example with full context
const result = await client.doSomething({
  option: 'value',
})
```

### Use This Pattern For X

Explain when and why.

```typescript
// Complete, working example
```

## Common Gotchas

### Don't Do This

Explain why this is problematic.

```typescript
// BAD - explain the issue
const bad = wrongApproach()

// GOOD - explain the fix
const good = correctApproach()
```

## Security

### Protect Sensitive Data

```typescript
// Never expose API keys
// Use environment variables
// Validate all inputs
```