Every AI coding tool has its own config format. Claude uses CLAUDE.md. Cursor uses .cursor/rules/. Copilot uses .github/copilot-instructions.md. Codex uses AGENTS.md. Windsurf, Cline, Zed — all different.
Skillr gives you one canonical format (.skillr/) and compiles it to all of them. No Docker, no database, no web browser. Just a CLI.
.skillr/skills/
├── code-review.md
├── testing-strategy.md
└── api-standards.md
│
▼ skillr sync
┌─────┼─────┬─────┬─────┬─────┐
▼ ▼ ▼ ▼ ▼ ▼
CLAUDE .cursor copilot .windsurf .clinerules AGENTS
.md /rules .md /rules .md
npm install -g @eooo/skillrOr use directly with npx:
npx @eooo/skillr <command>skillr init
skillr add "Code Review Standards"
# edit .skillr/skills/code-review-standards.md
skillr syncThat's it. Here's what just happened:
Your skill (.skillr/skills/code-review-standards.md):
---
id: code-review-standards
name: Code Review Standards
description: Enforce team code review conventions
tags: [code-quality]
---
All public functions must have JSDoc.
Prefer composition over inheritance.
No `any` types in TypeScript.Generated output after skillr sync:
.claude/CLAUDE.md:
## Code Review Standards
All public functions must have JSDoc.
Prefer composition over inheritance.
No `any` types in TypeScript.
---.cursor/rules/code-review-standards.mdc:
---
description: Enforce team code review conventions
alwaysApply: true
tags:
- code-quality
---
All public functions must have JSDoc.
Prefer composition over inheritance.
No `any` types in TypeScript..github/copilot-instructions.md:
## Code Review Standards
All public functions must have JSDoc.
Prefer composition over inheritance.
No `any` types in TypeScript.
---Same instructions, every tool's native format, from one source file.
Import them from existing provider configs:
skillr import
# Detected 3 skills in .claude/CLAUDE.md
# Detected 2 skills in .cursor/rules/
# Imported 5 skills → .skillr/skills/| Command | Description |
|---|---|
skillr init |
Initialize .skillr/ in the current directory |
skillr add <name> |
Create a new skill from a template |
skillr sync |
Compile skills to all enabled provider configs |
skillr diff |
Preview what sync would change |
skillr lint [slug] |
Run prompt quality checks (11 rules) |
skillr import |
Import skills from existing provider configs |
skillr test <slug> |
Test a skill against an LLM (Anthropic or OpenAI) |
skillr init --name "My Project" --providers claude,cursor
skillr sync --provider claude # sync one provider only
skillr sync --dry-run # preview without writing
skillr lint --json # machine-readable output
skillr test my-skill --model gpt-4o # override the skill's model| Provider | Output | Format |
|---|---|---|
| Claude | .claude/CLAUDE.md |
All skills under H2 headings |
| Cursor | .cursor/rules/{slug}.mdc |
One MDC file per skill |
| GitHub Copilot | .github/copilot-instructions.md |
All skills concatenated |
| Windsurf | .windsurf/rules/{slug}.md |
One file per skill |
| Cline | .clinerules |
Single flat file |
| OpenAI Codex (CLI / macOS / IDE) | AGENTS.md |
All skills concatenated at project root |
| OpenAI (deprecated, removed in v1.2.0) | .openai/instructions.md |
Use codex instead |
| Zed | .rules |
Single flat file |
| Aider | CONVENTIONS.md + .aider.conf.yml |
Aggregated conventions referenced by config |
| Continue | .continue/rules/{slug}.md |
One file per skill |
| JetBrains AI (Junie) | .junie/guidelines.md |
Single flat file |
A skill is a Markdown file with YAML frontmatter:
---
id: code-review
name: Code Review Standards
description: Enforce team code review conventions
tags: [code-quality, review]
includes: [base-instructions]
template_variables:
- name: language
default: TypeScript
---
You are a senior code reviewer. All code must be written in {{language}}.
## Rules
- No `any` types
- All public functions must have JSDoc
- Prefer composition over inheritance
## Output Format
Return a structured review with severity levels: critical, warning, suggestion.Required fields: id, name. Everything else is optional.
Skills can include other skills via includes. Resolved recursively at sync time with circular dependency detection (max depth 5):
includes: [base-instructions, typescript-conventions]{{variable}} placeholders with defaults, resolved per-project at sync time:
template_variables:
- name: language
default: TypeScript11 built-in quality rules catch vague instructions, weak constraints, conflicting directives, missing output formats, role confusion, and more:
skillr lint # lint all skills
skillr lint code-review # lint one skillSimple skills are flat Markdown files. Complex skills use folder format:
.skillr/skills/api-standards/
├── skill.md # main skill file
├── gotchas.md # common pitfalls
└── examples/
└── response.json # supplementary files
| Field | Type | Description |
|---|---|---|
id |
string |
Required. Unique identifier (kebab-case) |
name |
string |
Required. Display name |
description |
string |
When this skill applies |
category |
string |
One of 10 predefined categories |
skill_type |
string |
capability-uplift or encoded-preference |
model |
string |
Target model (e.g., claude-sonnet-4-6) |
max_tokens |
number |
Max output tokens |
tags |
string[] |
Organizational tags |
tools |
object[] |
Tool/function definitions |
includes |
string[] |
Skill slugs to compose with |
template_variables |
object[] |
{{variable}} definitions with defaults |
gotchas |
string |
Common pitfalls and edge cases |
conditions |
object |
file_patterns and path_prefixes for conditional application |
cd cli
npm install
npm run build # compile TypeScript
npm run dev -- init # run commands during development
npm test # run tests (109 tests, vitest)This repo also contains a web-based dashboard for teams that want a GUI. It's a separate application built on Laravel + React — see docs/guide/getting-started.md for setup instructions.
The CLI does not depend on the web dashboard. They share the same .skillr/ format.
Contributions are welcome. See CONTRIBUTING.md for setup instructions and guidelines.
If you discover a security vulnerability, please see SECURITY.md for responsible disclosure instructions. Do not open a public issue.
