The open-source skill registry for AI coding agents.
Create, manage, and distribute SKILL.md files, or connect any agent directly via MCP.
Quick Start · MCP Server · Features · CLI · API · Self-Hosting · Roadmap · Contributing
AI coding agents like Claude Code, Cursor, and Codex use SKILL.md files to learn new capabilities. But managing these files is painful:
- They live scattered across
~/.claude/skills/,.cursor/skills/,.codex/skills/ - No versioning, no search, no way to share across projects or teams
- Writing them from scratch means guessing what works
SkillNote fixes this. It's a self-hosted registry with a clean web UI, a CLI for one-command installs, and an MCP server that lets any agent connect directly with no file installation needed.
Why self-hosted? Enterprise workflows, proprietary codebases, and compliance-sensitive prompts contain institutional knowledge that shouldn't leave your infrastructure. SkillNote runs entirely on your machines. Your skills stay private, versioned, and accessible only to your team.
Make sure you have Docker and Docker Compose v2+ installed.
git clone https://github.com/luna-prompts/skillnote.git
cd skillnote
docker compose up --build -dFour containers spin up:
| Service | URL | What it does |
|---|---|---|
| Web | http://localhost:3000 | Next.js frontend |
| API | http://localhost:8082 | FastAPI backend (auto-migrates + seeds) |
| MCP | http://localhost:8083/mcp | MCP server, skills as tools |
| DB | localhost:5432 | PostgreSQL 16 |
Open http://localhost:3000 and start creating skills.
The backend auto-runs migrations and seeds a default skill (
skill-creator) on first boot. No manual setup needed.
Most people building AI agents hear about both and assume they're the same thing. They're not. Understanding the difference is what makes SkillNote click.
A Skill is a reusable piece of knowledge injected into an agent's context: instructions, workflows, rules, examples. Think of it as a dynamic system prompt loaded on demand:
User message
↓
Agent picks the right Skill
↓
Injects SKILL.md content into the prompt
↓
LLM responds with that context
Skills improve reasoning. They teach the agent how to do something.
Model Context Protocol is a standard for delivering context to agents: tools, APIs, documents, prompts. It improves connectivity. It doesn't care what the content is; it's the pipe.
Skills = HTML (the content)
MCP = HTTP (the transport)
HTTP delivers HTML. But HTML isn't part of HTTP. Same relationship.
Version 1: local files:
Agent reads skills/making-tea/SKILL.md from disk
Simple. Works offline. But skills go stale, drift across machines, and require manual installs.
Version 2: MCP delivery (what SkillNote does):
Agent → MCP → SkillNote → Skills DB
Every skill is exposed as an MCP tool. The agent discovers and calls them live: no files, no installs, always up to date. Update a skill in the Web UI and every connected agent gets the new version instantly.
No restart required. The MCP server queries the database on every
tools/listrequest. There is no in-memory cache. Create or update a skill and it is available to all connected agents on their very next call, with zero downtime.
┌──────────┐ tools/list ┌───────────────┐
│ Agent │ ─────────────────▶ │ SkillNote │
│ │ ◀───────────────── │ MCP Server │
│ │ [all your skills] │ │
│ │ │ reads from │
│ │ tools/call │ PostgreSQL │
│ │ ─────────────────▶ │ on every │
│ │ ◀───────────────── │ request │
└──────────┘ skill content └───────────────┘
| Local Skills | MCP Skills (SkillNote) | |
|---|---|---|
| Updates | Manual (git pull / npx install) |
Automatic: edit in UI, live instantly |
| Fragmentation | Different versions per machine | One source of truth |
| Discovery | Agent must know the file path | Agent discovers via tools/list |
| Sharing | Send files or links | Connect to the same server |
| Offline | Yes | Needs network |
SkillNote exposes every skill as an MCP tool your agent can discover and call directly: no local files needed, no restart when skills change.
Every skill = one MCP tool. The tool name is the skill slug, the description is what the agent reads to decide when to invoke it, and calling the tool returns the full
SKILL.mdcontent. Filter by collection to control which skills (tools) each agent sees.
How it works:
- Each skill becomes a tool:
name = slug,description = skill description - The agent uses the description to decide when to invoke the skill
- Calling the tool returns the full
SKILL.mdcontent - Skills added or removed in SkillNote are reflected immediately
Claude Code
claude mcp add --transport http skillnote http://localhost:8083/mcp --scope userRestart Claude Code, then run /mcp to confirm skillnote is listed.
OpenClaw
openclaw mcp add --transport http skillnote http://localhost:8083/mcp --scope userOr add to ~/.openclaw/settings.json:
{
"mcpServers": {
"skillnote": {
"type": "http",
"url": "http://localhost:8083/mcp"
}
}
}OpenHands
In the OpenHands settings, add a new MCP server under MCP Servers:
{
"mcpServers": {
"skillnote": {
"type": "http",
"url": "http://localhost:8083/mcp"
}
}
}Codex (OpenAI)
Add to your codex.json config:
{
"mcpServers": {
"skillnote": {
"type": "http",
"url": "http://localhost:8083/mcp"
}
}
}Antigravity
Add to your Antigravity MCP config:
{
"mcpServers": {
"skillnote": {
"type": "http",
"url": "http://localhost:8083/mcp"
}
}
}Cursor
Add to ~/.cursor/mcp.json or via Settings → MCP:
{
"mcpServers": {
"skillnote": {
"type": "http",
"url": "http://localhost:8083/mcp"
}
}
}Any other MCP-compatible agent
Any agent that supports the MCP HTTP transport can connect:
http://localhost:8083/mcp
Use environment variables to serve only a subset of skills to a specific agent:
SKILLNOTE_MCP_FILTER_COLLECTIONS=devops,security docker compose up -d mcpThis is useful for scoping what different teams or agents can see.
The MCP Integrations page (sidebar → Connect → MCP Integrations) gives you ready-to-copy config snippets for every supported agent, a scope selector to generate collection-filtered URLs, and a live connection monitor that shows every connected agent — its name, version, IP, call count, and session duration — updating every 5 seconds.
A Notion-style WYSIWYG editor powered by Tiptap. Write in rich text or switch to raw markdown. Paste a raw SKILL.md file and it auto-extracts the name, description, and body from the frontmatter.
Every save creates a snapshot. Browse the full history, compare versions, and restore any previous state with one click. Published versions use semantic versioning (1.0.0, 1.1.0, ...) and are distributed as checksummed ZIP bundles.
Organise skills into collections. Filter, search, and browse by category. Add or remove skills from any collection with inline confirmation.
Install skills as local files to any AI coding agent from the web UI or CLI. Supported agents:
| Agent | Install Path |
|---|---|
| Claude Code | ~/.claude/skills/<skill>/SKILL.md |
| Cursor | .cursor/skills/<skill>/SKILL.md |
| Codex | .codex/skills/<skill>/SKILL.md |
| OpenClaw | ~/.openclaw/skills/<skill>/SKILL.md |
| OpenHands | ~/.openhands/skills/<skill>/SKILL.md |
| Windsurf | .windsurf/skills/<skill>/SKILL.md |
| Universal | .skills/<skill>/SKILL.md |
The frontend works without a backend. Skills are stored in localStorage and sync to PostgreSQL when the API is available. No data loss if the backend goes down.
| Shortcut | Action |
|---|---|
N |
New Skill |
Cmd/Ctrl + K |
Focus search |
Cmd/Ctrl + S |
Save (in editor) |
Escape |
Close / Go back |
Every skill is a Markdown file with YAML frontmatter:
---
name: pdf-extractor
description: Extract text and tables from PDF files. Use when the user mentions PDFs, scanned documents, or form extraction.
---
# PDF Extractor
When the user provides a PDF file:
1. Use `pdftotext` to extract raw text
2. Identify tables and format them as markdown
3. Preserve headings and document structure| Field | Rule |
|---|---|
name |
Required. Lowercase a-z, 0-9, - only. Max 64 chars. No reserved words (anthropic, claude). |
description |
Required. Max 1024 chars. Should explain what it does and when to trigger it. |
Tip: Be aggressive in descriptions. Agents tend to under-trigger skills. Include specific phrases the user might say.
SkillNote includes a CLI for installing and managing skills from the terminal, no browser needed.
cd cli
npm install && npm run build
npm linkskillnote login --host http://localhost:8082 --token skn_dev_demo_tokenskillnote list # List all skills in the registry
skillnote add pdf-extractor # Install a skill (auto-detects agent)
skillnote add pdf-extractor --agent claude # Install for a specific agent
skillnote add --all # Install everything
skillnote check # Check for updates
skillnote update --all # Update all installed skills
skillnote remove pdf-extractor # Uninstall a skill
skillnote doctor # Diagnose setup issuesSkillNote is lightweight. Here's what it uses on a typical machine at idle:
| Container | Image size | RAM (idle) | RAM (under load) |
|---|---|---|---|
| Web | ~302 MB | ~37 MB | ~60 MB |
| API | ~456 MB | ~71 MB | ~120 MB |
| MCP | ~456 MB | ~104 MB | ~160 MB |
| Postgres | ~663 MB | ~38 MB | ~80 MB |
| Total | ~1.9 GB | ~250 MB | ~420 MB |
The API and MCP images share base layers — the combined pull is ~600 MB, not 912 MB.
Minimum recommended specs:
- CPU: 1 core (2+ recommended for MCP-heavy workloads)
- RAM: 512 MB free
- Disk: 2 GB for images + space for skill bundles (5 MB each by default)
Disk usage over time:
- Each published skill version creates a ZIP bundle (≤ 5 MB by default)
- PostgreSQL data grows slowly — a typical install with 100 skills is < 10 MB
- Logs are written to stdout (captured by Docker); no files accumulate on disk
To check live resource usage at any time:
docker statsgit clone https://github.com/luna-prompts/skillnote.git
cd skillnote
docker compose up --build -dSKILLNOTE_HOST=192.168.1.100 SKILLNOTE_API_PORT=9000 docker compose up --build -ddocker compose down # Stop (keeps data)
docker compose down -v # Stop + wipe databaseRun the backend in Docker, frontend with hot-reload:
# Terminal 1: Backend + MCP
docker compose up --build -d postgres api mcp
curl http://localhost:8082/health # Wait for {"status":"ok"}
# Terminal 2: Frontend
npm install
npm run dev # http://localhost:3000| Variable | Default | Description |
|---|---|---|
SKILLNOTE_HOST |
localhost |
Host IP or domain (CORS + frontend URL) |
SKILLNOTE_API_PORT |
8082 |
Host port for the API |
SKILLNOTE_MCP_PORT |
8083 |
Host port for the MCP server |
SKILLNOTE_DATABASE_URL |
(set in compose) | PostgreSQL connection string |
SKILLNOTE_BUNDLE_STORAGE_DIR |
/app/data/bundles |
Where versioned ZIP bundles are stored |
SKILLNOTE_MAX_BUNDLE_SIZE_BYTES |
5242880 |
Max bundle upload size (5 MB) |
SKILLNOTE_CORS_ORIGINS |
(auto from host) | Comma-separated CORS origins |
NEXT_PUBLIC_API_BASE_URL |
http://localhost:8082 |
Frontend API endpoint |
SKILLNOTE_MCP_FILTER_COLLECTIONS |
(all) | Comma-separated collections to expose via MCP |
All endpoints except /health require Authorization: Bearer <token>.
curl http://localhost:8082/v1/skills \
-H "Authorization: Bearer skn_dev_demo_token"| Method | Endpoint | Description |
|---|---|---|
GET |
/v1/skills |
List all skills |
POST |
/v1/skills |
Create a skill |
GET |
/v1/skills/{slug} |
Get skill details |
PATCH |
/v1/skills/{slug} |
Update a skill |
DELETE |
/v1/skills/{slug} |
Delete a skill |
| Method | Endpoint | Description |
|---|---|---|
GET |
/v1/skills/{slug}/content-versions |
List content snapshots |
POST |
/v1/skills/{slug}/content-versions/{version}/set-latest |
Set version as latest |
POST |
/v1/skills/{slug}/content-versions/{version}/restore |
Restore a version |
GET |
/v1/skills/{slug}/versions |
List published versions |
POST |
/v1/publish |
Publish a bundle |
GET |
/v1/skills/{slug}/{version}/download |
Download a bundle |
| Method | Endpoint | Description |
|---|---|---|
GET |
/health |
Health check |
POST |
/auth/validate-token |
Validate a token |
| Layer | Technology |
|---|---|
| Frontend | Next.js 16, React 19, TypeScript, Tailwind CSS 4, Tiptap |
| Backend | Python 3.12, FastAPI, SQLAlchemy 2, Alembic, Pydantic 2 |
| MCP Server | Python 3.12, FastMCP |
| Database | PostgreSQL 16 |
| CLI | Node.js, TypeScript, Commander.js |
| Infra | Docker, Docker Compose |
skillnote/
├── src/ # Next.js frontend
│ ├── app/(app)/ # App Router pages
│ │ ├── page.tsx # Home: skill list + search
│ │ ├── skills/new/ # Create skill (full-page editor)
│ │ ├── skills/[slug]/ # Skill detail + edit
│ │ ├── collections/ # Browse by collection
│ │ └── settings/ # Settings
│ ├── components/ # UI components
│ │ ├── skills/ # Editor, detail view, install strip
│ │ ├── layout/ # Sidebar, topbar
│ │ └── ui/ # Primitives (Shadcn)
│ └── lib/ # State, API client, validation
│
├── backend/ # FastAPI backend + MCP server
│ ├── app/api/ # Route handlers
│ ├── app/db/models/ # SQLAlchemy models
│ ├── app/schemas/ # Pydantic schemas
│ ├── app/validators/ # SKILL.md spec validators
│ ├── alembic/ # Database migrations
│ ├── scripts/ # Seed data, health checks
│ ├── mcp_server.py # MCP server (FastMCP, port 8083)
│ └── Dockerfile.mcp # MCP container
│
├── cli/ # CLI tool
│ └── src/
│ ├── commands/ # login, list, add, update, remove, doctor
│ └── agents/ # Agent detection + install paths
│
├── docker-compose.yml # Full stack orchestration
├── Dockerfile # Frontend multi-stage build
└── start.sh # One-command startup
Containers won't start
docker compose logs api # Check API logs
docker compose logs mcp # Check MCP logs
docker compose logs postgres # Check DB logsMCP server not showing up in agent
Verify the MCP server is running:
curl -s -X POST http://localhost:8083/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1"}}}'You should see "name":"SkillNote" in the response. Then restart your agent.
API returns 401 / 403
Make sure the backend has been seeded:
docker compose exec -T api python scripts/seed_data.pyUse token skn_dev_demo_token for development.
Port already in use
SKILLNOTE_API_PORT=9000 SKILLNOTE_MCP_PORT=9001 docker compose up --build -dReset everything
docker compose down -v
docker compose up --build -d- Claude Code Skills - Anthropic's official skills documentation
- Model Context Protocol - MCP specification
- AgentSkills.io - The skills ecosystem
- Codex Skills - OpenAI Codex skills reference
- Antigravity Skills - Google Antigravity skills documentation
- OpenHands Skills - OpenHands skills overview
- Skill editor with live preview and SKILL.md validation
- Version history with restore
- Collections
- REST API (CRUD, versioning, publish pipeline)
- MCP server: expose all skills as tools for any AI agent
- One-command Docker Compose stack (postgres + api + mcp + web)
- CLI skill installer (
npx skillnote) - Multi-agent connect guide (Claude Code, OpenClaw, Cursor, Windsurf)
- Redis caching: cache skill listings and content in Redis to cut MCP
tools/listand tool-call latency; skills invalidated on create/update/delete - Collection-scoped MCP mounts: mount a single collection as an MCP server so agents only see relevant skills
- Skill search and semantic ranking: full-text and embedding-based search in the Web UI and via MCP
- Skill dependencies: declare that one skill requires another; agents resolve the full tree automatically
- Webhook on skill publish: notify CI or agent pipelines when a new skill version is published
- Role-based access control: read-only vs editor vs admin roles with API tokens
- Import from GitHub: sync a skills repo directly into SkillNote via URL
If you find SkillNote useful, please consider giving it a star on GitHub. It helps others discover the project and motivates us to keep improving it.
Contributions are welcome! Here's how:
- Fork the repository
- Create a feature branch (
git checkout -b feat/my-feature) - Commit your changes (
git commit -m 'feat: add my feature') - Push to the branch (
git push origin feat/my-feature) - Open a Pull Request
Please follow Conventional Commits for commit messages.
Join us on Discord to discuss ideas, get help, or just hang out.
MIT © Luna Prompts
Made with ❤️ by Luna Prompts



