Skills Marketplace API — Build Spec
Instructions for building the server-side Skills API that powers the groove Skills Store. This API is hosted on the docs/retail site (docs.groovedev.ai).
Context
groove is an agent orchestration tool. Its GUI has a Skills Store (app-store style) that currently reads from a static registry.json file. We need a real API so users can submit, edit, and sell their own skills. The groove daemon will fetch from this API instead of the static file.
What exists today (static files):
https://docs.groovedev.ai/skills/registry.json— JSON array of all skill metadatahttps://docs.groovedev.ai/skills/content/<id>.md— individual SKILL.md files
What we're building:
A REST API that replaces the static files and adds CRUD + author management.
Data Model
Skill
{
"id": "frontend-design",
"name": "Frontend Design",
"description": "Create distinctive, production-grade frontend interfaces...",
"author": "Anthropic",
"authorId": "user_abc123",
"authorProfile": {
"avatar": "https://...",
"website": "https://anthropic.com",
"github": "anthropics",
"twitter": "AnthropicAI",
"bio": "Building reliable AI systems"
},
"category": "design",
"tags": ["frontend", "ui", "css", "react"],
"roles": ["frontend", "fullstack"],
"source": "claude-official",
"icon": "P",
"contentUrl": "https://docs.groovedev.ai/skills/content/frontend-design.md",
"content": "--- (full SKILL.md content) ---",
"downloads": 1840,
"rating": 4.8,
"ratingCount": 124,
"price": 0,
"featured": false,
"status": "published",
"version": "1.0.0",
"createdAt": "2026-04-01T00:00:00Z",
"updatedAt": "2026-04-06T00:00:00Z"
}Categories (enum): design, quality, devtools, workflow, security, specialized
Status (enum): draft, review, published, rejected, unlisted
Source: claude-official for Anthropic skills, community for user-submitted
Author / User
{
"id": "user_abc123",
"githubId": "12345",
"username": "johndoe",
"displayName": "John Doe",
"avatar": "https://avatars.githubusercontent.com/u/12345",
"bio": "Senior UI designer, 10 years experience",
"website": "https://johndoe.dev",
"github": "johndoe",
"twitter": "johndoe",
"portfolio": "https://dribbble.com/johndoe",
"createdAt": "2026-04-01T00:00:00Z",
"skillCount": 3,
"totalDownloads": 5200
}API Endpoints
Base URL: https://docs.groovedev.ai/api/v1
Public (no auth)
GET /skills
Returns the full skill registry. This is what the groove daemon fetches on startup.
Query params:
search— text search on name, description, tagscategory— filter by categorysort—popular(default),rating,newest,namestatus— defaults topublishedonlyauthor— filter by authorIdlimit— pagination (default 50)offset— pagination offset
Response:
{
"skills": [ ... ],
"total": 21,
"categories": [
{ "id": "devtools", "count": 9 },
{ "id": "quality", "count": 3 }
]
}Important: The response shape must match what the groove daemon expects. The skills array uses the same schema as registry.json today. The content field should NOT be included in list responses (it's large). Only metadata.
GET /skills/:id
Returns a single skill with full metadata.
Response: single skill object (without content field)
GET /skills/:id/content
Returns the full SKILL.md content for a skill.
Response:
{
"id": "frontend-design",
"content": "---\nname: Frontend Design\n---\n\n..."
}GET /skills/registry.json
Backwards compatibility. Returns the same format as the current static file so older groove versions still work. Just the skills array, no wrapper object.
GET /authors/:id
Public author profile.
Response: author object + their published skills
Authenticated (shared API key)
Auth Model
Server-to-server only. No OAuth, no JWT, no user accounts.
- Single shared API key between groove daemon and skills server
- Passed via
Authorization: Bearer <API_KEY>header - The API key is set as an environment variable on both servers
- All write endpoints require the key; public read endpoints do not
- The groove daemon is the only client — users interact through the daemon GUI, never directly with this API
This keeps everything contained. When we add user accounts later (for paid skills / seller dashboards), we'll layer that on top — but the server-to-server channel stays as a simple API key.
POST /skills
Submit a new skill.
Headers: Authorization: Bearer <API_KEY>
Body:
{
"name": "My Awesome Skill",
"description": "Does amazing things...",
"author": "John Doe",
"authorProfile": {
"website": "https://johndoe.dev",
"github": "johndoe",
"twitter": "johndoe"
},
"category": "design",
"tags": ["ui", "css"],
"roles": ["frontend"],
"icon": "A",
"content": "---\nname: My Awesome Skill\n---\n\nFull SKILL.md content here...",
"price": 0,
"version": "1.0.0"
}idis auto-generated from slugifiednamesourceset tocommunitystatusset todraftinitiallydownloads,rating,ratingCountinitialized to 0
Response: created skill object
PUT /skills/:id
Edit an existing skill.
Headers: Authorization: Bearer <API_KEY>
Body: partial skill object (only changed fields)
Restrictions:
- Cannot change
id,source,downloads,rating,ratingCount - Changing
contentbumpsupdatedAt
DELETE /skills/:id
Remove a skill. Sets status to unlisted (soft delete).
Headers: Authorization: Bearer <API_KEY>
POST /skills/:id/publish
Submit a skill for review / publish it.
Headers: Authorization: Bearer <API_KEY>
- If
price === 0: auto-publish (set status topublished) - If
price > 0: set status toreview(manual review before listing)
Rating (public, no auth)
POST /skills/:id/rate
Submit a rating for a skill. No auth required — rate-limited by IP (1 rating per skill per IP per 24 hours).
Body:
{
"rating": 4
}rating: integer 1-5- Server should track ratings per IP to prevent spam (overwrite previous rating from same IP, don't accumulate)
- Recalculate skill's
rating(weighted average) andrating_count(unique raters)
Response:
{
"id": "code-review",
"rating": 4.8,
"rating_count": 202
}The groove daemon proxies this request from the GUI. The daemon calls POST /api/v1/skills/:id/rate on behalf of the user.
Future (Payments — don't build yet, but design schema for it)
POST /skills/:id/purchase— record a purchaseGET /authors/me/earnings— seller dashboard- Stripe Connect for payouts
- 80/20 revenue share (creator/platform)
- Price field already in the skill model, just not enforced yet
Key Design Decisions
Backwards compatible —
/skills/registry.jsonmust keep working as a plain JSON array. The groove daemon currently fetches this on startup. Newer daemon versions will switch to/api/v1/skills.Content separate from metadata — The
content(full SKILL.md) is large. Never include it in list/registry responses. Only serve it via/skills/:id/content.Soft deletes — Never hard-delete skills. Set status to
unlisted.Download counting — Increment on install. The groove daemon will POST to
/skills/:id/installto record an install (new endpoint, unauthenticated, rate-limited by IP).Rating —
POST /skills/:id/rateis live. Rate-limited by IP (1 per skill per 24h). Overwrites previous rating from same IP. Recalculates weighted average.The 21 Anthropic skills — Seed the database with these. They have
source: "claude-official"andauthor: "Anthropic". They should not be editable via the API.Validation:
name: 3-100 charsdescription: 10-500 charscontent: must be valid markdown, max 50KBcategory: must be one of the enum valuestags: max 10, each 2-30 charsicon: single characterprice: >= 0, max 99.99
Tech Recommendations
- Whatever fits the existing docs site stack
- If starting fresh: Node.js + Express or Hono, SQLite or Postgres
- Shared API key for write endpoints (env var
SKILLS_API_KEY) - No OAuth, no JWT — server-to-server only for now
- Rate limiting on public endpoints (60/min per IP)
- CORS: allow
localhost:*(for groove daemon) +groovedev.aiorigins
Install Tracking Endpoint
Add this for download counting (the groove daemon calls this when a user installs a skill):
POST /skills/:id/install
Unauthenticated. Rate-limited (1 per skill per IP per hour).
Increments the downloads counter.
Response: { "downloads": 1841 }
This replaces the current flow where the daemon downloads from contentUrl directly. New flow:
- Daemon calls
POST /api/v1/skills/:id/installto record the install - Daemon calls
GET /api/v1/skills/:id/contentto get the SKILL.md - Daemon saves locally
Seed Data
The current skills-registry.json in the groove repo has all 21 Anthropic skills with full metadata including downloads, ratings, prices, author profiles, and featured flags. Use this to seed the database.
