Skip to content

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 metadata
  • https://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

json
{
  "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

json
{
  "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, tags
  • category — filter by category
  • sortpopular (default), rating, newest, name
  • status — defaults to published only
  • author — filter by authorId
  • limit — pagination (default 50)
  • offset — pagination offset

Response:

json
{
  "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:

json
{
  "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:

json
{
  "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"
}
  • id is auto-generated from slugified name
  • source set to community
  • status set to draft initially
  • downloads, rating, ratingCount initialized 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 content bumps updatedAt

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 to published)
  • If price > 0: set status to review (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:

json
{
  "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) and rating_count (unique raters)

Response:

json
{
  "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 purchase
  • GET /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

  1. Backwards compatible/skills/registry.json must keep working as a plain JSON array. The groove daemon currently fetches this on startup. Newer daemon versions will switch to /api/v1/skills.

  2. 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.

  3. Soft deletes — Never hard-delete skills. Set status to unlisted.

  4. Download counting — Increment on install. The groove daemon will POST to /skills/:id/install to record an install (new endpoint, unauthenticated, rate-limited by IP).

  5. RatingPOST /skills/:id/rate is live. Rate-limited by IP (1 per skill per 24h). Overwrites previous rating from same IP. Recalculates weighted average.

  6. The 21 Anthropic skills — Seed the database with these. They have source: "claude-official" and author: "Anthropic". They should not be editable via the API.

  7. Validation:

    • name: 3-100 chars
    • description: 10-500 chars
    • content: must be valid markdown, max 50KB
    • category: must be one of the enum values
    • tags: max 10, each 2-30 chars
    • icon: single character
    • price: >= 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.ai origins

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:

  1. Daemon calls POST /api/v1/skills/:id/install to record the install
  2. Daemon calls GET /api/v1/skills/:id/content to get the SKILL.md
  3. 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.

Last updated:

FSL-1.1-Apache-2.0