mirror of
https://github.com/supabase/agent-skills.git
synced 2026-03-27 10:09:26 +08:00
chore: comply with agent skills open stardard (#14)
This commit is contained in:
45
AGENTS.md
45
AGENTS.md
@@ -2,16 +2,18 @@
|
|||||||
|
|
||||||
Guidance for AI coding agents working with this repository.
|
Guidance for AI coding agents working with this repository.
|
||||||
|
|
||||||
|
> **Note:** `CLAUDE.md` is a symlink to this file.
|
||||||
|
|
||||||
## Repository Structure
|
## Repository Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
skills/
|
skills/
|
||||||
{skill-name}/
|
{skill-name}/
|
||||||
metadata.json # Required: skill metadata
|
SKILL.md # Required: skill manifest (Agent Skills spec)
|
||||||
AGENTS.md # Generated: compiled rules
|
AGENTS.md # Generated: compiled references
|
||||||
rules/
|
references/
|
||||||
_sections.md # Required: section definitions
|
_sections.md # Required: section definitions
|
||||||
{prefix}-{name}.md # Rule files
|
{prefix}-{name}.md # Reference files
|
||||||
|
|
||||||
packages/
|
packages/
|
||||||
skills-build/ # Generic build system for all skills
|
skills-build/ # Generic build system for all skills
|
||||||
@@ -31,13 +33,38 @@ npm run check # Format and lint (auto-fix)
|
|||||||
|
|
||||||
## Creating a New Skill
|
## Creating a New Skill
|
||||||
|
|
||||||
1. Create directory: `mkdir -p skills/{name}/rules`
|
Skills follow the [Agent Skills Open Standard](https://agentskills.io/).
|
||||||
2. Add `metadata.json` with version, organization, abstract
|
|
||||||
3. Add `rules/_sections.md` defining sections
|
1. Create directory: `mkdir -p skills/{skill-name}/references`
|
||||||
4. Add rule files: `{prefix}-{rule-name}.md`
|
2. Create `SKILL.md` with required frontmatter:
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
name: skill-name
|
||||||
|
description: What this skill does and when to use it.
|
||||||
|
license: MIT
|
||||||
|
metadata:
|
||||||
|
author: your-org
|
||||||
|
version: "1.0.0"
|
||||||
|
---
|
||||||
|
```
|
||||||
|
3. Add `references/_sections.md` defining sections
|
||||||
|
4. Add reference files: `{prefix}-{reference-name}.md`
|
||||||
5. Run `npm run build`
|
5. Run `npm run build`
|
||||||
|
|
||||||
## Rule File Format
|
## SKILL.md Format (Agent Skills Spec)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
name: skill-name # Required: must match directory name
|
||||||
|
description: Description of skill. # Required: what it does and when to use
|
||||||
|
license: MIT # Optional: license
|
||||||
|
metadata: # Optional: arbitrary key-value pairs
|
||||||
|
author: your-org
|
||||||
|
version: "1.0.0"
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
## Reference File Format
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
Thank you for contributing to Supabase Agent Skills! Here's how to get started:
|
Thank you for contributing to Supabase Agent Skills! Here's how to get started:
|
||||||
|
|
||||||
[1. Getting Started](#getting-started) | [2. Issues](#issues) |
|
[1. Getting Started](#getting-started) | [2. Issues](#issues) |
|
||||||
[3. Pull Requests](#pull-requests) | [4. Contributing New Rules](#contributing-new-rules) |
|
[3. Pull Requests](#pull-requests) | [4. Contributing New References](#contributing-new-references) |
|
||||||
[5. Creating a New Skill](#creating-a-new-skill)
|
[5. Creating a New Skill](#creating-a-new-skill)
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
@@ -14,15 +14,15 @@ before contributing.
|
|||||||
|
|
||||||
## Issues
|
## Issues
|
||||||
|
|
||||||
If you find a typo, have a suggestion for a new skill/rule, or want to improve
|
If you find a typo, have a suggestion for a new skill/reference, or want to improve
|
||||||
existing skills/rules, please create an Issue.
|
existing skills/references, please create an Issue.
|
||||||
|
|
||||||
- Please search
|
- Please search
|
||||||
[existing Issues](https://github.com/supabase/agent-skills/issues) before
|
[existing Issues](https://github.com/supabase/agent-skills/issues) before
|
||||||
creating a new one.
|
creating a new one.
|
||||||
- Please include a clear description of the problem or suggestion.
|
- Please include a clear description of the problem or suggestion.
|
||||||
- Tag your issue appropriately (e.g., `bug`, `question`, `enhancement`,
|
- Tag your issue appropriately (e.g., `bug`, `question`, `enhancement`,
|
||||||
`new-rule`, `new-skill`, `documentation`).
|
`new-reference`, `new-skill`, `documentation`).
|
||||||
|
|
||||||
## Pull Requests
|
## Pull Requests
|
||||||
|
|
||||||
@@ -42,18 +42,18 @@ We actively welcome your Pull Requests! Here's what to keep in mind:
|
|||||||
Before submitting your PR, please run these checks:
|
Before submitting your PR, please run these checks:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run validate # Check rule format and structure
|
npm run validate # Check reference format and structure
|
||||||
npm run build # Generate AGENTS.md from rules
|
npm run build # Generate AGENTS.md from references
|
||||||
```
|
```
|
||||||
|
|
||||||
Both commands must complete successfully.
|
Both commands must complete successfully.
|
||||||
|
|
||||||
## Contributing New Rules
|
## Contributing New References
|
||||||
|
|
||||||
To add a rule to an existing skill:
|
To add a reference to an existing skill:
|
||||||
|
|
||||||
1. Navigate to `skills/{skill-name}/rules/`
|
1. Navigate to `skills/{skill-name}/references/`
|
||||||
2. Copy `_template.md` to `{prefix}-{your-rule-name}.md`
|
2. Copy `_template.md` to `{prefix}-{your-reference-name}.md`
|
||||||
3. Fill in the frontmatter (title, impact, tags)
|
3. Fill in the frontmatter (title, impact, tags)
|
||||||
4. Write explanation and examples (Incorrect/Correct)
|
4. Write explanation and examples (Incorrect/Correct)
|
||||||
5. Run validation and build:
|
5. Run validation and build:
|
||||||
@@ -65,26 +65,39 @@ npm run build
|
|||||||
|
|
||||||
## Creating a New Skill
|
## Creating a New Skill
|
||||||
|
|
||||||
To create an entirely new skill:
|
Skills follow the [Agent Skills Open Standard](https://agentskills.io/).
|
||||||
|
|
||||||
### 1. Create the directory structure
|
### 1. Create the directory structure
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mkdir -p skills/my-skill/rules
|
mkdir -p skills/my-skill/references
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Create metadata.json
|
### 2. Create SKILL.md
|
||||||
|
|
||||||
```json
|
```yaml
|
||||||
{
|
---
|
||||||
"version": "1.0.0",
|
name: my-skill
|
||||||
"organization": "Your Org",
|
description: Brief description of what this skill does and when to use it.
|
||||||
"date": "January 2026",
|
license: MIT
|
||||||
"abstract": "Brief description of this skill."
|
metadata:
|
||||||
}
|
author: your-org
|
||||||
|
version: "1.0.0"
|
||||||
|
organization: Your Org
|
||||||
|
date: January 2026
|
||||||
|
abstract: Detailed description of this skill for the compiled AGENTS.md.
|
||||||
|
---
|
||||||
|
|
||||||
|
# My Skill
|
||||||
|
|
||||||
|
Instructions for agents using this skill.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- https://example.com/docs
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Create rules/_sections.md
|
### 3. Create references/_sections.md
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
## 1. First Category (first)
|
## 1. First Category (first)
|
||||||
@@ -96,11 +109,11 @@ mkdir -p skills/my-skill/rules
|
|||||||
**Description:** What this category covers.
|
**Description:** What this category covers.
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. Create rule files
|
### 4. Create reference files
|
||||||
|
|
||||||
Name files as `{prefix}-{rule-name}.md` where prefix matches a section.
|
Name files as `{prefix}-{reference-name}.md` where prefix matches a section.
|
||||||
|
|
||||||
Example: `first-example-rule.md` for section "First Category"
|
Example: `first-example-reference.md` for section "First Category"
|
||||||
|
|
||||||
### 5. Build
|
### 5. Build
|
||||||
|
|
||||||
@@ -108,7 +121,7 @@ Example: `first-example-rule.md` for section "First Category"
|
|||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
The build system auto-discovers skills. No configuration needed.
|
The build system auto-discovers skills by looking for `SKILL.md` files.
|
||||||
|
|
||||||
## Questions or Feedback?
|
## Questions or Feedback?
|
||||||
|
|
||||||
|
|||||||
13
README.md
13
README.md
@@ -29,9 +29,9 @@ You can also install the skills in this repo as Claude Code plugins
|
|||||||
## Available Skills
|
## Available Skills
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><strong>postgres-best-practices</strong></summary>
|
<summary><strong>supabase-postgres-best-practices</strong></summary>
|
||||||
|
|
||||||
Postgres performance optimization guidelines from Supabase. Contains rules
|
Postgres performance optimization guidelines from Supabase. Contains references
|
||||||
across 8 categories, prioritized by impact.
|
across 8 categories, prioritized by impact.
|
||||||
|
|
||||||
**Use when:**
|
**Use when:**
|
||||||
@@ -76,12 +76,11 @@ Help me add proper indexes to this table
|
|||||||
|
|
||||||
## Skill Structure
|
## Skill Structure
|
||||||
|
|
||||||
Each skill contains:
|
Each skill follows the [Agent Skills Open Standard](https://agentskills.io/):
|
||||||
|
|
||||||
- `SKILL.md` - Instructions for the agent
|
- `SKILL.md` - Required skill manifest with frontmatter (name, description, metadata)
|
||||||
- `AGENTS.md` - Compiled rules document (generated)
|
- `AGENTS.md` - Compiled references document (generated)
|
||||||
- `rules/` - Individual rule files
|
- `references/` - Individual reference files
|
||||||
- `metadata.json` - Version and metadata
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -45,10 +45,117 @@ function parseSections(rulesDir: string): Section[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load metadata from metadata.json
|
* Parse SKILL.md frontmatter to extract metadata
|
||||||
*/
|
*/
|
||||||
function loadMetadata(metadataFile: string, skillName: string): Metadata {
|
function parseSkillFrontmatter(content: string): Record<string, unknown> {
|
||||||
if (!existsSync(metadataFile)) {
|
if (!content.startsWith("---")) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const endIndex = content.indexOf("---", 3);
|
||||||
|
if (endIndex === -1) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const frontmatterContent = content.slice(3, endIndex).trim();
|
||||||
|
const result: Record<string, unknown> = {};
|
||||||
|
let currentKey = "";
|
||||||
|
let inMetadata = false;
|
||||||
|
const metadataObj: Record<string, string> = {};
|
||||||
|
|
||||||
|
for (const line of frontmatterContent.split("\n")) {
|
||||||
|
// Check for metadata block start
|
||||||
|
if (line.trim() === "metadata:") {
|
||||||
|
inMetadata = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle metadata nested values
|
||||||
|
if (inMetadata && line.startsWith(" ")) {
|
||||||
|
const colonIndex = line.indexOf(":");
|
||||||
|
if (colonIndex !== -1) {
|
||||||
|
const key = line.slice(0, colonIndex).trim();
|
||||||
|
let value = line.slice(colonIndex + 1).trim();
|
||||||
|
if (
|
||||||
|
(value.startsWith('"') && value.endsWith('"')) ||
|
||||||
|
(value.startsWith("'") && value.endsWith("'"))
|
||||||
|
) {
|
||||||
|
value = value.slice(1, -1);
|
||||||
|
}
|
||||||
|
metadataObj[key] = value;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// End metadata block when we hit a non-indented line
|
||||||
|
if (inMetadata && !line.startsWith(" ") && line.trim()) {
|
||||||
|
inMetadata = false;
|
||||||
|
result.metadata = metadataObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle top-level key-value
|
||||||
|
const colonIndex = line.indexOf(":");
|
||||||
|
if (colonIndex === -1) continue;
|
||||||
|
|
||||||
|
currentKey = line.slice(0, colonIndex).trim();
|
||||||
|
let value = line.slice(colonIndex + 1).trim();
|
||||||
|
|
||||||
|
if (
|
||||||
|
(value.startsWith('"') && value.endsWith('"')) ||
|
||||||
|
(value.startsWith("'") && value.endsWith("'"))
|
||||||
|
) {
|
||||||
|
value = value.slice(1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
result[currentKey] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure metadata is captured if file ends in metadata block
|
||||||
|
if (inMetadata && Object.keys(metadataObj).length > 0) {
|
||||||
|
result.metadata = metadataObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract references from SKILL.md body
|
||||||
|
*/
|
||||||
|
function extractReferencesFromBody(content: string): string[] {
|
||||||
|
const references: string[] = [];
|
||||||
|
const lines = content.split("\n");
|
||||||
|
let inReferencesSection = false;
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
if (line.match(/^##\s+References/i)) {
|
||||||
|
inReferencesSection = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inReferencesSection) {
|
||||||
|
// Stop at next heading
|
||||||
|
if (line.startsWith("## ")) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match list items with URLs
|
||||||
|
const urlMatch = line.match(/^-\s*(https?:\/\/[^\s]+)/);
|
||||||
|
if (urlMatch) {
|
||||||
|
references.push(urlMatch[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return references;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load metadata from SKILL.md frontmatter (Agent Skills spec compliant)
|
||||||
|
*/
|
||||||
|
function loadMetadata(skillFile: string, skillName: string): Metadata {
|
||||||
|
if (!existsSync(skillFile)) {
|
||||||
return {
|
return {
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
organization: "Supabase",
|
organization: "Supabase",
|
||||||
@@ -61,7 +168,25 @@ function loadMetadata(metadataFile: string, skillName: string): Metadata {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return JSON.parse(readFileSync(metadataFile, "utf-8"));
|
const content = readFileSync(skillFile, "utf-8");
|
||||||
|
const frontmatter = parseSkillFrontmatter(content);
|
||||||
|
const metadata = (frontmatter.metadata as Record<string, string>) || {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
version: metadata.version || "1.0.0",
|
||||||
|
organization: metadata.organization || "Supabase",
|
||||||
|
date:
|
||||||
|
metadata.date ||
|
||||||
|
new Date().toLocaleDateString("en-US", {
|
||||||
|
month: "long",
|
||||||
|
year: "numeric",
|
||||||
|
}),
|
||||||
|
abstract:
|
||||||
|
metadata.abstract ||
|
||||||
|
(frontmatter.description as string) ||
|
||||||
|
`${skillName} guide for developers.`,
|
||||||
|
references: extractReferencesFromBody(content),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -104,14 +229,14 @@ function buildSkill(paths: SkillPaths): void {
|
|||||||
console.log(`[${paths.name}] Building AGENTS.md...`);
|
console.log(`[${paths.name}] Building AGENTS.md...`);
|
||||||
|
|
||||||
// Load metadata and sections
|
// Load metadata and sections
|
||||||
const metadata = loadMetadata(paths.metadataFile, paths.name);
|
const metadata = loadMetadata(paths.skillFile, paths.name);
|
||||||
const sections = parseSections(paths.rulesDir);
|
const sections = parseSections(paths.referencesDir);
|
||||||
const sectionMap = generateSectionMap(sections);
|
const sectionMap = generateSectionMap(sections);
|
||||||
const skillTitle = skillNameToTitle(paths.name);
|
const skillTitle = skillNameToTitle(paths.name);
|
||||||
|
|
||||||
// Check if rules directory exists
|
// Check if references directory exists
|
||||||
if (!existsSync(paths.rulesDir)) {
|
if (!existsSync(paths.referencesDir)) {
|
||||||
console.log(` No rules directory found. Generating empty AGENTS.md.`);
|
console.log(` No references directory found. Generating empty AGENTS.md.`);
|
||||||
writeFileSync(
|
writeFileSync(
|
||||||
paths.agentsOutput,
|
paths.agentsOutput,
|
||||||
`# ${skillTitle}\n\nNo rules defined yet.\n`,
|
`# ${skillTitle}\n\nNo rules defined yet.\n`,
|
||||||
@@ -119,19 +244,19 @@ function buildSkill(paths: SkillPaths): void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all rule files
|
// Get all reference files
|
||||||
const ruleFiles = readdirSync(paths.rulesDir)
|
const referenceFiles = readdirSync(paths.referencesDir)
|
||||||
.filter((f) => f.endsWith(".md") && !f.startsWith("_"))
|
.filter((f) => f.endsWith(".md") && !f.startsWith("_"))
|
||||||
.map((f) => join(paths.rulesDir, f));
|
.map((f) => join(paths.referencesDir, f));
|
||||||
|
|
||||||
if (ruleFiles.length === 0) {
|
if (referenceFiles.length === 0) {
|
||||||
console.log(` No rule files found. Generating empty AGENTS.md.`);
|
console.log(` No reference files found. Generating empty AGENTS.md.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse and validate all rules
|
// Parse and validate all rules
|
||||||
const rules: Rule[] = [];
|
const rules: Rule[] = [];
|
||||||
|
|
||||||
for (const file of ruleFiles) {
|
for (const file of referenceFiles) {
|
||||||
const validation = validateRuleFile(file, sectionMap);
|
const validation = validateRuleFile(file, sectionMap);
|
||||||
if (!validation.valid) {
|
if (!validation.valid) {
|
||||||
console.error(` Skipping invalid file ${basename(file)}:`);
|
console.error(` Skipping invalid file ${basename(file)}:`);
|
||||||
|
|||||||
@@ -15,18 +15,18 @@ export const SKILLS_ROOT = join(BUILD_DIR, "../../skills");
|
|||||||
export interface SkillPaths {
|
export interface SkillPaths {
|
||||||
name: string;
|
name: string;
|
||||||
skillDir: string;
|
skillDir: string;
|
||||||
rulesDir: string;
|
referencesDir: string;
|
||||||
agentsOutput: string;
|
agentsOutput: string;
|
||||||
metadataFile: string;
|
skillFile: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Discover all valid skills (directories with metadata.json)
|
// Discover all valid skills (directories with SKILL.md per Agent Skills spec)
|
||||||
export function discoverSkills(): string[] {
|
export function discoverSkills(): string[] {
|
||||||
if (!existsSync(SKILLS_ROOT)) return [];
|
if (!existsSync(SKILLS_ROOT)) return [];
|
||||||
|
|
||||||
return readdirSync(SKILLS_ROOT, { withFileTypes: true })
|
return readdirSync(SKILLS_ROOT, { withFileTypes: true })
|
||||||
.filter((d) => d.isDirectory())
|
.filter((d) => d.isDirectory())
|
||||||
.filter((d) => existsSync(join(SKILLS_ROOT, d.name, "metadata.json")))
|
.filter((d) => existsSync(join(SKILLS_ROOT, d.name, "SKILL.md")))
|
||||||
.map((d) => d.name);
|
.map((d) => d.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,16 +36,16 @@ export function getSkillPaths(skillName: string): SkillPaths {
|
|||||||
return {
|
return {
|
||||||
name: skillName,
|
name: skillName,
|
||||||
skillDir,
|
skillDir,
|
||||||
rulesDir: join(skillDir, "rules"),
|
referencesDir: join(skillDir, "references"),
|
||||||
agentsOutput: join(skillDir, "AGENTS.md"),
|
agentsOutput: join(skillDir, "AGENTS.md"),
|
||||||
metadataFile: join(skillDir, "metadata.json"),
|
skillFile: join(skillDir, "SKILL.md"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate skill exists
|
// Validate skill exists
|
||||||
export function validateSkillExists(skillName: string): boolean {
|
export function validateSkillExists(skillName: string): boolean {
|
||||||
const paths = getSkillPaths(skillName);
|
const paths = getSkillPaths(skillName);
|
||||||
return existsSync(paths.metadataFile);
|
return existsSync(paths.skillFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Valid impact levels in priority order
|
// Valid impact levels in priority order
|
||||||
|
|||||||
@@ -44,14 +44,14 @@ function isGoodExample(label: string): boolean {
|
|||||||
export function validateRuleFile(
|
export function validateRuleFile(
|
||||||
filePath: string,
|
filePath: string,
|
||||||
sectionMap?: Record<string, number>,
|
sectionMap?: Record<string, number>,
|
||||||
rulesDir?: string,
|
referencesDir?: string,
|
||||||
): ValidationResult {
|
): ValidationResult {
|
||||||
const errors: string[] = [];
|
const errors: string[] = [];
|
||||||
const warnings: string[] = [];
|
const warnings: string[] = [];
|
||||||
|
|
||||||
// Generate section map if not provided
|
// Generate section map if not provided
|
||||||
if (!sectionMap && rulesDir) {
|
if (!sectionMap && referencesDir) {
|
||||||
const sections = parseSections(rulesDir);
|
const sections = parseSections(referencesDir);
|
||||||
sectionMap = generateSectionMap(sections);
|
sectionMap = generateSectionMap(sections);
|
||||||
} else if (!sectionMap) {
|
} else if (!sectionMap) {
|
||||||
sectionMap = {};
|
sectionMap = {};
|
||||||
@@ -138,25 +138,25 @@ export function validateRuleFile(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate all rule files for a skill
|
* Validate all reference files for a skill
|
||||||
*/
|
*/
|
||||||
function validateSkill(paths: SkillPaths): boolean {
|
function validateSkill(paths: SkillPaths): boolean {
|
||||||
console.log(`[${paths.name}] Validating...`);
|
console.log(`[${paths.name}] Validating...`);
|
||||||
|
|
||||||
// Check if rules directory exists
|
// Check if references directory exists
|
||||||
if (!existsSync(paths.rulesDir)) {
|
if (!existsSync(paths.referencesDir)) {
|
||||||
console.log(` No rules directory found.`);
|
console.log(` No references directory found.`);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get section map
|
// Get section map
|
||||||
const sections = parseSections(paths.rulesDir);
|
const sections = parseSections(paths.referencesDir);
|
||||||
const sectionMap = generateSectionMap(sections);
|
const sectionMap = generateSectionMap(sections);
|
||||||
|
|
||||||
// Get all markdown files (excluding _ prefixed files)
|
// Get all markdown files (excluding _ prefixed files)
|
||||||
const files = readdirSync(paths.rulesDir)
|
const files = readdirSync(paths.referencesDir)
|
||||||
.filter((f) => f.endsWith(".md") && !f.startsWith("_"))
|
.filter((f) => f.endsWith(".md") && !f.startsWith("_"))
|
||||||
.map((f) => join(paths.rulesDir, f));
|
.map((f) => join(paths.referencesDir, f));
|
||||||
|
|
||||||
if (files.length === 0) {
|
if (files.length === 0) {
|
||||||
console.log(` No rule files found.`);
|
console.log(` No rule files found.`);
|
||||||
@@ -168,7 +168,7 @@ function validateSkill(paths: SkillPaths): boolean {
|
|||||||
let hasErrors = false;
|
let hasErrors = false;
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const result = validateRuleFile(file, sectionMap, paths.rulesDir);
|
const result = validateRuleFile(file, sectionMap, paths.referencesDir);
|
||||||
const filename = basename(file);
|
const filename = basename(file);
|
||||||
|
|
||||||
if (result.valid) {
|
if (result.valid) {
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"version": "1.0.0",
|
|
||||||
"organization": "Supabase",
|
|
||||||
"date": "January 2026",
|
|
||||||
"abstract": "Comprehensive Postgres performance optimization guide for developers using Supabase and Postgres. Contains performance rules across 8 categories, prioritized by impact from critical (query performance, connection management) to incremental (advanced features). Each rule includes detailed explanations, incorrect vs. correct SQL examples, query plan analysis, and specific performance metrics to guide automated optimization and code generation.",
|
|
||||||
"references": [
|
|
||||||
"https://www.postgresql.org/docs/current/",
|
|
||||||
"https://supabase.com/docs",
|
|
||||||
"https://wiki.postgresql.org/wiki/Performance_Optimization",
|
|
||||||
"https://supabase.com/docs/guides/database/overview",
|
|
||||||
"https://supabase.com/docs/guides/auth/row-level-security"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# Postgres Best Practices
|
# Supabase Postgres Best Practices
|
||||||
|
|
||||||
**Version 1.0.0**
|
**Version 1.1.0**
|
||||||
Supabase
|
Supabase
|
||||||
January 2026
|
January 2026
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# Postgres Best Practices - Contributor Guide
|
# Supabase Postgres Best Practices - Contributor Guide
|
||||||
|
|
||||||
This repository contains Postgres performance optimization rules optimized for
|
This skill contains Postgres performance optimization references optimized for
|
||||||
AI agents and LLMs.
|
AI agents and LLMs. It follows the [Agent Skills Open Standard](https://agentskills.io/).
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
@@ -9,14 +9,14 @@ AI agents and LLMs.
|
|||||||
# From repository root
|
# From repository root
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
# Validate existing rules
|
# Validate existing references
|
||||||
npm run validate
|
npm run validate
|
||||||
|
|
||||||
# Build AGENTS.md
|
# Build AGENTS.md
|
||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
## Creating a New Rule
|
## Creating a New Reference
|
||||||
|
|
||||||
1. **Choose a section prefix** based on the category:
|
1. **Choose a section prefix** based on the category:
|
||||||
- `query-` Query Performance (CRITICAL)
|
- `query-` Query Performance (CRITICAL)
|
||||||
@@ -30,7 +30,7 @@ npm run build
|
|||||||
|
|
||||||
2. **Copy the template**:
|
2. **Copy the template**:
|
||||||
```bash
|
```bash
|
||||||
cp rules/_template.md rules/query-your-rule-name.md
|
cp references/_template.md references/query-your-reference-name.md
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Fill in the content** following the template structure
|
3. **Fill in the content** following the template structure
|
||||||
@@ -43,29 +43,27 @@ npm run build
|
|||||||
|
|
||||||
5. **Review** the generated `AGENTS.md`
|
5. **Review** the generated `AGENTS.md`
|
||||||
|
|
||||||
## Repository Structure
|
## Skill Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
skills/postgres-best-practices/
|
skills/supabase-postgres-best-practices/
|
||||||
├── SKILL.md # Agent-facing skill manifest
|
├── SKILL.md # Agent-facing skill manifest (Agent Skills spec)
|
||||||
├── AGENTS.md # [GENERATED] Compiled rules document
|
├── AGENTS.md # [GENERATED] Compiled references document
|
||||||
├── README.md # This file
|
├── README.md # This file
|
||||||
├── metadata.json # Version and metadata
|
└── references/
|
||||||
└── rules/
|
├── _template.md # Reference template
|
||||||
├── _template.md # Rule template
|
|
||||||
├── _sections.md # Section definitions
|
├── _sections.md # Section definitions
|
||||||
├── _contributing.md # Writing guidelines
|
├── _contributing.md # Writing guidelines
|
||||||
└── *.md # Individual rules
|
└── *.md # Individual references
|
||||||
|
|
||||||
packages/skills-build/
|
packages/skills-build/
|
||||||
├── src/ # Generic build system source
|
├── src/ # Generic build system source
|
||||||
├── package.json # NPM scripts
|
└── package.json # NPM scripts
|
||||||
└── test-cases.json # [GENERATED] Test artifacts
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Rule File Structure
|
## Reference File Structure
|
||||||
|
|
||||||
See `rules/_template.md` for the complete template. Key elements:
|
See `references/_template.md` for the complete template. Key elements:
|
||||||
|
|
||||||
````markdown
|
````markdown
|
||||||
---
|
---
|
||||||
@@ -97,7 +95,7 @@ tags: relevant, keywords
|
|||||||
```
|
```
|
||||||
## Writing Guidelines
|
## Writing Guidelines
|
||||||
|
|
||||||
See `rules/_contributing.md` for detailed guidelines. Key principles:
|
See `references/_contributing.md` for detailed guidelines. Key principles:
|
||||||
|
|
||||||
1. **Show concrete transformations** - "Change X to Y", not abstract advice
|
1. **Show concrete transformations** - "Change X to Y", not abstract advice
|
||||||
2. **Error-first structure** - Show the problem before the solution
|
2. **Error-first structure** - Show the problem before the solution
|
||||||
@@ -4,7 +4,10 @@ description: Postgres performance optimization and best practices from Supabase.
|
|||||||
license: MIT
|
license: MIT
|
||||||
metadata:
|
metadata:
|
||||||
author: supabase
|
author: supabase
|
||||||
version: "1.0.0"
|
version: "1.1.0"
|
||||||
|
organization: Supabase
|
||||||
|
date: January 2026
|
||||||
|
abstract: Comprehensive Postgres performance optimization guide for developers using Supabase and Postgres. Contains performance rules across 8 categories, prioritized by impact from critical (query performance, connection management) to incremental (advanced features). Each rule includes detailed explanations, incorrect vs. correct SQL examples, query plan analysis, and specific performance metrics to guide automated optimization and code generation.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Supabase Postgres Best Practices
|
# Supabase Postgres Best Practices
|
||||||
@@ -39,9 +42,9 @@ Reference these guidelines when:
|
|||||||
Read individual rule files for detailed explanations and SQL examples:
|
Read individual rule files for detailed explanations and SQL examples:
|
||||||
|
|
||||||
```
|
```
|
||||||
rules/query-missing-indexes.md
|
references/query-missing-indexes.md
|
||||||
rules/schema-partial-indexes.md
|
references/schema-partial-indexes.md
|
||||||
rules/_sections.md
|
references/_sections.md
|
||||||
```
|
```
|
||||||
|
|
||||||
Each rule file contains:
|
Each rule file contains:
|
||||||
@@ -55,3 +58,11 @@ Each rule file contains:
|
|||||||
## Full Compiled Document
|
## Full Compiled Document
|
||||||
|
|
||||||
For the complete guide with all rules expanded: `AGENTS.md`
|
For the complete guide with all rules expanded: `AGENTS.md`
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- https://www.postgresql.org/docs/current/
|
||||||
|
- https://supabase.com/docs
|
||||||
|
- https://wiki.postgresql.org/wiki/Performance_Optimization
|
||||||
|
- https://supabase.com/docs/guides/database/overview
|
||||||
|
- https://supabase.com/docs/guides/auth/row-level-security
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# Writing Guidelines for Postgres Rules
|
# Writing Guidelines for Postgres References
|
||||||
|
|
||||||
This document provides guidelines for creating effective Postgres best
|
This document provides guidelines for creating effective Postgres best
|
||||||
practice rules that work well with AI agents and LLMs.
|
practice references that work well with AI agents and LLMs.
|
||||||
|
|
||||||
## Key Principles
|
## Key Principles
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ CREATE INDEX CONCURRENTLY USERS_EMAIL_IDX ON USERS(EMAIL) WHERE DELETED_AT IS NU
|
|||||||
|
|
||||||
**Default: SQL Only**
|
**Default: SQL Only**
|
||||||
|
|
||||||
Most rules should focus on pure SQL patterns. This keeps examples portable.
|
Most references should focus on pure SQL patterns. This keeps examples portable.
|
||||||
|
|
||||||
**Include Application Code When:**
|
**Include Application Code When:**
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ Reference:
|
|||||||
|
|
||||||
## Review Checklist
|
## Review Checklist
|
||||||
|
|
||||||
Before submitting a rule:
|
Before submitting a reference:
|
||||||
|
|
||||||
- [ ] Title is clear and action-oriented
|
- [ ] Title is clear and action-oriented
|
||||||
- [ ] Impact level matches the performance gain
|
- [ ] Impact level matches the performance gain
|
||||||
35
skills/using-supabase/references/_sections.md
Normal file
35
skills/using-supabase/references/_sections.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Reference Sections
|
||||||
|
|
||||||
|
Defines the organization of reference documentation. Each section groups related content.
|
||||||
|
|
||||||
|
## 1. Getting Started (getting-started)
|
||||||
|
|
||||||
|
**Description:** Project setup, connection strings, initial configuration, and first steps with Supabase.
|
||||||
|
|
||||||
|
## 2. Auth (auth)
|
||||||
|
|
||||||
|
**Description:** Authentication, authorization, Row Level Security, social login, and session management.
|
||||||
|
|
||||||
|
## 3. Database (database)
|
||||||
|
|
||||||
|
**Description:** Postgres database, migrations, queries, RLS policies, and data modeling.
|
||||||
|
|
||||||
|
## 4. Storage (storage)
|
||||||
|
|
||||||
|
**Description:** File uploads, buckets, access control, and media handling.
|
||||||
|
|
||||||
|
## 5. Edge Functions (functions)
|
||||||
|
|
||||||
|
**Description:** Serverless functions, Deno runtime, webhooks, and background tasks.
|
||||||
|
|
||||||
|
## 6. Realtime (realtime)
|
||||||
|
|
||||||
|
**Description:** Real-time subscriptions, presence, broadcast, and live updates.
|
||||||
|
|
||||||
|
## 7. Client Libraries (client)
|
||||||
|
|
||||||
|
**Description:** supabase-js SDK, client configuration, and framework integrations.
|
||||||
|
|
||||||
|
## 8. CLI & Tools (cli)
|
||||||
|
|
||||||
|
**Description:** Supabase CLI, local development, migrations, CI/CD, and MCP integration.
|
||||||
Reference in New Issue
Block a user