> ## Documentation Index
> Fetch the complete documentation index at: https://docs.uniskill.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Skill Registry

> Three-tier KV skill registry structure and Unified JSON format

## Three-Tier Priority

Skills are stored in Cloudflare KV under three namespaced layers, resolved with strict priority:

| Priority        | KV Key Prefix                   | Scope                      |
| --------------- | ------------------------------- | -------------------------- |
| **1 (highest)** | `skill:private:{uid}:{skillId}` | Per-user custom skills     |
| **2**           | `skill:official:{skillId}`      | UniSkill curated tools     |
| **3**           | `skill:market:{skillId}`        | Community-published skills |

Resolution stops at the first hit. A private skill always shadows an official skill of the same name.

## Unified JSON Format

Every skill entry is stored as a single JSON blob:

```json theme={null}
{
  "id": "uniskill_weather",
  "source": "official",
  "skill_uid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "meta": {
    "name": "Global Weather",
    "description": "...",
    "emoji": "🌤",
    "tags": ["weather", "forecast"],
    "parameters": {
      "type": "object",
      "properties": {
        "location": { "type": "string", "description": "City name or coordinates" }
      },
      "required": ["location"]
    }
  },
  "config": {
    "endpoint": "https://api.open-meteo.com/v1/forecast",
    "method": "GET",
    "plugin_hook": "weather"
  },
  "credits_per_call": 1
}
```

## Full KV Namespace

| Key Pattern                     | Purpose                                       |
| ------------------------------- | --------------------------------------------- |
| `skill:official:{skillId}`      | Official skills                               |
| `skill:private:{uid}:{skillId}` | Private skills (UID-isolated)                 |
| `skill:market:{skillId}`        | Market skills                                 |
| `auth:hash:{keyHash}`           | Key hash → User UID (TTL=30d)                 |
| `profile:{uid}`                 | User profile JSON (credits + tier + username) |
| `skill:secrets:{uid}`           | User global secrets (AES-256 encrypted)       |
| `skill:secrets:{uid}:{skillId}` | Skill-level secrets (AES-256 encrypted)       |
| `ratelimit:{keyHash}:{minute}`  | Per-minute request counter                    |
| `mcp_registry:tools_cache`      | MCP tools/list cache (manual invalidation)    |
| `mcp_broadcast:tools_changed`   | Global tool refresh broadcast timestamp       |

> **Deprecated (self-healing migration in progress):** `credits:{uid}`, `tier:{uid}`, `user:uid:{hash}`

## Parsing

`engine/parser.ts` (`SkillParser.parse()`) handles two formats:

* **Unified JSON** (primary) — detected by `input.trim().startsWith('{')`, parsed directly
* **Legacy Markdown** (fallback) — H1 as name, YAML block as implementation, JSON block as parameters

The parser normalizes both formats into a standard `SkillSpec` struct before execution.

## Admin Sync

Skills are pushed into KV by `uniskill-web` via:

* `POST /v1/admin/sync_skill` — single skill upsert (accepts `ADMIN_KEY` or `INTERNAL_API_SECRET`)
* `POST /v1/admin/sync_cache` — bulk cache invalidation
* `POST /v1/admin/refresh-tools` — writes `mcp_broadcast:tools_changed` to trigger global MCP tool list refresh
