{"manifest":{"name":"OpenAPI REST Explorer","version":"1.0.0","description":"Browse API endpoints interactively. Pre-loaded with the SkillSlap REST API spec — endpoints, parameters, response schemas, and status codes all in one view.","tags":["api","openapi","documentation","rest","tool","visualization"],"standard":"agentskills.io","standard_version":"1.0","content_checksum":"70b8e614f38564b51198e4f24013985bb05ac3b8b28cd3c106d9835c92428f4b","bundle_checksum":"f6b6858a588d917d0921a4de482e7da83b174bb7ac44c80b5af576b400d03d80","metadata":{"runtime":{"entrypoint":"openapi-explorer.html"}},"files":[{"path":"openapi-explorer.html","name":"openapi-explorer.html","mime_type":"text/html","checksum":"57a2c34d6e91d7f563f4600e9bb9f9023ab2715182171b0254028e2071fb35f0"}]},"files":{"SKILL.md":"# OpenAPI REST Explorer\n\n> **Purpose:** Render any REST API spec as an interactive, searchable reference UI. Pre-loaded with the SkillSlap API endpoints. Click an endpoint in the sidebar to see its full documentation: description, parameters (with types and required flags), example response schema, and status codes.\n\n---\n\n## What's Included (Pre-loaded)\n\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /skills | List all skills with search and filtering |\n| GET | /skills/{id} | Retrieve full skill details |\n| POST | /skills | Create and publish a new skill |\n| POST | /skills/{id}/fork | Fork a skill to your account |\n| GET | /skills/{id}/verifications | List verification runs |\n\n---\n\n## How to Use\n\n1. Click any endpoint in the left sidebar\n2. Read the description, parameters, and response schema\n3. Use **Try It Out** to manually test against a live API\n\n---\n\n## Reading Parameters\n\n- **Red asterisk (*)** — required parameter\n- `in: path` — part of the URL\n- `in: query` — appended as `?key=value`\n- `in: body` — sent as JSON request body\n- `in: header` — sent as HTTP header\n\n---\n\n## Adapting to Your API\n\nModify the `api.endpoints` array in the source to document your own API. The renderer handles GET, POST, PUT, DELETE, and PATCH with color-coded method badges.\n","openapi-explorer.html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<title>OpenAPI REST Explorer</title>\n<style>\n* { box-sizing: border-box; margin: 0; padding: 0; }\nbody { background: #0a0a14; color: #e2e8f0; font-family: system-ui, sans-serif; display: flex; flex-direction: column; height: 100vh; }\nheader { background: #1a1a2e; border-bottom: 1px solid #2d2d4e; padding: 12px 20px; flex-shrink: 0; }\n.h-title { font-size: 16px; color: #a78bfa; font-weight: 700; }\n.h-sub { font-size: 11px; color: #4b5563; margin-top: 3px; }\n.layout { display: flex; flex: 1; overflow: hidden; }\n.sidebar { width: 258px; background: #0d0d1c; border-right: 1px solid #1e1e3a; overflow-y: auto; padding: 14px; flex-shrink: 0; }\n.sb-label { font-size: 10px; text-transform: uppercase; letter-spacing: 1px; color: #4b5563; margin-bottom: 10px; }\n.ep { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-radius: 6px; cursor: pointer; margin-bottom: 3px; transition: background 0.1s; }\n.ep:hover { background: #1a1a2e; }\n.ep.sel { background: #2d1b69; }\n.badge { font-size: 10px; font-weight: 800; padding: 2px 7px; border-radius: 4px; min-width: 40px; text-align: center; }\n.GET    { background: #064e3b; color: #6ee7b7; }\n.POST   { background: #1e3a5f; color: #93c5fd; }\n.PUT    { background: #451a03; color: #fcd34d; }\n.DELETE { background: #450a0a; color: #fca5a5; }\n.PATCH  { background: #3b1f6e; color: #c4b5fd; }\n.ep-path { font-family: monospace; font-size: 11px; color: #94a3b8; flex: 1; }\n.main { flex: 1; overflow-y: auto; padding: 24px 28px; }\n.ep-title { font-size: 20px; font-weight: 700; display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }\n.ep-desc { color: #94a3b8; font-size: 13px; line-height: 1.7; margin-bottom: 24px; }\n.section { margin-bottom: 22px; }\n.sec-hd { font-size: 10px; text-transform: uppercase; letter-spacing: 1px; color: #4b5563; border-bottom: 1px solid #1e1e3a; padding-bottom: 7px; margin-bottom: 12px; }\n.param { display: flex; gap: 12px; padding: 8px 0; border-bottom: 1px solid #12121e; align-items: flex-start; }\n.pname { font-family: monospace; font-size: 12px; color: #c4b5fd; min-width: 130px; }\n.req { color: #f87171; margin-left: 1px; }\n.pin { font-size: 10px; color: #4b5563; margin-top: 2px; }\n.ptype { font-size: 10px; background: #1e1e3a; padding: 2px 7px; border-radius: 4px; color: #6b7280; white-space: nowrap; }\n.pdesc { font-size: 12px; color: #6b7280; flex: 1; }\n.codeblock { background: #0a0a14; border: 1px solid #1e1e3a; border-radius: 8px; padding: 16px; font-family: monospace; font-size: 12px; line-height: 1.65; color: #6ee7b7; overflow-x: auto; white-space: pre; }\n.sc { display: inline-block; font-family: monospace; font-size: 11px; padding: 2px 9px; border-radius: 4px; margin-right: 6px; font-weight: 700; }\n.s2 { background: #064e3b; color: #6ee7b7; }\n.s4 { background: #451a03; color: #fcd34d; }\n.s401 { background: #450a0a; color: #fca5a5; }\n.trybtn { margin-top: 18px; background: #6d28d9; color: white; border: none; padding: 9px 18px; border-radius: 7px; cursor: pointer; font-size: 13px; font-weight: 700; }\n.trybtn:hover { background: #7c3aed; }\n.empty { text-align: center; padding-top: 80px; color: #2d2d4e; }\n.empty-icon { font-size: 48px; margin-bottom: 14px; }\n</style>\n</head>\n<body>\n<header>\n  <div class=\"h-title\">SkillSlap API <span style=\"font-size:11px;font-weight:400;background:#2d1b69;color:#a78bfa;padding:2px 9px;border-radius:12px;margin-left:8px\">v1.0</span></div>\n  <div class=\"h-sub\">REST API &#8226; Base: https://skillslap.com/api/v1 &#8226; Auth: Bearer token</div>\n</header>\n<div class=\"layout\">\n  <div class=\"sidebar\">\n    <div class=\"sb-label\">Skills Endpoints</div>\n    <div id=\"sb\"></div>\n  </div>\n  <div class=\"main\" id=\"main\">\n    <div class=\"empty\"><div class=\"empty-icon\">&#9889;</div><div style=\"color:#4b5563;font-size:15px\">Select an endpoint</div></div>\n  </div>\n</div>\n<script>\nvar sel = -1;\nvar eps = [\n  { method:'GET', path:'/skills', sum:'List Skills',\n    desc:'Returns a paginated list of published skills. Supports full-text search, tag filtering, verified-only toggle, and cursor-based pagination.',\n    params:[\n      {n:'q',in:'query',t:'string',req:false,d:'Full-text search query'},\n      {n:'tags',in:'query',t:'string[]',req:false,d:'Comma-separated tag filter'},\n      {n:'verified',in:'query',t:'boolean',req:false,d:'Only return AI-verified skills'},\n      {n:'page',in:'query',t:'integer',req:false,d:'Page number (default: 1)'},\n      {n:'limit',in:'query',t:'integer',req:false,d:'Items per page, max 100 (default: 20)'},\n    ],\n    res:'{\\n  \"skills\": [\\n    {\\n      \"id\": \"ck8x9q1a0000001\",\\n      \"title\": \"Code Reviewer\",\\n      \"description\": \"Systematic code review agent\",\\n      \"author\": { \"username\": \"atapifire\" },\\n      \"tags\": [\"code-quality\", \"review\"],\\n      \"overall_score\": 0.92,\\n      \"fork_count\": 14,\\n      \"verified\": true\\n    }\\n  ],\\n  \"total\": 42,\\n  \"page\": 1\\n}',\n    codes:['200','400'] },\n  { method:'GET', path:'/skills/{id}', sum:'Get Skill',\n    desc:'Retrieve full skill details. Use X-Detail-Level header to control response depth: 1 = metadata only, 2 = metadata + content, 3 = full detail including files and verification results.',\n    params:[\n      {n:'id',in:'path',t:'string',req:true,d:'Skill ID or slug'},\n      {n:'X-Detail-Level',in:'header',t:'1 | 2 | 3',req:false,d:'Response detail level (default: 2)'},\n    ],\n    res:'{\\n  \"id\": \"ck8x9q1a0000001\",\\n  \"title\": \"Code Reviewer\",\\n  \"content\": \"# Code Reviewer\\\\n\\\\n> **Purpose:** ...\",\\n  \"version\": \"1.0.0\",\\n  \"invocation_type\": \"agent\",\\n  \"overall_score\": 0.92,\\n  \"verification\": {\\n    \"status\": \"verified\",\\n    \"last_verified_at\": \"2026-02-20T10:00:00Z\"\\n  }\\n}',\n    codes:['200','401','404'] },\n  { method:'POST', path:'/skills', sum:'Create Skill',\n    desc:'Publish a new skill to the marketplace. Skills start in draft status and must pass AI verification before appearing in search results and the public marketplace.',\n    params:[\n      {n:'title',in:'body',t:'string',req:true,d:'Skill title, max 100 characters'},\n      {n:'description',in:'body',t:'string',req:true,d:'Short description, max 500 characters'},\n      {n:'content',in:'body',t:'string',req:true,d:'Full skill content in Markdown'},\n      {n:'tags',in:'body',t:'string[]',req:false,d:'Up to 10 tags'},\n      {n:'invocation_type',in:'body',t:'agent|user|tool|context',req:true,d:'How this skill is invoked'},\n    ],\n    res:'{\\n  \"id\": \"ck9abc123\",\\n  \"title\": \"My New Skill\",\\n  \"status\": \"draft\",\\n  \"created_at\": \"2026-02-20T10:00:00Z\"\\n}',\n    codes:['201','400','401'] },\n  { method:'POST', path:'/skills/{id}/fork', sum:'Fork Skill',\n    desc:'Create a personal copy of any skill. The fork maintains attribution to the original author and increments the original skill fork count. Forked skills start as drafts.',\n    params:[\n      {n:'id',in:'path',t:'string',req:true,d:'ID of the skill to fork'},\n      {n:'title',in:'body',t:'string',req:false,d:'Optional custom title for your fork'},\n    ],\n    res:'{\\n  \"id\": \"ck9fork456\",\\n  \"title\": \"Code Reviewer (fork)\",\\n  \"forked_from\": \"ck8x9q1a0000001\",\\n  \"status\": \"draft\"\\n}',\n    codes:['201','401','404'] },\n  { method:'GET', path:'/skills/{id}/verifications', sum:'Get Verifications',\n    desc:'List all AI verification runs for a skill. Each verification includes per-category scores, execution trace, screenshot URLs, and an overall pass/fail decision.',\n    params:[\n      {n:'id',in:'path',t:'string',req:true,d:'Skill ID'},\n    ],\n    res:'{\\n  \"verifications\": [\\n    {\\n      \"id\": \"ver_abc\",\\n      \"status\": \"passed\",\\n      \"overall_score\": 0.92,\\n      \"categories\": {\\n        \"correctness\": 0.95,\\n        \"completeness\": 0.88,\\n        \"format_quality\": 0.92\\n      },\\n      \"created_at\": \"2026-02-20T10:00:00Z\"\\n    }\\n  ]\\n}',\n    codes:['200','404'] },\n];\n\nfunction renderSb() {\n  document.getElementById('sb').innerHTML = eps.map(function(e,i){\n    return '<div class=\"ep'+(i===sel?' sel':'')+'\" onclick=\"pick('+i+')\">'\n      +'<span class=\"badge '+e.method+'\">'+e.method+'</span>'\n      +'<span class=\"ep-path\">'+e.path+'</span></div>';\n  }).join('');\n}\n\nfunction scClass(c) {\n  if (c==='200'||c==='201') return 's2';\n  if (c==='401') return 's401';\n  return 's4';\n}\n\nfunction pick(i) {\n  sel = i;\n  renderSb();\n  var e = eps[i];\n  var params = e.params.map(function(p){\n    return '<div class=\"param\">'\n      +'<div><div class=\"pname\">'+p.n+(p.req?'<span class=\"req\">*</span>':'')+'</div>'\n      +'<div class=\"pin\">in: '+p.in+'</div></div>'\n      +'<span class=\"ptype\">'+p.t+'</span>'\n      +'<span class=\"pdesc\">'+p.d+'</span></div>';\n  }).join('');\n  var codes = e.codes.map(function(c){\n    return '<span class=\"sc '+scClass(c)+'\">'+c+'</span>';\n  }).join('');\n  document.getElementById('main').innerHTML =\n    '<div class=\"ep-title\"><span class=\"badge '+e.method+'\" style=\"font-size:13px\">'+e.method+'</span>'+e.path+'</div>'\n    +'<div class=\"ep-desc\">'+e.desc+'</div>'\n    +(params?'<div class=\"section\"><div class=\"sec-hd\">Parameters</div>'+params+'</div>':'')\n    +'<div class=\"section\"><div class=\"sec-hd\">Response</div><div class=\"codeblock\">'+e.res+'</div></div>'\n    +'<div class=\"section\"><div class=\"sec-hd\">Status Codes</div>'+codes+'</div>'\n    +'<button class=\"trybtn\">Try It Out &rarr;</button>';\n}\n\nrenderSb();\npick(0);\n</script>\n</body>\n</html>"}}