{"items":[{"id":"cmuguczl600o8qu06ul2geh5y","slug":"yusufkaraaslan-skill-seekers-skill-seekers","name":"skill-seekers","description":"Convert documentation websites, GitHub repositories, and PDFs into Claude AI skills with automatic conflict detection","authorId":"gh:yusufkaraaslan","authorName":"yusufkaraaslan","version":"0.1.0","category":"MCP","securityLevel":"Sandbox","downloadsCount":0,"githubStars":15027,"pricePerCall":0,"manifest":{"name":"skill-seekers","tools":[],"category":"MCP","entrypoint":{"args":["-m","skill_seekers.mcp.server_fastmcp"],"type":"mcp-stdio","command":"python"},"description":"","permissions":["shell","network"],"requiredEnv":[],"schemaVersion":1},"repoUrl":"https://github.com/yusufkaraaslan/Skill_Seekers","tags":["ai-tools","ast-parser","automation","claude-ai","claude-skills","code-analysis","conflict-detection","documentation","documentation-generator","github","github-scraper","mcp"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"Skill_Seekers","audit":{"files":["pyproject.toml","requirements.txt","uv.lock"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-03","message":"`GitPython` is one or two edits away from the popular `ipython`.","surface":"pyproject.toml","evidence":"GitPython","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"anyio@4.11.0 has a known vulnerability: AnyIO process-pool workers can block indefinitely on undrained stderr.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-5p39-cfhj-2xmp · PyPI:anyio@4.11.0","severity":"medium"},{"kind":"dependency","rule":"DP-01","message":"anyio@4.11.0 has a known vulnerability: AnyIO: TLSStream IDNA 2003 host name encoding enables potential TLS certificate spoofing.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-82r6-8w77-94w6 · PyPI:anyio@4.11.0","severity":"critical"},{"kind":"dependency","rule":"DP-01","message":"click@8.3.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2132 · PyPI:click@8.3.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"idna@3.11 has a known vulnerability: Internationalized Domain Names in Applications (IDNA): Specially crafted inputs to idna.encode() can bypass CVE-2024-3651 fix.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-65pc-fj4g-8rjx · PyPI:idna@3.11","severity":"medium"},{"kind":"dependency","rule":"DP-01","message":"idna@3.11 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-215 · PyPI:idna@3.11","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pygments@2.19.2 has a known vulnerability: Pygments has Regular Expression Denial of Service (ReDoS) due to Inefficient Regex for GUID Matching.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-5239-wwwm-4pmq · PyPI:Pygments@2.19.2","severity":"low"},{"kind":"dependency","rule":"DP-01","message":"Pygments@2.19.2 has a known vulnerability: Pygments has Regular Expression Denial of Service (ReDoS) due to Inefficient Regex for GUID Matching.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2987 · PyPI:Pygments@2.19.2","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability: Pillow `BdfFontFile`: `Image.new()` called without `_decompression_bomb_check()` — bomb protection bypass via font loading.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-45hq-cxwh-f6vc · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability: Pillow: WindowsViewer.get_command() OS command injection via unescaped shell path.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-4x4j-2g7c-83w6 · PyPI:Pillow@11.0.0","severity":"medium"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability: Pillow: `FontFile.compile()`: `Image.new()` called without `_decompression_bomb_check()`.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-5x94-69rx-g8h2 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-62p4-gmf7-7g93 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-6r8x-57c9-28j4 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-8v84-f9pq-wr9x · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-9hw9-ch79-4vh6 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-cfh3-3jmp-rvhc · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-fj7v-r99m-22gq · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-jjj6-mw9f-p565 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-phj9-mv4w-65pm · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-pwv6-vv43-88gr · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-r73j-pqj5-w3x7 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-vjc4-5qp5-m44j · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-whj4-6x5x-4v2j · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-wjx4-4jcj-g98j · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-xj96-63gp-2gmr · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-165 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2249 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2250 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2252 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2253 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2254 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2255 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2256 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2257 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2874 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3451 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3453 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3454 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3493 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3494 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3495 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3496 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"pytest@8.4.2 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-6w46-j5rx-g56g · PyPI:pytest@8.4.2","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"pytest@8.4.2 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-1845 · PyPI:pytest@8.4.2","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"python-dotenv@1.1.1 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-mf9w-mj56-hr94 · PyPI:python-dotenv@1.1.1","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"python-dotenv@1.1.1 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2270 · PyPI:python-dotenv@1.1.1","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"requests@2.32.5 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-gc5v-m9x4-r6x2 · PyPI:requests@2.32.5","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"requests@2.32.5 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2275 · PyPI:requests@2.32.5","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"soupsieve@2.8 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-2wc2-fm75-p42x · PyPI:soupsieve@2.8","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"soupsieve@2.8 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-836r-79rf-4m37 · PyPI:soupsieve@2.8","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"soupsieve@2.8 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-gjv8-xp57-g29c · PyPI:soupsieve@2.8","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"soupsieve@2.8 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-j934-xhv5-fg8f · PyPI:soupsieve@2.8","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"soupsieve@2.8 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3071 · PyPI:soupsieve@2.8","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"soupsieve@2.8 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3072 · PyPI:soupsieve@2.8","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-2xpw-w6gg-jr37 · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-38jv-5279-wg99 · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-gm62-xv2j-4w53 · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-qccp-gfcp-xxvc · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-141 · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-1994 · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-1996 · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-1998 · PyPI:urllib3@2.5.0","severity":"high"}],"packages":63,"auditedAt":"2026-09-25T10:52:13.469Z","lockfiles":["uv.lock"]},"forks":1533,"owner":"yusufkaraaslan","stars":15027,"topics":["ai-tools","ast-parser","automation","claude-ai","claude-skills","code-analysis","conflict-detection","documentation","documentation-generator","github","github-scraper","mcp","mcp-server","multi-source","ocr","pdf","python","web-scraping"],"license":"MIT","fullName":"yusufkaraaslan/Skill_Seekers","homepage":"https://skillseekersweb.com/","language":"Python","pushedAt":"2026-09-20T16:14:08Z","avatarUrl":"https://avatars.githubusercontent.com/u/11597362?v=4","crawledAt":"2026-09-25T10:52:08.347Z","openIssues":47,"manifestFile":".mcp.json","manifestPath":".mcp.json","defaultBranch":"development"},"readme":"<p align=\"center\">\n  <img src=\"docs/assets/logo.png\" alt=\"Skill Seekers\" width=\"200\"/>\n</p>\n\n# Skill Seekers\n\nEnglish | [简体中文](README.zh-CN.md) | [日本語](README.ja.md) | [한국어](README.ko.md) | [Español](README.es.md) | [Français](README.fr.md) | [Deutsch](README.de.md) | [Português](README.pt-BR.md) | [Türkçe](README.tr.md) | [العربية](README.ar.md) | [हिन्दी](README.hi.md) | [Русский](README.ru.md)\n\n[![Version](https://img.shields.io/badge/version-3.9.0-blue.svg)](https://github.com/yusufkaraaslan/Skill_Seekers/releases)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)\n[![MCP Integration](https://img.shields.io/badge/MCP-40-Tools-blue.svg)](https://modelcontextprotocol.io)\n[![Tested](https://img.shields.io/badge/Tests-3900%2B%20Passing-brightgreen.svg)](tests/)\n[![PyPI version](https://badge.fury.io/py/skill-seekers.svg)](https://pypi.org/project/skill-seekers/)\n[![PyPI - Downloads](https://img.shields.io/pypi/dm/skill-seekers.svg)](https://pypi.org/project/skill-seekers/)\n[![Website](https://img.shields.io/badge/Website-skillseekersweb.com-blue.svg)](https://skillseekersweb.com/)\n[![GitHub Repo stars](https://img.shields.io/github/stars/yusufkaraaslan/Skill_Seekers?style=social)](https://github.com/yusufkaraaslan/Skill_Seekers)\n[![PyPI Downloads](https://static.pepy.tech/personalized-badge/skill-seekers?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/skill-seekers)\n\n<a href=\"https://trendshift.io/repositories/18329\" target=\"_blank\"><img src=\"https://trendshift.io/api/badge/repositories/18329\" alt=\"yusufkaraaslan%2FSkill_Seekers | Trendshift\" style=\"width: 250px; height: 55px;\" width=\"250\" height=\"55\"/></a>\n\n**🧠 The data layer for AI systems.** Skill Seekers turns documentation sites, GitHub repos, PDFs, videos, notebooks, wikis, and more — **18 source types** — into structured knowledge assets, ready to power AI Skills (Claude, Gemini, OpenAI), RAG pipelines (LangChain, LlamaIndex, Pinecone), and AI coding assistants (Cursor, Windsurf, Cline). Prepare once, export to **22 targets**.\n\n## 💛 Sponsors\n\n<!-- SPONSORS:START -->\n### Bronze Sponsors\n\n<p align=\"center\">\n  <a href=\"https://fluxionai.world/register?utm_source=github&utm_medium=sponsor&utm_campaign=skillseekers\"><img src=\"docs/assets/sponsors/fluxion-ai.png\" alt=\"Fluxion AI\" width=\"100\"></a><br/><sub><b>Sponsor — Bronze</b></sub>\n</p>\n<!-- SPONSORS:END -->\n\n**[Become a sponsor](SPONSORSHIP.md)** · [GitHub Sponsors](https://github.com/sponsors/yusufkaraaslan)\n\n---\n\n## 🚀 Quick Start\n\n```bash\n# 1. Install\npip install skill-seekers\n\n# 2. Create a skill from any source\nskill-seekers create https://docs.djangoproject.com/\n\n# Optional: preview how a source will be detected without creating anything\nskill-seekers detect https://docs.djangoproject.com/ --json\n\n# 3. Package it for your AI platform\nskill-seekers package output/django --target claude\n```\n\nYou now have `output/django-claude.zip`, ready to use.\n\n```bash\n# Pick a different AI agent for enhancement (default: claude)\nskill-seekers create https://docs.djangoproject.com/ --agent kimi\nskill-seekers create https://docs.djangoproject.com/ --agent-cmd \"my-custom-agent run\"\n```\n\n### 🛰️ AI-driven project scan\n\nPoint `scan` at a project and an AI agent reads its manifests, README, Dockerfile/CI and sampled source imports — then emits one config per detected framework, plus a `<project>-codebase.json` for your own code:\n\n```bash\nskill-seekers scan ./my-react-app --out ./configs/scanned/\n# → react.json, vite.json, tailwind.json, jest.json, my-react-app-codebase.json\n\nskill-seekers create ./configs/scanned/react.json\n```\n\nIf a detection has no existing preset, the AI generates a fresh config; on exit you can optionally publish it back to the [community registry](https://github.com/yusufkaraaslan","createdAt":"2026-09-25T10:52:13.482Z","updatedAt":"2026-09-25T10:52:13.482Z"},{"id":"cmuguczll00obqu067q4c4nfv","slug":"yusufkaraaslan-skill-seekers-skill-seekers-2","name":"skill-builder","description":"Automatically detect source types and build AI skills using Skill Seekers. Use when the user wants to create skills from documentation, repos, PDFs, videos, or other knowledge sources.","authorId":"gh:yusufkaraaslan","authorName":"yusufkaraaslan","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":15027,"pricePerCall":0,"manifest":{"name":"skill-builder","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Automatically detect source types and build AI skills using Skill Seekers. Use when the user wants to create skills from documentation, repos, PDFs, videos, or other knowledge sources.","permissions":[],"systemPrompt":"# Skill Builder\n\nYou have access to the Skill Seekers MCP server which provides 40 tools for converting knowledge sources into AI-ready skills.\n\n## When to Use This Skill\n\nUse this skill when the user:\n- Wants to create an AI skill from a documentation site, GitHub repo, PDF, video, or other source\n- Needs to convert documentation into a format suitable for LLM consumption\n- Wants to update or sync existing skills with their source documentation\n- Needs to export skills to vector databases (Weaviate, Chroma, FAISS, Qdrant)\n- Asks about scraping, converting, or packaging documentation for AI\n\n## Source Type Detection\n\nAutomatically detect the source type from user input:\n\n| Input Pattern | Source Type | Tool to Use |\n|---------------|-------------|-------------|\n| `https://...` (not GitHub/YouTube) | Documentation | `scrape_docs` |\n| `owner/repo` or `github.com/...` | GitHub | `scrape_github` |\n| `*.pdf` | PDF | `scrape_pdf` |\n| YouTube/Vimeo URL or video file | Video | `scrape_video` |\n| Local directory path | Codebase | `scrape_codebase` |\n| `*.ipynb`, `*.html`, `*.yaml` (OpenAPI), `*.adoc`, `*.pptx`, `*.rss`, `*.1`-`.8` | Various | `scrape_generic` |\n| JSON config file | Unified | Use config with `scrape_docs` |\n\n## Recommended Workflow\n\n1. **Detect source type** from the user's input\n2. **Generate or fetch config** using `generate_config` or `fetch_config` if needed\n3. **Estimate scope** with `estimate_pages` for documentation sites\n4. **Scrape the source** using the appropriate scraping tool\n5. **Enhance** with `enhance_skill` if the user wants AI-powered improvements\n6. **Package** with `package_skill` for the target platform\n7. **Export to vector DB** if requested using `export_to_*` tools\n\n## Available MCP Tools\n\n### Config Management\n- `generate_config` — Generate a scraping config from a URL\n- `list_configs` — List available preset configs\n- `validate_config` — Validate a config file\n\n### Scraping (use based on source type)\n- `scrape_docs` — Documentation sites\n- `scrape_github` — GitHub repositories\n- `scrape_pdf` — PDF files\n- `scrape_video` — Video transcripts\n- `scrape_codebase` — Local code analysis\n- `scrape_generic` — Jupyter, HTML, OpenAPI, AsciiDoc, PPTX, RSS, manpage, Confluence, Notion, chat\n\n### Post-processing\n- `enhance_skill` — AI-powered skill enhancement\n- `package_skill` — Package for target platform\n- `upload_skill` — Upload to platform API\n- `install_skill` — End-to-end install workflow\n\n### Advanced\n- `detect_patterns` — Design pattern detection in code\n- `extract_test_examples` — Extract usage examples from tests\n- `build_how_to_guides` — Generate how-to guides from tests\n- `split_config` — Split large configs into focused skills\n- `export_to_weaviate`, `export_to_chroma`, `export_to_faiss`, `export_to_qdrant` — Vector DB export","schemaVersion":1},"repoUrl":"https://github.com/yusufkaraaslan/Skill_Seekers/tree/development/skills/skill-seekers","tags":["ai-tools","ast-parser","automation","claude-ai","claude-skills","code-analysis","conflict-detection","documentation","documentation-generator","github","github-scraper","mcp"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"Skill_Seekers","audit":{"files":["pyproject.toml","requirements.txt","uv.lock"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-03","message":"`GitPython` is one or two edits away from the popular `ipython`.","surface":"pyproject.toml","evidence":"GitPython","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"anyio@4.11.0 has a known vulnerability: AnyIO process-pool workers can block indefinitely on undrained stderr.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-5p39-cfhj-2xmp · PyPI:anyio@4.11.0","severity":"medium"},{"kind":"dependency","rule":"DP-01","message":"anyio@4.11.0 has a known vulnerability: AnyIO: TLSStream IDNA 2003 host name encoding enables potential TLS certificate spoofing.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-82r6-8w77-94w6 · PyPI:anyio@4.11.0","severity":"critical"},{"kind":"dependency","rule":"DP-01","message":"click@8.3.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2132 · PyPI:click@8.3.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"idna@3.11 has a known vulnerability: Internationalized Domain Names in Applications (IDNA): Specially crafted inputs to idna.encode() can bypass CVE-2024-3651 fix.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-65pc-fj4g-8rjx · PyPI:idna@3.11","severity":"medium"},{"kind":"dependency","rule":"DP-01","message":"idna@3.11 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-215 · PyPI:idna@3.11","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pygments@2.19.2 has a known vulnerability: Pygments has Regular Expression Denial of Service (ReDoS) due to Inefficient Regex for GUID Matching.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-5239-wwwm-4pmq · PyPI:Pygments@2.19.2","severity":"low"},{"kind":"dependency","rule":"DP-01","message":"Pygments@2.19.2 has a known vulnerability: Pygments has Regular Expression Denial of Service (ReDoS) due to Inefficient Regex for GUID Matching.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2987 · PyPI:Pygments@2.19.2","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability: Pillow `BdfFontFile`: `Image.new()` called without `_decompression_bomb_check()` — bomb protection bypass via font loading.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-45hq-cxwh-f6vc · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability: Pillow: WindowsViewer.get_command() OS command injection via unescaped shell path.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-4x4j-2g7c-83w6 · PyPI:Pillow@11.0.0","severity":"medium"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability: Pillow: `FontFile.compile()`: `Image.new()` called without `_decompression_bomb_check()`.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-5x94-69rx-g8h2 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-62p4-gmf7-7g93 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-6r8x-57c9-28j4 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-8v84-f9pq-wr9x · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-9hw9-ch79-4vh6 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-cfh3-3jmp-rvhc · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-fj7v-r99m-22gq · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-jjj6-mw9f-p565 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-phj9-mv4w-65pm · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-pwv6-vv43-88gr · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-r73j-pqj5-w3x7 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-vjc4-5qp5-m44j · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-whj4-6x5x-4v2j · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-wjx4-4jcj-g98j · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-xj96-63gp-2gmr · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-165 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2249 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2250 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2252 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2253 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2254 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2255 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2256 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2257 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2874 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3451 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3453 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3454 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3493 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3494 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3495 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3496 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"pytest@8.4.2 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-6w46-j5rx-g56g · PyPI:pytest@8.4.2","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"pytest@8.4.2 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-1845 · PyPI:pytest@8.4.2","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"python-dotenv@1.1.1 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-mf9w-mj56-hr94 · PyPI:python-dotenv@1.1.1","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"python-dotenv@1.1.1 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2270 · PyPI:python-dotenv@1.1.1","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"requests@2.32.5 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-gc5v-m9x4-r6x2 · PyPI:requests@2.32.5","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"requests@2.32.5 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2275 · PyPI:requests@2.32.5","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"soupsieve@2.8 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-2wc2-fm75-p42x · PyPI:soupsieve@2.8","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"soupsieve@2.8 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-836r-79rf-4m37 · PyPI:soupsieve@2.8","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"soupsieve@2.8 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-gjv8-xp57-g29c · PyPI:soupsieve@2.8","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"soupsieve@2.8 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-j934-xhv5-fg8f · PyPI:soupsieve@2.8","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"soupsieve@2.8 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3071 · PyPI:soupsieve@2.8","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"soupsieve@2.8 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3072 · PyPI:soupsieve@2.8","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-2xpw-w6gg-jr37 · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-38jv-5279-wg99 · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-gm62-xv2j-4w53 · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-qccp-gfcp-xxvc · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-141 · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-1994 · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-1996 · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-1998 · PyPI:urllib3@2.5.0","severity":"high"}],"packages":63,"auditedAt":"2026-09-25T10:52:13.469Z","lockfiles":["uv.lock"]},"forks":1533,"owner":"yusufkaraaslan","stars":15027,"topics":["ai-tools","ast-parser","automation","claude-ai","claude-skills","code-analysis","conflict-detection","documentation","documentation-generator","github","github-scraper","mcp","mcp-server","multi-source","ocr","pdf","python","web-scraping"],"license":"MIT","fullName":"yusufkaraaslan/Skill_Seekers","homepage":"https://skillseekersweb.com/","language":"Python","pushedAt":"2026-09-20T16:14:08Z","avatarUrl":"https://avatars.githubusercontent.com/u/11597362?v=4","crawledAt":"2026-09-25T10:52:08.347Z","openIssues":47,"manifestFile":"SKILL.md","manifestPath":"skills/skill-seekers/SKILL.md","defaultBranch":"development"},"readme":"# Skill Builder\n\nYou have access to the Skill Seekers MCP server which provides 40 tools for converting knowledge sources into AI-ready skills.\n\n## When to Use This Skill\n\nUse this skill when the user:\n- Wants to create an AI skill from a documentation site, GitHub repo, PDF, video, or other source\n- Needs to convert documentation into a format suitable for LLM consumption\n- Wants to update or sync existing skills with their source documentation\n- Needs to export skills to vector databases (Weaviate, Chroma, FAISS, Qdrant)\n- Asks about scraping, converting, or packaging documentation for AI\n\n## Source Type Detection\n\nAutomatically detect the source type from user input:\n\n| Input Pattern | Source Type | Tool to Use |\n|---------------|-------------|-------------|\n| `https://...` (not GitHub/YouTube) | Documentation | `scrape_docs` |\n| `owner/repo` or `github.com/...` | GitHub | `scrape_github` |\n| `*.pdf` | PDF | `scrape_pdf` |\n| YouTube/Vimeo URL or video file | Video | `scrape_video` |\n| Local directory path | Codebase | `scrape_codebase` |\n| `*.ipynb`, `*.html`, `*.yaml` (OpenAPI), `*.adoc`, `*.pptx`, `*.rss`, `*.1`-`.8` | Various | `scrape_generic` |\n| JSON config file | Unified | Use config with `scrape_docs` |\n\n## Recommended Workflow\n\n1. **Detect source type** from the user's input\n2. **Generate or fetch config** using `generate_config` or `fetch_config` if needed\n3. **Estimate scope** with `estimate_pages` for documentation sites\n4. **Scrape the source** using the appropriate scraping tool\n5. **Enhance** with `enhance_skill` if the user wants AI-powered improvements\n6. **Package** with `package_skill` for the target platform\n7. **Export to vector DB** if requested using `export_to_*` tools\n\n## Available MCP Tools\n\n### Config Management\n- `generate_config` — Generate a scraping config from a URL\n- `list_configs` — List available preset configs\n- `validate_config` — Validate a config file\n\n### Scraping (use based on source type)\n- `scrape_docs` — Documentation sites\n- `scrape_github` — GitHub repositories\n- `scrape_pdf` — PDF files\n- `scrape_video` — Video transcripts\n- `scrape_codebase` — Local code analysis\n- `scrape_generic` — Jupyter, HTML, OpenAPI, AsciiDoc, PPTX, RSS, manpage, Confluence, Notion, chat\n\n### Post-processing\n- `enhance_skill` — AI-powered skill enhancement\n- `package_skill` — Package for target platform\n- `upload_skill` — Upload to platform API\n- `install_skill` — End-to-end install workflow\n\n### Advanced\n- `detect_patterns` — Design pattern detection in code\n- `extract_test_examples` — Extract usage examples from tests\n- `build_how_to_guides` — Generate how-to guides from tests\n- `split_config` — Split large configs into focused skills\n- `export_to_weaviate`, `export_to_chroma`, `export_to_faiss`, `export_to_qdrant` — Vector DB export","createdAt":"2026-09-25T10:52:13.497Z","updatedAt":"2026-09-25T10:52:13.497Z"},{"id":"cmuguczlz00oequ06v09cwt8l","slug":"yusufkaraaslan-skill-seekers-skill-builder","name":"skill-builder","description":"Automatically detect source types and build AI skills using Skill Seekers. Use when the user wants to create skills from documentation, repos, PDFs, videos, or other knowledge sources.","authorId":"gh:yusufkaraaslan","authorName":"yusufkaraaslan","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":15027,"pricePerCall":0,"manifest":{"name":"skill-builder","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Automatically detect source types and build AI skills using Skill Seekers. Use when the user wants to create skills from documentation, repos, PDFs, videos, or other knowledge sources.","permissions":[],"systemPrompt":"# Skill Builder\n\nThis skill uses the Skill Seekers MCP server, which provides 40 tools for converting knowledge sources into AI-ready skills. If the MCP tools are not available, use the CLI fallback at the bottom of this file instead — do not stop.\n\n## Prerequisites\n\nThe MCP tools below only work when the Skill Seekers MCP server is connected:\n\n1. Install the package: `pip install \"skill-seekers[mcp]\"`\n2. Connect the server:\n   - Installed as the Skill Seekers plugin? Nothing to do — the plugin's bundled `.mcp.json` starts the server automatically (it still needs step 1).\n   - Installed standalone (e.g. copied into `~/.claude/skills/`)? Register the server once: `claude mcp add skill-seekers -- python -m skill_seekers.mcp.server_fastmcp`\n\nIf tools like `scrape_docs` or `package_skill` are not in your tool list, the server is not connected. Tell the user about the two steps above, and use the CLI fallback in the meantime.\n\n## When to Use This Skill\n\nUse this skill when the user:\n- Wants to create an AI skill from a documentation site, GitHub repo, PDF, video, or other source\n- Needs to convert documentation into a format suitable for LLM consumption\n- Wants to update or sync existing skills with their source documentation\n- Needs to export skills to vector databases (Weaviate, Chroma, FAISS, Qdrant)\n- Asks about scraping, converting, or packaging documentation for AI\n\n## Source Type Detection\n\nAutomatically detect the source type from user input:\n\n| Input Pattern | Source Type | Tool to Use |\n|---------------|-------------|-------------|\n| `https://...` (not GitHub/YouTube) | Documentation | `scrape_docs` |\n| `owner/repo` or `github.com/...` | GitHub | `scrape_github` |\n| `*.pdf` | PDF | `scrape_pdf` |\n| YouTube/Vimeo URL or video file | Video | `scrape_video` |\n| Local directory path | Codebase | `scrape_codebase` |\n| `*.ipynb`, `*.html`, `*.yaml` (OpenAPI), `*.adoc`, `*.pptx`, `*.rss`, `*.1`-`.8` | Various | `scrape_generic` |\n| JSON config file | Unified | Use config with `scrape_docs` |\n\n## Recommended Workflow\n\n1. **Detect source type** from the user's input\n2. **Generate or fetch config** using `generate_config` or `fetch_config` if needed\n3. **Estimate scope** with `estimate_pages` for documentation sites\n4. **Scrape the source** using the appropriate scraping tool\n5. **Enhance** with `enhance_skill` if the user wants AI-powered improvements\n6. **Package** with `package_skill` for the target platform\n7. **Export to vector DB** if requested using `export_to_*` tools\n\n## Available MCP Tools\n\n### Config Management\n- `generate_config` — Generate a scraping config from a URL\n- `list_configs` — List available preset configs\n- `validate_config` — Validate a config file\n\n### Scraping (use based on source type)\n- `scrape_docs` — Documentation sites\n- `scrape_github` — GitHub repositories\n- `scrape_pdf` — PDF files\n- `scrape_video` — Video transcripts\n- `scrape_codebase` — Local code analysis\n- `scrape_generic` — Jupyter, HTML, OpenAPI, AsciiDoc, PPTX, RSS, manpage, Confluence, Notion, chat\n\n### Post-processing\n- `enhance_skill` — AI-powered skill enhancement\n- `package_skill` — Package for target platform\n- `upload_skill` — Upload to platform API\n- `install_skill` — End-to-end install workflow\n\n### Advanced\n- `detect_patterns` — Design pattern detection in code\n- `extract_test_examples` — Extract usage examples from tests\n- `build_how_to_guides` — Generate how-to guides from tests\n- `split_config` — Split large configs into focused skills\n- `export_to_weaviate`, `export_to_chroma`, `export_to_faiss`, `export_to_qdrant` — Vector DB export\n\n## CLI Fallback (MCP server not connected)\n\nThe same pipeline is available from the command line (requires `pip install skill-seekers`). Run it with the Bash tool:\n\n```bash\nskill-seekers create <source>                      # auto-detects: URL, owner/repo, ./path, file.pdf, video URL, ...\nskill-seekers package <skill_dir> --target claude  # or gemini/openai/langchain/chroma/...\n```\n\n`create` covers detection, scraping, and building in one step; add `--enhance-level 0` to skip AI enhancement. After it finishes, read the generated `SKILL.md` and summarize what was created.","schemaVersion":1},"repoUrl":"https://github.com/yusufkaraaslan/Skill_Seekers/tree/development/distribution/claude-plugin/skills/skill-builder","tags":["ai-tools","ast-parser","automation","claude-ai","claude-skills","code-analysis","conflict-detection","documentation","documentation-generator","github","github-scraper","mcp"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"Skill_Seekers","audit":{"files":["pyproject.toml","requirements.txt","uv.lock"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-03","message":"`GitPython` is one or two edits away from the popular `ipython`.","surface":"pyproject.toml","evidence":"GitPython","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"anyio@4.11.0 has a known vulnerability: AnyIO process-pool workers can block indefinitely on undrained stderr.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-5p39-cfhj-2xmp · PyPI:anyio@4.11.0","severity":"medium"},{"kind":"dependency","rule":"DP-01","message":"anyio@4.11.0 has a known vulnerability: AnyIO: TLSStream IDNA 2003 host name encoding enables potential TLS certificate spoofing.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-82r6-8w77-94w6 · PyPI:anyio@4.11.0","severity":"critical"},{"kind":"dependency","rule":"DP-01","message":"click@8.3.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2132 · PyPI:click@8.3.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"idna@3.11 has a known vulnerability: Internationalized Domain Names in Applications (IDNA): Specially crafted inputs to idna.encode() can bypass CVE-2024-3651 fix.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-65pc-fj4g-8rjx · PyPI:idna@3.11","severity":"medium"},{"kind":"dependency","rule":"DP-01","message":"idna@3.11 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-215 · PyPI:idna@3.11","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pygments@2.19.2 has a known vulnerability: Pygments has Regular Expression Denial of Service (ReDoS) due to Inefficient Regex for GUID Matching.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-5239-wwwm-4pmq · PyPI:Pygments@2.19.2","severity":"low"},{"kind":"dependency","rule":"DP-01","message":"Pygments@2.19.2 has a known vulnerability: Pygments has Regular Expression Denial of Service (ReDoS) due to Inefficient Regex for GUID Matching.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2987 · PyPI:Pygments@2.19.2","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability: Pillow `BdfFontFile`: `Image.new()` called without `_decompression_bomb_check()` — bomb protection bypass via font loading.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-45hq-cxwh-f6vc · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability: Pillow: WindowsViewer.get_command() OS command injection via unescaped shell path.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-4x4j-2g7c-83w6 · PyPI:Pillow@11.0.0","severity":"medium"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability: Pillow: `FontFile.compile()`: `Image.new()` called without `_decompression_bomb_check()`.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-5x94-69rx-g8h2 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-62p4-gmf7-7g93 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-6r8x-57c9-28j4 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-8v84-f9pq-wr9x · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-9hw9-ch79-4vh6 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-cfh3-3jmp-rvhc · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-fj7v-r99m-22gq · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-jjj6-mw9f-p565 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-phj9-mv4w-65pm · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-pwv6-vv43-88gr · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-r73j-pqj5-w3x7 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-vjc4-5qp5-m44j · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-whj4-6x5x-4v2j · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-wjx4-4jcj-g98j · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-xj96-63gp-2gmr · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-165 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2249 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2250 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2252 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2253 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2254 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2255 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2256 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2257 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2874 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3451 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3453 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3454 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3493 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3494 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3495 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"Pillow@11.0.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3496 · PyPI:Pillow@11.0.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"pytest@8.4.2 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-6w46-j5rx-g56g · PyPI:pytest@8.4.2","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"pytest@8.4.2 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-1845 · PyPI:pytest@8.4.2","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"python-dotenv@1.1.1 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-mf9w-mj56-hr94 · PyPI:python-dotenv@1.1.1","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"python-dotenv@1.1.1 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2270 · PyPI:python-dotenv@1.1.1","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"requests@2.32.5 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-gc5v-m9x4-r6x2 · PyPI:requests@2.32.5","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"requests@2.32.5 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-2275 · PyPI:requests@2.32.5","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"soupsieve@2.8 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-2wc2-fm75-p42x · PyPI:soupsieve@2.8","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"soupsieve@2.8 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-836r-79rf-4m37 · PyPI:soupsieve@2.8","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"soupsieve@2.8 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-gjv8-xp57-g29c · PyPI:soupsieve@2.8","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"soupsieve@2.8 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-j934-xhv5-fg8f · PyPI:soupsieve@2.8","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"soupsieve@2.8 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3071 · PyPI:soupsieve@2.8","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"soupsieve@2.8 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-3072 · PyPI:soupsieve@2.8","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-2xpw-w6gg-jr37 · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-38jv-5279-wg99 · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-gm62-xv2j-4w53 · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"GHSA-qccp-gfcp-xxvc · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-141 · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-1994 · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-1996 · PyPI:urllib3@2.5.0","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"urllib3@2.5.0 has a known vulnerability.","surface":"pyproject.toml, requirements.txt, uv.lock","evidence":"PYSEC-2026-1998 · PyPI:urllib3@2.5.0","severity":"high"}],"packages":63,"auditedAt":"2026-09-25T10:52:13.469Z","lockfiles":["uv.lock"]},"forks":1533,"owner":"yusufkaraaslan","stars":15027,"topics":["ai-tools","ast-parser","automation","claude-ai","claude-skills","code-analysis","conflict-detection","documentation","documentation-generator","github","github-scraper","mcp","mcp-server","multi-source","ocr","pdf","python","web-scraping"],"license":"MIT","fullName":"yusufkaraaslan/Skill_Seekers","homepage":"https://skillseekersweb.com/","language":"Python","pushedAt":"2026-09-20T16:14:08Z","avatarUrl":"https://avatars.githubusercontent.com/u/11597362?v=4","crawledAt":"2026-09-25T10:52:08.347Z","openIssues":47,"manifestFile":"SKILL.md","manifestPath":"distribution/claude-plugin/skills/skill-builder/SKILL.md","defaultBranch":"development"},"readme":"# Skill Builder\n\nThis skill uses the Skill Seekers MCP server, which provides 40 tools for converting knowledge sources into AI-ready skills. If the MCP tools are not available, use the CLI fallback at the bottom of this file instead — do not stop.\n\n## Prerequisites\n\nThe MCP tools below only work when the Skill Seekers MCP server is connected:\n\n1. Install the package: `pip install \"skill-seekers[mcp]\"`\n2. Connect the server:\n   - Installed as the Skill Seekers plugin? Nothing to do — the plugin's bundled `.mcp.json` starts the server automatically (it still needs step 1).\n   - Installed standalone (e.g. copied into `~/.claude/skills/`)? Register the server once: `claude mcp add skill-seekers -- python -m skill_seekers.mcp.server_fastmcp`\n\nIf tools like `scrape_docs` or `package_skill` are not in your tool list, the server is not connected. Tell the user about the two steps above, and use the CLI fallback in the meantime.\n\n## When to Use This Skill\n\nUse this skill when the user:\n- Wants to create an AI skill from a documentation site, GitHub repo, PDF, video, or other source\n- Needs to convert documentation into a format suitable for LLM consumption\n- Wants to update or sync existing skills with their source documentation\n- Needs to export skills to vector databases (Weaviate, Chroma, FAISS, Qdrant)\n- Asks about scraping, converting, or packaging documentation for AI\n\n## Source Type Detection\n\nAutomatically detect the source type from user input:\n\n| Input Pattern | Source Type | Tool to Use |\n|---------------|-------------|-------------|\n| `https://...` (not GitHub/YouTube) | Documentation | `scrape_docs` |\n| `owner/repo` or `github.com/...` | GitHub | `scrape_github` |\n| `*.pdf` | PDF | `scrape_pdf` |\n| YouTube/Vimeo URL or video file | Video | `scrape_video` |\n| Local directory path | Codebase | `scrape_codebase` |\n| `*.ipynb`, `*.html`, `*.yaml` (OpenAPI), `*.adoc`, `*.pptx`, `*.rss`, `*.1`-`.8` | Various | `scrape_generic` |\n| JSON config file | Unified | Use config with `scrape_docs` |\n\n## Recommended Workflow\n\n1. **Detect source type** from the user's input\n2. **Generate or fetch config** using `generate_config` or `fetch_config` if needed\n3. **Estimate scope** with `estimate_pages` for documentation sites\n4. **Scrape the source** using the appropriate scraping tool\n5. **Enhance** with `enhance_skill` if the user wants AI-powered improvements\n6. **Package** with `package_skill` for the target platform\n7. **Export to vector DB** if requested using `export_to_*` tools\n\n## Available MCP Tools\n\n### Config Management\n- `generate_config` — Generate a scraping config from a URL\n- `list_configs` — List available preset configs\n- `validate_config` — Validate a config file\n\n### Scraping (use based on source type)\n- `scrape_docs` — Documentation sites\n- `scrape_github` — GitHub repositories\n- `scrape_pdf` — PDF files\n- `scrape_video` — Video transcripts\n- `scrape_codebase` — Local code analysis\n- `scrape_generic` — Jupyter, HTML, OpenAPI, AsciiDoc, PPTX, RSS, manpage, Confluence, Notion, chat\n\n### Post-processing\n- `enhance_skill` — AI-powered skill enhancement\n- `package_skill` — Package for target platform\n- `upload_skill` — Upload to platform API\n- `install_skill` — End-to-end install workflow\n\n### Advanced\n- `detect_patterns` — Design pattern detection in code\n- `extract_test_examples` — Extract usage examples from tests\n- `build_how_to_guides` — Generate how-to guides from tests\n- `split_config` — Split large configs into focused skills\n- `export_to_weaviate`, `export_to_chroma`, `export_to_faiss`, `export_to_qdrant` — Vector DB export\n\n## CLI Fallback (MCP server not connected)\n\nThe same pipeline is available from the command line (requires `pip install skill-seekers`). Run it with the Bash tool:\n\n```bash\nskill-seekers create <source>                      # auto-detects: URL, owner/repo, ./path, file.pdf, video URL, ...\nskill-seekers package <skill_dir> --target claude  # or gemini/openai/langchain/chroma/...\n```\n\n`create` cov","createdAt":"2026-09-25T10:52:13.511Z","updatedAt":"2026-09-25T10:52:13.511Z"},{"id":"cmugwhsew01gnqu06au6h66y7","slug":"glitternetwork-pinme-pinme-auth","name":"pinme-auth","description":"Use when a PinMe project (Worker TypeScript) needs to integrate user authentication — creating email/password users, verifying id_tokens, querying user info, or listing users via Identity Platform auth proxy APIs.","authorId":"gh:glitternetwork","authorName":"glitternetwork","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":3745,"pricePerCall":0,"manifest":{"name":"pinme-auth","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Use when a PinMe project (Worker TypeScript) needs to integrate user authentication — creating email/password users, verifying id_tokens, querying user info, or listing users via Identity Platform auth proxy APIs.","permissions":[],"systemPrompt":"# PinMe Worker Auth API Integration\n\nGuides how to call PinMe platform's Identity Platform auth proxy APIs in a PinMe Worker (TypeScript).\n\n## Environment Variables\n\n```typescript\n// backend/src/worker.ts\nexport interface Env {\n  DB: D1Database;\n  API_KEY: string;       // 项目 API Key — 用于所有 auth 接口认证\n  PROJECT_NAME: string;  // 项目名 — 所有 auth 接口必须同时传递\n  BASE_URL?: string;     // 可选，默认 https://pinme.cloud\n}\n```\n\n> `API_KEY` 和 `PROJECT_NAME` 是所有 auth 接口的必填凭证，缺一不可。\n\n---\n\n## 认证方式（所有接口通用）\n\n| 参数 | 传递方式 | 必填 | 说明 |\n|------|---------|------|------|\n| `X-API-Key` | 请求头 | 是 | 项目 API Key |\n| `project_name` | Query 参数 | 是 | 必须与 `X-API-Key` 对应同一个项目 |\n\n服务端会先校验这两个字段是否匹配同一个项目，再从项目配置中取出 `tenant_id`，然后转调 Identity Platform。\n\n---\n\n## 通用错误\n\n| 场景 | HTTP | `data.error` |\n|------|------|-------------|\n| 缺少 `X-API-Key` | 401 | `X-API-Key header is required` |\n| 缺少 `project_name` | 400 | `project_name is required` |\n| API Key 和项目不匹配 | 401 | `Invalid API key or project name` |\n| 项目未配置认证租户 | 400 | `Auth service not configured for this project` |\n\n---\n\n## 通用 TypeScript 类型\n\n```typescript\ntype ApiEnvelope<T> = {\n  code: number   // 200=成功，其他=失败\n  msg: string    // \"ok\" | \"fail\" | \"invalid param\"\n  data: T\n}\n\ntype ApiErrorData = { error?: string }\n\ntype UserInfo = {\n  uid: string\n  email: string\n  display_name: string\n  photo_url?: string\n  disabled: boolean\n  email_verified: boolean\n}\n```\n\n---\n\n## API 1: 创建用户\n\n**Endpoint:** `POST {BASE_URL}/api/v1/auth/create_user?project_name={project_name}`\n\n仅用于邮箱密码注册。成功时用户已创建且验证邮件已发出；失败时自动回滚，不会留下僵尸账号。\n\n> 创建成功后用户默认仍是\"未验证\"状态，需点击邮件验证链接后，`verify_token` 才能通过校验。\n\n### 请求体\n\n```json\n{ \"email\": \"alice@example.com\", \"password\": \"Test@12345678\", \"display_name\": \"Alice\" }\n```\n\n| 字段 | 类型 | 必填 |\n|------|------|------|\n| `email` | string | 是 |\n| `password` | string | 是 |\n| `display_name` | string | 否 |\n\n### 错误\n\n| 场景 | HTTP | `data.error` |\n|------|------|-------------|\n| 缺少 email/password | 400 | `email and password are required` |\n| 上游创建失败 | 502 | `Failed to create user` |\n| 发送验证邮件失败 | 500 | `Failed to send verification email. Please try again.` |\n\n### TypeScript 示例\n\n```typescript\nasync function createAuthUser(\n  env: Env,\n  payload: { email: string; password: string; display_name?: string }\n): Promise<{ user?: UserInfo; error?: string }> {\n  const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';\n  const resp = await fetch(\n    `${baseUrl}/api/v1/auth/create_user?project_name=${encodeURIComponent(env.PROJECT_NAME)}`,\n    {\n      method: 'POST',\n      headers: { 'X-API-Key': env.API_KEY, 'Content-Type': 'application/json' },\n      body: JSON.stringify(payload),\n    }\n  );\n  const result = await resp.json() as ApiEnvelope<UserInfo | ApiErrorData>;\n  if (!resp.ok || result.code !== 200) {\n    return { error: (result.data as ApiErrorData)?.error ?? result.msg };\n  }\n  return { user: result.data as UserInfo };\n}\n```\n\n---\n\n## API 2: 校验 id_token\n\n**Endpoint:** `POST {BASE_URL}/api/v1/auth/verify_token?project_name={project_name}`\n\n校验前端登录后拿到的 `id_token`（邮箱密码或 Google 登录均适用）。\n\n**注意：** token 合法但邮箱未验证时返回 `403`，不是 `401`。\n\n### 请求体\n\n```json\n{ \"id_token\": \"eyJhbGciOiJSUzI1NiIsImtpZCI6...\" }\n```\n\n### 成功响应 data\n\n```typescript\ntype VerifyTokenData = {\n  uid: string\n  email?: string\n  tenant_id: string\n  claims: Record<string, unknown>\n}\n```\n\n### 错误\n\n| 场景 | HTTP | `data.error` |\n|------|------|-------------|\n| 缺少 `id_token` | 400 | `id_token is required` |\n| token 无效或过期 | 401 | `Invalid or expired token` |\n| 邮箱未验证 | 403 | `Email not verified. Please check your inbox and verify your email address.` |\n\n### TypeScript 示例\n\n```typescript\nasync function verifyAuthToken(\n  env: Env,\n  idToken: string\n): Promise<{ uid?: string; email?: string; error?: string; emailNotVerified?: boolean }> {\n  const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';\n  const resp = await fetch(\n    `${baseUrl}/api/v1/auth/verify_token?project_name=${encodeURIComponent(env.PROJECT_NAME)}`,\n    {\n      method: 'POST',\n      headers: { 'X-API-Key': env.API_KEY, 'Content-Type': 'application/json' },\n      body: JSON.stringify({ id_token: idToken }),\n    }\n  );\n  const result = await resp.json() as ApiEnvelope<VerifyTokenData | ApiErrorData>;\n  if (!resp.ok || result.code !== 200) {\n    const error = (result.data as ApiErrorData)?.error ?? result.msg;\n    return { error, emailNotVerified: resp.status === 403 };\n  }\n  const data = result.data as VerifyTokenData;\n  return { uid: data.uid, email: data.email };\n}\n```\n\n---\n\n## API 3: 查询单个用户\n\n**Endpoint:** `GET {BASE_URL}/api/v1/auth/user?project_name={project_name}&uid={uid}`\n\n### 错误\n\n| 场景 | HTTP | `data.error` |\n|------|------|-------------|\n| 缺少 `uid` | 400 | `uid is required` |\n| 用户不存在 | 404 | `User not found` |\n| 上游查询失败 | 502 | `Failed to get user` |\n\n### TypeScript 示例\n\n```typescript\nasync function getAuthUser(env: Env, uid: string): Promise<{ user?: UserInfo; error?: string }> {\n  const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';\n  const resp = await fetch(\n    `${baseUrl}/api/v1/auth/user?project_name=${encodeURIComponent(env.PROJECT_NAME)}&uid=${encodeURIComponent(uid)}`,\n    { method: 'GET', headers: { 'X-API-Key': env.API_KEY } }\n  );\n  const result = await resp.json() as ApiEnvelope<UserInfo | ApiErrorData>;\n  if (!resp.ok || result.code !== 200) {\n    return { error: (result.data as ApiErrorData)?.error ?? result.msg };\n  }\n  return { user: result.data as UserInfo };\n}\n```\n\n---\n\n## API 4: 列出用户（分页）\n\n**Endpoint:** `GET {BASE_URL}/api/v1/auth/list_users?project_name={project_name}`\n\n默认 `max_results=100`，最大 `1000`。通过 `next_page_token` 循环翻页。\n\n### Query 参数\n\n| 参数 | 必填 | 说明 |\n|------|------|------|\n| `project_name` | 是 | 项目名 |\n| `page_token` | 否 | 分页游标 |\n| `max_results` | 否 | 每页数量，1–1000 |\n\n### TypeScript 示例\n\n```typescript\nasync function listAuthUsers(\n  env: Env,\n  options: { pageToken?: string; maxResults?: number } = {}\n): Promise<{ users?: UserInfo[]; nextPageToken?: string; error?: string }> {\n  const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';\n  const url = new URL('/api/v1/auth/list_users', baseUrl);\n  url.searchParams.set('project_name', env.PROJECT_NAME);\n  if (options.pageToken) url.searchParams.set('page_token', options.pageToken);\n  if (options.maxResults) url.searchParams.set('max_results', String(options.maxResults));\n\n  const resp = await fetch(url.toString(), { method: 'GET', headers: { 'X-API-Key': env.API_KEY } });\n  const result = await resp.json() as ApiEnvelope<{ users: UserInfo[]; next_page_token?: string } | ApiErrorData>;\n  if (!resp.ok || result.code !== 200) {\n    return { error: (result.data as ApiErrorData)?.error ?? result.msg };\n  }\n  const data = result.data as { users: UserInfo[]; next_page_token?: string };\n  return { users: data.users, nextPageToken: data.next_page_token };\n}\n\n// 批量遍历所有用户示例\nasync function* iterAllUsers(env: Env) {\n  let pageToken: string | undefined;\n  do {\n    const { users, nextPageToken, error } = await listAuthUsers(env, { pageToken, maxResults: 1000 });\n    if (error) throw new Error(error);\n    for (const user of users ?? []) yield user;\n    pageToken = nextPageToken;\n  } while (pageToken);\n}\n```\n\n---\n\n## 前端集成（Firebase Auth）\n\n`create_worker` 响应中包含 `public_client_config`，前端用它初始化 Firebase Auth SDK。\n\n### 两种 api_key 区分\n\n| 字段 | 用途 | 是否可暴露到浏览器 |\n|------|------|-----------------|\n| `data.api_key` | 项目 API Key，调用本文所有代理接口 | **不能**，只给 Worker/服务端 |\n| `data.public_client_config.auth_api_key` | Firebase Web API Key，初始化前端登录 SDK | 可以 |\n\n### public_client_config 字段说明\n\n| 字段 | 前端用途 |\n|------|---------|\n| `public_client_config.auth_api_key` | `initializeApp({ apiKey })` |\n| `public_client_config.auth_domain` | `initializeApp({ authDomain })` |\n| `public_client_config.auth_project_id` | `initializeApp({ projectId })` |\n| `public_client_config.tenant_id` | `auth.tenantId = config.tenant_id`（必须设置，否则 token 归属错误） |\n\n### 前端 TypeScript 示例\n\n```typescript\nimport { initializeApp } from 'firebase/app'\nimport {\n  type Auth,\n  getAuth,\n  GoogleAuthProvider,\n  signInWithEmailAndPassword,\n  signInWithPopup,\n} from 'firebase/auth'\n\ntype PublicClientConfig = {\n  tenant_id: string\n  auth_api_key: string\n  auth_domain: string\n  auth_project_id: string\n}\n\nexport function createProjectAuth(config: PublicClientConfig): Auth {\n  const app = initializeApp({\n    apiKey: config.auth_api_key,\n    authDomain: config.auth_domain,\n    projectId: config.auth_project_id,\n  })\n  const auth = getAuth(app)\n  auth.tenantId = config.tenant_id  // 必须设置，确保 token 归属正确租户\n  return auth\n}\n\n// 邮箱密码登录，返回 id_token\nexport async function loginWithEmail(auth: Auth, email: string, password: string): Promise<string> {\n  const credential = await signInWithEmailAndPassword(auth, email, password)\n  return credential.user.getIdToken()\n}\n\n// Google 登录，返回 id_token\nexport async function loginWithGoogle(auth: Auth): Promise<string> {\n  const credential = await signInWithPopup(auth, new GoogleAuthProvider())\n  return credential.user.getIdToken()\n}\n\n// 用法示例\n// pinme create 会自动将 public_client_config 写入 frontend/src/utils/config.ts\nimport { public_client_config } from '../utils/config'\n\nconst auth = createProjectAuth(public_client_config)\nconst idToken = await loginWithGoogle(auth)\n// 然后把 idToken 发给自己的 Worker，由 Worker 调用 verify_token\n```\n\n> 前端只负责登录和拿 `id_token`，不要直接持有项目 `api_key`。`verify_token` 必须由 Worker/服务端代调。\n> `frontend/src/utils/config.ts` 由 `pinme create` 自动生成，无需手动创建。\n\n---\n\n## 典型调用链路\n\n**邮箱密码注册流程：**\n1. `create_user` → 创建用户并发出验证邮件\n2. 用户点击邮件链接完成验证\n3. 前端登录拿到 `id_token`\n4. `verify_token` → 校验 token，取得 `uid`\n5. 需要时再调 `getAuthUser` 读取完整用户信息\n\n**Google 登录流程：**\n1. 前端完成 Google Sign-In，拿到 `id_token`\n2. `verify_token` → 校验 token（无需调用 `create_user`）\n\n---\n\n## 易错点\n\n| 错误 | 正确做法 |\n|------|---------|\n| 只传 `X-API-Key`，忘记 `project_name` | 每个请求都要同时带 `X-API-Key` header 和 `project_name` query |\n| `verify_token` 返回 403 时当 token 失效处理 | 403 = 邮箱未验证，提示用户检查邮箱；401 才是 token 失效 |\n| `create_user` 成功就认为邮箱已验证 | 创建成功只代表验证邮件已发，用户必须点击后才算验证 |\n| `list_users` 只取第一页 | 有 `next_page_token` 时需继续请求，直到为空 |\n| 成功判断只看 `resp.ok` | 同时判断 `resp.ok && result.code === 200` |","schemaVersion":1},"repoUrl":"https://github.com/glitternetwork/pinme/tree/main/skills/pinme-auth","tags":["ai-tools","claude-code-skill","claude-skills","deployment","deployment-tools","frontend","frontend-deployment","hosting","serverless","skills","static-site","static-site-deploy"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pinme","audit":{"files":["package-lock.json","package.json","pnpm-lock.yaml"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip: Uncontrolled memory allocation via the declared uncompressed size (DoS).","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-7q85-xj36-vmfc · npm:adm-zip@0.5.17","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip extraction follows destination symlinks, allowing arbitrary file overwrite.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-vwc7-r8mq-g2x9 · npm:adm-zip@0.5.17","severity":"medium"},{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip: Crafted ZIP file triggers 4GB memory allocation.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-xcpc-8h2w-3j85 · npm:adm-zip@0.5.17","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"uuid@9.0.1 has a known vulnerability: uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-w5hq-g745-h8pq · npm:uuid@9.0.1","severity":"medium"}],"packages":16,"auditedAt":"2026-09-25T11:51:56.672Z","lockfiles":["package-lock.json","pnpm-lock.yaml"]},"forks":277,"owner":"glitternetwork","stars":3745,"topics":["ai-tools","claude-code-skill","claude-skills","deployment","deployment-tools","frontend","frontend-deployment","hosting","serverless","skills","static-site","static-site-deploy","static-site-hosting","web-hosting","zero-configuration"],"license":"MIT","fullName":"glitternetwork/pinme","homepage":"https://pinme.eth.limo","language":"TypeScript","pushedAt":"2026-09-12T05:23:49Z","avatarUrl":"https://avatars.githubusercontent.com/u/102277171?v=4","crawledAt":"2026-09-25T11:51:44.477Z","openIssues":7,"manifestFile":"SKILL.md","manifestPath":"skills/pinme-auth/SKILL.md","defaultBranch":"main"},"readme":"# PinMe Worker Auth API Integration\n\nGuides how to call PinMe platform's Identity Platform auth proxy APIs in a PinMe Worker (TypeScript).\n\n## Environment Variables\n\n```typescript\n// backend/src/worker.ts\nexport interface Env {\n  DB: D1Database;\n  API_KEY: string;       // 项目 API Key — 用于所有 auth 接口认证\n  PROJECT_NAME: string;  // 项目名 — 所有 auth 接口必须同时传递\n  BASE_URL?: string;     // 可选，默认 https://pinme.cloud\n}\n```\n\n> `API_KEY` 和 `PROJECT_NAME` 是所有 auth 接口的必填凭证，缺一不可。\n\n---\n\n## 认证方式（所有接口通用）\n\n| 参数 | 传递方式 | 必填 | 说明 |\n|------|---------|------|------|\n| `X-API-Key` | 请求头 | 是 | 项目 API Key |\n| `project_name` | Query 参数 | 是 | 必须与 `X-API-Key` 对应同一个项目 |\n\n服务端会先校验这两个字段是否匹配同一个项目，再从项目配置中取出 `tenant_id`，然后转调 Identity Platform。\n\n---\n\n## 通用错误\n\n| 场景 | HTTP | `data.error` |\n|------|------|-------------|\n| 缺少 `X-API-Key` | 401 | `X-API-Key header is required` |\n| 缺少 `project_name` | 400 | `project_name is required` |\n| API Key 和项目不匹配 | 401 | `Invalid API key or project name` |\n| 项目未配置认证租户 | 400 | `Auth service not configured for this project` |\n\n---\n\n## 通用 TypeScript 类型\n\n```typescript\ntype ApiEnvelope<T> = {\n  code: number   // 200=成功，其他=失败\n  msg: string    // \"ok\" | \"fail\" | \"invalid param\"\n  data: T\n}\n\ntype ApiErrorData = { error?: string }\n\ntype UserInfo = {\n  uid: string\n  email: string\n  display_name: string\n  photo_url?: string\n  disabled: boolean\n  email_verified: boolean\n}\n```\n\n---\n\n## API 1: 创建用户\n\n**Endpoint:** `POST {BASE_URL}/api/v1/auth/create_user?project_name={project_name}`\n\n仅用于邮箱密码注册。成功时用户已创建且验证邮件已发出；失败时自动回滚，不会留下僵尸账号。\n\n> 创建成功后用户默认仍是\"未验证\"状态，需点击邮件验证链接后，`verify_token` 才能通过校验。\n\n### 请求体\n\n```json\n{ \"email\": \"alice@example.com\", \"password\": \"Test@12345678\", \"display_name\": \"Alice\" }\n```\n\n| 字段 | 类型 | 必填 |\n|------|------|------|\n| `email` | string | 是 |\n| `password` | string | 是 |\n| `display_name` | string | 否 |\n\n### 错误\n\n| 场景 | HTTP | `data.error` |\n|------|------|-------------|\n| 缺少 email/password | 400 | `email and password are required` |\n| 上游创建失败 | 502 | `Failed to create user` |\n| 发送验证邮件失败 | 500 | `Failed to send verification email. Please try again.` |\n\n### TypeScript 示例\n\n```typescript\nasync function createAuthUser(\n  env: Env,\n  payload: { email: string; password: string; display_name?: string }\n): Promise<{ user?: UserInfo; error?: string }> {\n  const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';\n  const resp = await fetch(\n    `${baseUrl}/api/v1/auth/create_user?project_name=${encodeURIComponent(env.PROJECT_NAME)}`,\n    {\n      method: 'POST',\n      headers: { 'X-API-Key': env.API_KEY, 'Content-Type': 'application/json' },\n      body: JSON.stringify(payload),\n    }\n  );\n  const result = await resp.json() as ApiEnvelope<UserInfo | ApiErrorData>;\n  if (!resp.ok || result.code !== 200) {\n    return { error: (result.data as ApiErrorData)?.error ?? result.msg };\n  }\n  return { user: result.data as UserInfo };\n}\n```\n\n---\n\n## API 2: 校验 id_token\n\n**Endpoint:** `POST {BASE_URL}/api/v1/auth/verify_token?project_name={project_name}`\n\n校验前端登录后拿到的 `id_token`（邮箱密码或 Google 登录均适用）。\n\n**注意：** token 合法但邮箱未验证时返回 `403`，不是 `401`。\n\n### 请求体\n\n```json\n{ \"id_token\": \"eyJhbGciOiJSUzI1NiIsImtpZCI6...\" }\n```\n\n### 成功响应 data\n\n```typescript\ntype VerifyTokenData = {\n  uid: string\n  email?: string\n  tenant_id: string\n  claims: Record<string, unknown>\n}\n```\n\n### 错误\n\n| 场景 | HTTP | `data.error` |\n|------|------|-------------|\n| 缺少 `id_token` | 400 | `id_token is required` |\n| token 无效或过期 | 401 | `Invalid or expired token` |\n| 邮箱未验证 | 403 | `Email not verified. Please check your inbox and verify your email address.` |\n\n### TypeScript 示例\n\n```typescript\nasync function verifyAuthToken(\n  env: Env,\n  idToken: string\n): Promise<{ uid?: string; email?: string; error?: string; emailNotVerified?: boolean }> {\n  const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';\n  const resp = await fetch(\n    `${baseUrl}/api/v1/auth/verify_token?project_name=${encodeURIComponent(env.PROJECT_NAME)}`,\n    {\n      method: 'POST',\n      headers: { 'X-API-Key': env.API_KEY, 'Content-Type': 'applicati","createdAt":"2026-09-25T11:51:56.696Z","updatedAt":"2026-09-25T11:51:56.696Z"},{"id":"cmugwhsf701gqqu06a0r4op12","slug":"glitternetwork-pinme-pinme-email","name":"pinme-email","description":"Use this skill when a PinMe project (Worker TypeScript) needs to integrate email sending (send_email). Guides AI to generate correct Worker TS code.","authorId":"gh:glitternetwork","authorName":"glitternetwork","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":3745,"pricePerCall":0,"manifest":{"name":"pinme-email","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Use this skill when a PinMe project (Worker TypeScript) needs to integrate email sending (send_email). Guides AI to generate correct Worker TS code.","permissions":[],"systemPrompt":"# PinMe Worker Email API Integration\n\nGuides how to call PinMe platform's email sending API in a PinMe Worker (TypeScript).\n\n## Environment Variables\n\nThe following environment variables are automatically injected when the Worker is created — no manual configuration needed:\n\n```typescript\n// backend/src/worker.ts\nexport interface Env {\n  DB: D1Database;\n  API_KEY: string;      // Project API Key — used for send_email authentication\n  BASE_URL?: string;    // Optional override for PinMe API base URL, defaults to https://pinme.cloud\n}\n```\n\n> `API_KEY` is the sole credential for the Worker to call PinMe platform APIs. When `BASE_URL` is not set, it defaults to `https://pinme.cloud`.\n\n---\n\n## Send Email API\n\n**Endpoint:** `POST {BASE_URL}/api/v4/send_email`\n**Authentication:** `X-API-Key` header (using `env.API_KEY`)\n**Sender:** Automatically set to `{project_name}@pinme.cloud`\n\n### Request Format\n\n```json\n{\n  \"to\": \"user@example.com\",\n  \"subject\": \"Your verification code\",\n  \"html\": \"<p>Your code is <strong>123456</strong></p>\"\n}\n```\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `to` | string | Yes | Recipient email address |\n| `subject` | string | Yes | Email subject |\n| `html` | string | Yes | HTML body |\n\n### Response Format\n\n**Success (200):**\n```json\n{ \"code\": 200, \"msg\": \"ok\", \"data\": { \"ok\": true } }\n```\n\n**Errors:**\n\n| HTTP Status | Meaning | data.error Example |\n|-------------|---------|-------------------|\n| 401 | API Key missing or invalid | `\"X-API-Key header is required\"` / `\"Invalid API key\"` |\n| 400 | Parameter validation failed | `\"Invalid email address\"` / `\"Subject is required\"` |\n| 500 | Email service error | `\"Failed to send email\"` |\n\n### Worker Example Code\n\n```typescript\nasync function sendEmail(env: Env, to: string, subject: string, html: string): Promise<{ ok: boolean; error?: string }> {\n  const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';\n  const resp = await fetch(`${baseUrl}/api/v4/send_email`, {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json',\n      'X-API-Key': env.API_KEY,\n    },\n    body: JSON.stringify({ to, subject, html }),\n  });\n\n  const result = await resp.json() as { code: number; msg: string; data?: { ok?: boolean; error?: string } };\n\n  if (resp.status !== 200 || result.code !== 200) {\n    return { ok: false, error: result.data?.error || result.msg || 'Unknown error' };\n  }\n  return { ok: true };\n}\n\n// Usage in routes\nasync function handleSendVerification(request: Request, env: Env): Promise<Response> {\n  const { email } = await request.json() as { email: string };\n  const code = Math.random().toString().slice(2, 8);\n\n  const result = await sendEmail(env, email, 'Verification Code',\n    `<p>Your code is <strong>${code}</strong></p>`);\n\n  if (!result.ok) {\n    return json({ error: result.error }, 500);\n  }\n  return json({ ok: true });\n}\n```\n\n---\n\n## Error Handling Pattern\n\nPinMe platform API unified response format:\n\n```typescript\ninterface PinmeResponse<T = unknown> {\n  code: number;   // 200=success, other=failure\n  msg: string;    // \"ok\" | \"error\" | \"invalid params\"\n  data?: T;       // Business data on success, may contain { error: string } on failure\n}\n```\n\n### Recommended Unified Error Handler\n\n```typescript\nasync function callPinmeAPI<T>(url: string, apiKey: string, body: unknown): Promise<{ data?: T; error?: string }> {\n  let resp: Response;\n  try {\n    resp = await fetch(url, {\n      method: 'POST',\n      headers: { 'Content-Type': 'application/json', 'X-API-Key': apiKey },\n      body: JSON.stringify(body),\n    });\n  } catch {\n    return { error: 'Network error' };\n  }\n\n  if (!resp.ok) {\n    try {\n      const err = await resp.json() as PinmeResponse;\n      return { error: err.data && typeof err.data === 'object' && 'error' in err.data\n        ? (err.data as { error: string }).error\n        : err.msg || `HTTP ${resp.status}` };\n    } catch {\n      return { error: `HTTP ${resp.status}` };\n    }\n  }\n\n  const result = await resp.json() as PinmeResponse<T>;\n  if (result.code !== 200) {\n    return { error: result.data && typeof result.data === 'object' && 'error' in result.data\n      ? (result.data as { error: string }).error\n      : result.msg };\n  }\n  return { data: result.data as T };\n}\n```\n\n### Usage Example\n\n```typescript\nconst baseUrl = env.BASE_URL ?? 'https://pinme.cloud';\n\n// Send email\nconst emailResult = await callPinmeAPI<{ ok: boolean }>(\n  `${baseUrl}/api/v4/send_email`, env.API_KEY,\n  { to: 'user@example.com', subject: 'Hello', html: '<p>Hi</p>' },\n);\nif (emailResult.error) return json({ error: emailResult.error }, 500);\n```","schemaVersion":1},"repoUrl":"https://github.com/glitternetwork/pinme/tree/main/skills/pinme-email","tags":["ai-tools","claude-code-skill","claude-skills","deployment","deployment-tools","frontend","frontend-deployment","hosting","serverless","skills","static-site","static-site-deploy"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pinme","audit":{"files":["package-lock.json","package.json","pnpm-lock.yaml"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip: Uncontrolled memory allocation via the declared uncompressed size (DoS).","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-7q85-xj36-vmfc · npm:adm-zip@0.5.17","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip extraction follows destination symlinks, allowing arbitrary file overwrite.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-vwc7-r8mq-g2x9 · npm:adm-zip@0.5.17","severity":"medium"},{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip: Crafted ZIP file triggers 4GB memory allocation.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-xcpc-8h2w-3j85 · npm:adm-zip@0.5.17","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"uuid@9.0.1 has a known vulnerability: uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-w5hq-g745-h8pq · npm:uuid@9.0.1","severity":"medium"}],"packages":16,"auditedAt":"2026-09-25T11:51:56.672Z","lockfiles":["package-lock.json","pnpm-lock.yaml"]},"forks":277,"owner":"glitternetwork","stars":3745,"topics":["ai-tools","claude-code-skill","claude-skills","deployment","deployment-tools","frontend","frontend-deployment","hosting","serverless","skills","static-site","static-site-deploy","static-site-hosting","web-hosting","zero-configuration"],"license":"MIT","fullName":"glitternetwork/pinme","homepage":"https://pinme.eth.limo","language":"TypeScript","pushedAt":"2026-09-12T05:23:49Z","avatarUrl":"https://avatars.githubusercontent.com/u/102277171?v=4","crawledAt":"2026-09-25T11:51:44.477Z","openIssues":7,"manifestFile":"SKILL.md","manifestPath":"skills/pinme-email/SKILL.md","defaultBranch":"main"},"readme":"# PinMe Worker Email API Integration\n\nGuides how to call PinMe platform's email sending API in a PinMe Worker (TypeScript).\n\n## Environment Variables\n\nThe following environment variables are automatically injected when the Worker is created — no manual configuration needed:\n\n```typescript\n// backend/src/worker.ts\nexport interface Env {\n  DB: D1Database;\n  API_KEY: string;      // Project API Key — used for send_email authentication\n  BASE_URL?: string;    // Optional override for PinMe API base URL, defaults to https://pinme.cloud\n}\n```\n\n> `API_KEY` is the sole credential for the Worker to call PinMe platform APIs. When `BASE_URL` is not set, it defaults to `https://pinme.cloud`.\n\n---\n\n## Send Email API\n\n**Endpoint:** `POST {BASE_URL}/api/v4/send_email`\n**Authentication:** `X-API-Key` header (using `env.API_KEY`)\n**Sender:** Automatically set to `{project_name}@pinme.cloud`\n\n### Request Format\n\n```json\n{\n  \"to\": \"user@example.com\",\n  \"subject\": \"Your verification code\",\n  \"html\": \"<p>Your code is <strong>123456</strong></p>\"\n}\n```\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `to` | string | Yes | Recipient email address |\n| `subject` | string | Yes | Email subject |\n| `html` | string | Yes | HTML body |\n\n### Response Format\n\n**Success (200):**\n```json\n{ \"code\": 200, \"msg\": \"ok\", \"data\": { \"ok\": true } }\n```\n\n**Errors:**\n\n| HTTP Status | Meaning | data.error Example |\n|-------------|---------|-------------------|\n| 401 | API Key missing or invalid | `\"X-API-Key header is required\"` / `\"Invalid API key\"` |\n| 400 | Parameter validation failed | `\"Invalid email address\"` / `\"Subject is required\"` |\n| 500 | Email service error | `\"Failed to send email\"` |\n\n### Worker Example Code\n\n```typescript\nasync function sendEmail(env: Env, to: string, subject: string, html: string): Promise<{ ok: boolean; error?: string }> {\n  const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';\n  const resp = await fetch(`${baseUrl}/api/v4/send_email`, {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json',\n      'X-API-Key': env.API_KEY,\n    },\n    body: JSON.stringify({ to, subject, html }),\n  });\n\n  const result = await resp.json() as { code: number; msg: string; data?: { ok?: boolean; error?: string } };\n\n  if (resp.status !== 200 || result.code !== 200) {\n    return { ok: false, error: result.data?.error || result.msg || 'Unknown error' };\n  }\n  return { ok: true };\n}\n\n// Usage in routes\nasync function handleSendVerification(request: Request, env: Env): Promise<Response> {\n  const { email } = await request.json() as { email: string };\n  const code = Math.random().toString().slice(2, 8);\n\n  const result = await sendEmail(env, email, 'Verification Code',\n    `<p>Your code is <strong>${code}</strong></p>`);\n\n  if (!result.ok) {\n    return json({ error: result.error }, 500);\n  }\n  return json({ ok: true });\n}\n```\n\n---\n\n## Error Handling Pattern\n\nPinMe platform API unified response format:\n\n```typescript\ninterface PinmeResponse<T = unknown> {\n  code: number;   // 200=success, other=failure\n  msg: string;    // \"ok\" | \"error\" | \"invalid params\"\n  data?: T;       // Business data on success, may contain { error: string } on failure\n}\n```\n\n### Recommended Unified Error Handler\n\n```typescript\nasync function callPinmeAPI<T>(url: string, apiKey: string, body: unknown): Promise<{ data?: T; error?: string }> {\n  let resp: Response;\n  try {\n    resp = await fetch(url, {\n      method: 'POST',\n      headers: { 'Content-Type': 'application/json', 'X-API-Key': apiKey },\n      body: JSON.stringify(body),\n    });\n  } catch {\n    return { error: 'Network error' };\n  }\n\n  if (!resp.ok) {\n    try {\n      const err = await resp.json() as PinmeResponse;\n      return { error: err.data && typeof err.data === 'object' && 'error' in err.data\n        ? (err.data as { error: string }).error\n        : err.msg || `HTTP ${resp.status}` };\n    } catch {\n      return { error: `HTTP ${resp.status}` };\n    }\n  }\n\n  const res","createdAt":"2026-09-25T11:51:56.708Z","updatedAt":"2026-09-25T11:51:56.708Z"},{"id":"cmugwhsfk01gtqu06qllnm31q","slug":"glitternetwork-pinme-pinme-llm","name":"pinme-llm","description":"Use this skill when a PinMe project (Worker TypeScript) needs to call OpenRouter-backed LLM APIs, including models, chat/completions, streaming, or OpenRouter web search. Guides AI to generate correct Worker TS code.","authorId":"gh:glitternetwork","authorName":"glitternetwork","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":3745,"pricePerCall":0,"manifest":{"name":"pinme-llm","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Use this skill when a PinMe project (Worker TypeScript) needs to call OpenRouter-backed LLM APIs, including models, chat/completions, streaming, or OpenRouter web search. Guides AI to generate correct Worker TS code.","permissions":[],"systemPrompt":"# PinMe Worker OpenRouter API Integration\n\nGuides how to call PinMe platform's OpenRouter proxy APIs in a PinMe Worker (TypeScript). Workers use the PinMe project API key; they never hold the real OpenRouter API key.\n\n## Environment Variables\n\nThe following environment variables are automatically injected when the Worker is created — no manual configuration needed:\n\n```typescript\n// backend/src/worker.ts\nexport interface Env {\n  DB: D1Database;\n  API_KEY: string;       // Project API Key from create_worker\n  PROJECT_NAME: string;  // Actual project_name from create_worker; must match API_KEY\n  BASE_URL?: string;     // Optional override for PinMe API base URL, defaults to https://pinme.cloud\n}\n```\n\n> `API_KEY` authenticates the Worker to PinMe. `PROJECT_NAME` is required for `chat/completions` and must belong to the same project as `API_KEY`. When `BASE_URL` is not set, use `https://pinme.cloud`.\n\n---\n\n## Models API\n\n**Endpoint:** `GET {BASE_URL}/api/v1/models`\n**Authentication:** `X-API-Key` header (using `env.API_KEY`)\n**Request Body:** none\n\nUse this when the Worker needs to list available OpenRouter models. The response body, status, and headers are passed through from OpenRouter `/models`.\n\n```typescript\nasync function listModels(env: Env): Promise<unknown> {\n  const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';\n  const resp = await fetch(`${baseUrl}/api/v1/models`, {\n    headers: { 'X-API-Key': env.API_KEY },\n  });\n\n  if (!resp.ok) {\n    throw new Error(await extractPinmeOpenRouterError(resp));\n  }\n\n  return await resp.json();\n}\n```\n\n---\n\n## Chat Completions API\n\n**Endpoint:** `POST {BASE_URL}/api/v1/chat/completions?project_name={project_name}`\n**Authentication:** `X-API-Key` header (using `env.API_KEY`)\n**Request Body:** OpenRouter chat/completions format, passed through as-is after a 1MB size check\n**Streaming:** Supports SSE (`stream: true`)\n**Web Search:** Supports OpenRouter `openrouter:web_search` server tool via the `tools` array\n\n### Request Format\n\n```json\n{\n  \"model\": \"openai/gpt-4o-mini\",\n  \"messages\": [\n    { \"role\": \"system\", \"content\": \"You are a helpful assistant.\" },\n    { \"role\": \"user\", \"content\": \"Hello!\" }\n  ],\n  \"stream\": true\n}\n```\n\n> Use `env.PROJECT_NAME` from `create_worker`; always URL-encode it in the query string. For available models, call `GET /api/v1/models` or refer to OpenRouter model IDs.\n\n### OpenRouter Web Search\n\nPinMe does not provide a raw search endpoint. To search the web, pass OpenRouter's `openrouter:web_search` server tool to `chat/completions`; the model decides whether and when to search.\n\nAlways set `max_results` and `max_total_results` to keep search volume and cost bounded.\n\n```typescript\nasync function searchWithLLM(env: Env, query: string): Promise<string> {\n  const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';\n  const resp = await fetch(\n    `${baseUrl}/api/v1/chat/completions?project_name=${encodeURIComponent(env.PROJECT_NAME)}`,\n    {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        'X-API-Key': env.API_KEY,\n      },\n      body: JSON.stringify({\n        model: 'openai/gpt-5.2',\n        messages: [{ role: 'user', content: query }],\n        tools: [\n          {\n            type: 'openrouter:web_search',\n            parameters: {\n              engine: 'auto',\n              max_results: 5,\n              max_total_results: 10,\n            },\n          },\n        ],\n      }),\n    },\n  );\n\n  if (!resp.ok) {\n    throw new Error(await extractPinmeOpenRouterError(resp));\n  }\n\n  const data = await resp.json() as { choices: Array<{ message?: { content?: string } }> };\n  return data.choices[0]?.message?.content ?? '';\n}\n```\n\n### Response Format\n\nSuccessful requests return OpenRouter's raw response body.\n\n**Non-streaming Success (200):**\n```json\n{\n  \"id\": \"chatcmpl-...\",\n  \"choices\": [{ \"message\": { \"role\": \"assistant\", \"content\": \"Hello!\" }, \"finish_reason\": \"stop\" }],\n  \"usage\": { \"prompt_tokens\": 10, \"completion_tokens\": 5, \"total_tokens\": 15 }\n}\n```\n\n**Streaming Success (200):** SSE format\n```\ndata: {\"choices\":[{\"delta\":{\"content\":\"Hello\"}}]}\ndata: {\"choices\":[{\"delta\":{\"content\":\" there\"}}]}\ndata: [DONE]\n```\n\n**Errors:**\n\n| HTTP Status | Meaning | data.error Example |\n|-------------|---------|-------------------|\n| 401 | API Key missing, invalid, or mismatched with project_name | `\"X-API-Key header is required\"` / `\"Invalid API key\"` / `\"Invalid API key or project name\"` |\n| 400 | project_name missing or OpenRouter key not configured | `\"project_name is required\"` / `\"LLM service not configured for this project\"` |\n| 403 | LLM balance insufficient or disabled | `\"Insufficient balance, please recharge to continue using LLM service\"` |\n| 413 | Request body exceeds 1MB | `\"Request body too large (max 1MB)\"` |\n| 500 | Proxy failed before upstream request | `\"Failed to build request\"` |\n| 502 | LLM service unavailable | `\"LLM service unavailable\"` |\n\nIf OpenRouter receives the request and returns a 4xx/5xx, PinMe passes through OpenRouter's status, headers, and response body instead of wrapping it.\n\n### Worker Example Code — Non-streaming\n\n```typescript\nasync function callLLM(\n  env: Env,\n  messages: Array<{ role: string; content: string }>,\n  model = 'openai/gpt-4o-mini',\n): Promise<{ content: string; error?: string }> {\n  const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';\n  const resp = await fetch(\n    `${baseUrl}/api/v1/chat/completions?project_name=${encodeURIComponent(env.PROJECT_NAME)}`,\n    {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        'X-API-Key': env.API_KEY,\n      },\n      body: JSON.stringify({ model, messages }),\n    },\n  );\n\n  if (!resp.ok) {\n    return { content: '', error: await extractPinmeOpenRouterError(resp) };\n  }\n\n  const data = await resp.json() as { choices: Array<{ message: { content: string } }> };\n  return { content: data.choices[0]?.message?.content || '' };\n}\n\n// Usage in routes\nasync function handleChat(request: Request, env: Env): Promise<Response> {\n  const { question } = await request.json() as { question: string };\n\n  const result = await callLLM(env, [\n    { role: 'system', content: 'You are a helpful assistant.' },\n    { role: 'user', content: question },\n  ]);\n\n  if (result.error) {\n    return json({ error: result.error }, 502);\n  }\n  return json({ answer: result.content });\n}\n```\n\n### Worker Example Code — Streaming (SSE Passthrough)\n\n```typescript\nasync function handleChatStream(request: Request, env: Env): Promise<Response> {\n  const body = await request.text();\n  const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';\n\n  // Ensure stream=true in the request\n  let parsed = JSON.parse(body);\n  parsed.stream = true;\n\n  const resp = await fetch(\n    `${baseUrl}/api/v1/chat/completions?project_name=${encodeURIComponent(env.PROJECT_NAME)}`,\n    {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        'X-API-Key': env.API_KEY,\n      },\n      body: JSON.stringify(parsed),\n    },\n  );\n\n  if (!resp.ok) {\n    return json({ error: await extractPinmeOpenRouterError(resp) }, resp.status);\n  }\n\n  // Pass through SSE stream directly\n  return new Response(resp.body, {\n    status: 200,\n    headers: {\n      'Content-Type': 'text/event-stream',\n      'Cache-Control': 'no-cache',\n      'Connection': 'keep-alive',\n      ...CORS_HEADERS,\n    },\n  });\n}\n```\n\n### Frontend SSE Stream Consumer Example\n\n```typescript\nasync function streamChat(question: string, onChunk: (text: string) => void): Promise<void> {\n  const resp = await fetch(getApiUrl('/api/chat/stream'), {\n    method: 'POST',\n    headers: { 'Content-Type': 'application/json' },\n    body: JSON.stringify({ question }),\n  });\n\n  const reader = resp.body!.getReader();\n  const decoder = new TextDecoder();\n  let buffer = '';\n\n  while (true) {\n    const { done, value } = await reader.read();\n    if (done) break;\n\n    buffer += decoder.decode(value, { stream: true });\n    const lines = buffer.split('\\n');\n    buffer = lines.pop()!; // Keep incomplete line\n\n    for (const line of lines) {\n      if (!line.startsWith('data: ')) continue;\n      const payload = line.slice(6);\n      if (payload === '[DONE]') return;\n\n      const chunk = JSON.parse(payload) as { choices: Array<{ delta: { content?: string } }> };\n      const content = chunk.choices[0]?.delta?.content;\n      if (content) onChunk(content);\n    }\n  }\n}\n```\n\n---\n\n## Error Handling Pattern\n\nFor `/api/v1/models` and `/api/v1/chat/completions`, successful responses are raw OpenRouter responses. Proxy failures before the OpenRouter request use PinMe's wrapped error format:\n\n```typescript\ninterface PinmeResponse<T = unknown> {\n  code: number;   // 200=success, other=failure\n  msg: string;    // \"ok\" | \"error\" | \"invalid params\"\n  data?: T;       // Business data on success, may contain { error: string } on failure\n}\n```\n\n### Recommended Error Extractor\n\n```typescript\nasync function extractPinmeOpenRouterError(resp: Response): Promise<string> {\n  const fallback = `HTTP ${resp.status}`;\n  try {\n    const body = await resp.clone().json() as PinmeResponse | { error?: { message?: string } } | { error?: string };\n    if ('data' in body && body.data && typeof body.data === 'object' && 'error' in body.data) {\n      return String((body.data as { error: unknown }).error);\n    }\n    if ('msg' in body && typeof body.msg === 'string' && body.msg) {\n      return body.msg;\n    }\n    if ('error' in body) {\n      const error = body.error;\n      if (typeof error === 'string') return error;\n      if (error && typeof error === 'object' && 'message' in error) {\n        return String((error as { message: unknown }).message);\n      }\n    }\n  } catch {\n    try {\n      const text = await resp.text();\n      if (text) return text;\n    } catch {\n      // Ignore and return fallback below.\n    }\n  }\n  return fallback;\n}\n```\n\n### Optional JSON Helper\n\nUse this helper for non-streaming `POST` calls. It returns the raw OpenRouter JSON on success.\n\n```typescript\nasync function callOpenRouterJSON<T>(url: string, apiKey: string, body: unknown): Promise<{ data?: T; error?: string }> {\n  let resp: Response;\n  try {\n    resp = await fetch(url, {\n      method: 'POST',\n      headers: { 'Content-Type': 'application/json', 'X-API-Key': apiKey },\n      body: JSON.stringify(body),\n    });\n  } catch {\n    return { error: 'Network error' };\n  }\n\n  if (!resp.ok) {\n    return { error: await extractPinmeOpenRouterError(resp) };\n  }\n\n  return { data: await resp.json() as T };\n}\n```\n\n### Usage Example\n\n```typescript\nconst baseUrl = env.BASE_URL ?? 'https://pinme.cloud';\n\n// Call LLM (non-streaming)\nconst llmResult = await callOpenRouterJSON<{ choices: Array<{ message: { content: string } }> }>(\n  `${baseUrl}/api/v1/chat/completions?project_name=${encodeURIComponent(env.PROJECT_NAME)}`, env.API_KEY,\n  { model: 'openai/gpt-4o-mini', messages: [{ role: 'user', content: 'Hi' }] },\n);\nif (llmResult.error) return json({ error: llmResult.error }, 502);\n```","schemaVersion":1},"repoUrl":"https://github.com/glitternetwork/pinme/tree/main/skills/pinme-llm","tags":["ai-tools","claude-code-skill","claude-skills","deployment","deployment-tools","frontend","frontend-deployment","hosting","serverless","skills","static-site","static-site-deploy"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pinme","audit":{"files":["package-lock.json","package.json","pnpm-lock.yaml"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip: Uncontrolled memory allocation via the declared uncompressed size (DoS).","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-7q85-xj36-vmfc · npm:adm-zip@0.5.17","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip extraction follows destination symlinks, allowing arbitrary file overwrite.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-vwc7-r8mq-g2x9 · npm:adm-zip@0.5.17","severity":"medium"},{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip: Crafted ZIP file triggers 4GB memory allocation.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-xcpc-8h2w-3j85 · npm:adm-zip@0.5.17","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"uuid@9.0.1 has a known vulnerability: uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-w5hq-g745-h8pq · npm:uuid@9.0.1","severity":"medium"}],"packages":16,"auditedAt":"2026-09-25T11:51:56.672Z","lockfiles":["package-lock.json","pnpm-lock.yaml"]},"forks":277,"owner":"glitternetwork","stars":3745,"topics":["ai-tools","claude-code-skill","claude-skills","deployment","deployment-tools","frontend","frontend-deployment","hosting","serverless","skills","static-site","static-site-deploy","static-site-hosting","web-hosting","zero-configuration"],"license":"MIT","fullName":"glitternetwork/pinme","homepage":"https://pinme.eth.limo","language":"TypeScript","pushedAt":"2026-09-12T05:23:49Z","avatarUrl":"https://avatars.githubusercontent.com/u/102277171?v=4","crawledAt":"2026-09-25T11:51:44.477Z","openIssues":7,"manifestFile":"SKILL.md","manifestPath":"skills/pinme-llm/SKILL.md","defaultBranch":"main"},"readme":"# PinMe Worker OpenRouter API Integration\n\nGuides how to call PinMe platform's OpenRouter proxy APIs in a PinMe Worker (TypeScript). Workers use the PinMe project API key; they never hold the real OpenRouter API key.\n\n## Environment Variables\n\nThe following environment variables are automatically injected when the Worker is created — no manual configuration needed:\n\n```typescript\n// backend/src/worker.ts\nexport interface Env {\n  DB: D1Database;\n  API_KEY: string;       // Project API Key from create_worker\n  PROJECT_NAME: string;  // Actual project_name from create_worker; must match API_KEY\n  BASE_URL?: string;     // Optional override for PinMe API base URL, defaults to https://pinme.cloud\n}\n```\n\n> `API_KEY` authenticates the Worker to PinMe. `PROJECT_NAME` is required for `chat/completions` and must belong to the same project as `API_KEY`. When `BASE_URL` is not set, use `https://pinme.cloud`.\n\n---\n\n## Models API\n\n**Endpoint:** `GET {BASE_URL}/api/v1/models`\n**Authentication:** `X-API-Key` header (using `env.API_KEY`)\n**Request Body:** none\n\nUse this when the Worker needs to list available OpenRouter models. The response body, status, and headers are passed through from OpenRouter `/models`.\n\n```typescript\nasync function listModels(env: Env): Promise<unknown> {\n  const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';\n  const resp = await fetch(`${baseUrl}/api/v1/models`, {\n    headers: { 'X-API-Key': env.API_KEY },\n  });\n\n  if (!resp.ok) {\n    throw new Error(await extractPinmeOpenRouterError(resp));\n  }\n\n  return await resp.json();\n}\n```\n\n---\n\n## Chat Completions API\n\n**Endpoint:** `POST {BASE_URL}/api/v1/chat/completions?project_name={project_name}`\n**Authentication:** `X-API-Key` header (using `env.API_KEY`)\n**Request Body:** OpenRouter chat/completions format, passed through as-is after a 1MB size check\n**Streaming:** Supports SSE (`stream: true`)\n**Web Search:** Supports OpenRouter `openrouter:web_search` server tool via the `tools` array\n\n### Request Format\n\n```json\n{\n  \"model\": \"openai/gpt-4o-mini\",\n  \"messages\": [\n    { \"role\": \"system\", \"content\": \"You are a helpful assistant.\" },\n    { \"role\": \"user\", \"content\": \"Hello!\" }\n  ],\n  \"stream\": true\n}\n```\n\n> Use `env.PROJECT_NAME` from `create_worker`; always URL-encode it in the query string. For available models, call `GET /api/v1/models` or refer to OpenRouter model IDs.\n\n### OpenRouter Web Search\n\nPinMe does not provide a raw search endpoint. To search the web, pass OpenRouter's `openrouter:web_search` server tool to `chat/completions`; the model decides whether and when to search.\n\nAlways set `max_results` and `max_total_results` to keep search volume and cost bounded.\n\n```typescript\nasync function searchWithLLM(env: Env, query: string): Promise<string> {\n  const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';\n  const resp = await fetch(\n    `${baseUrl}/api/v1/chat/completions?project_name=${encodeURIComponent(env.PROJECT_NAME)}`,\n    {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        'X-API-Key': env.API_KEY,\n      },\n      body: JSON.stringify({\n        model: 'openai/gpt-5.2',\n        messages: [{ role: 'user', content: query }],\n        tools: [\n          {\n            type: 'openrouter:web_search',\n            parameters: {\n              engine: 'auto',\n              max_results: 5,\n              max_total_results: 10,\n            },\n          },\n        ],\n      }),\n    },\n  );\n\n  if (!resp.ok) {\n    throw new Error(await extractPinmeOpenRouterError(resp));\n  }\n\n  const data = await resp.json() as { choices: Array<{ message?: { content?: string } }> };\n  return data.choices[0]?.message?.content ?? '';\n}\n```\n\n### Response Format\n\nSuccessful requests return OpenRouter's raw response body.\n\n**Non-streaming Success (200):**\n```json\n{\n  \"id\": \"chatcmpl-...\",\n  \"choices\": [{ \"message\": { \"role\": \"assistant\", \"content\": \"Hello!\" }, \"finish_reason\": \"stop\" }],\n  \"usage\": { \"prompt_tokens\": 10, \"completion_tokens\": 5, \"total","createdAt":"2026-09-25T11:51:56.720Z","updatedAt":"2026-09-25T11:51:56.720Z"},{"id":"cmugwhsfv01gwqu06caq63e28","slug":"glitternetwork-pinme-pinme-r2","name":"pinme-r2","description":"Use when a PinMe Cloudflare Worker needs R2 object storage, including secure file or image upload, streaming download, metadata lookup, deletion, listing, Range requests, or R2+D1 coordination. Guides AI to use PinMe's automatically injected env.R2 binding without R2 credentials or manual Wrangler configuration.","authorId":"gh:glitternetwork","authorName":"glitternetwork","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":3745,"pricePerCall":0,"manifest":{"name":"pinme-r2","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Use when a PinMe Cloudflare Worker needs R2 object storage, including secure file or image upload, streaming download, metadata lookup, deletion, listing, Range requests, or R2+D1 coordination. Guides AI to use PinMe's automatically injected env.R2 binding without R2 credentials or manual Wrangler configuration.","permissions":[],"systemPrompt":"# PinMe Worker R2 Storage\n\nUse the project-scoped R2 bucket that PinMe binds to every deployed Worker as `env.R2`. Do not create credentials, choose a bucket name, or edit generated Wrangler configuration.\n\n## Runtime Contract\n\nPinMe rebuilds trusted Worker metadata on create, save, and update. Client metadata cannot replace the R2 binding.\n\n| Binding | TypeScript type | Availability |\n| --- | --- | --- |\n| `DB` | `D1Database` | Always injected |\n| `R2` | `R2Bucket` | Always injected; current project's bucket |\n| `API_KEY` | `string` | Always injected |\n| `LLM_API_KEY` | `string` | Always injected |\n| `BASE_URL` | `string` | Always injected |\n| `WORKER_URL` | `string` | Always injected |\n| `PROJECT_NAME` | `string` | Always injected |\n\nPayment-specific bindings such as `UNIWEB_SECRET` are conditional and unrelated to R2 access.\n\nDeclare only the bindings used by the Worker module. R2 code normally starts with:\n\n```typescript\nexport interface Env {\n  R2: R2Bucket;\n  PROJECT_NAME: string;\n  WORKER_URL: string;\n}\n```\n\nWhen the same module coordinates file metadata in D1, also declare `DB: D1Database` as a required field.\n\n## Choose R2 or D1\n\n- Use R2 for file bodies, images, attachments, media, exports, and other objects addressed by key.\n- Use D1 for searchable business metadata, ownership, relations, status, and audit fields.\n- For managed files, store the body in R2 and store only its key and business metadata in D1.\n- Never use Worker local filesystem state for persistence and never store complete files or base64 payloads in D1.\n\n## Required Security Workflow\n\nApply this sequence to every upload, download, metadata, delete, and list route:\n\n```text\nauthenticate request\n→ authorize the project/user action\n→ validate size and media policy\n→ generate or normalize a scoped object key\n→ call env.R2\n→ return a sanitized response\n```\n\nUse the application's existing authentication. The examples below accept a trusted `userId` that the route must obtain from verified identity claims, never from an untrusted request body or query parameter.\n\nKeep object keys server-controlled. Prefer opaque IDs under an owner prefix:\n\n```typescript\nconst FILE_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\nfunction ownerPrefix(userId: string): string {\n  if (!userId) throw new Error('Authenticated user id is required');\n  return `users/${encodeURIComponent(userId)}/files/`;\n}\n\nfunction objectKey(userId: string, fileId: string): string {\n  if (!FILE_ID_RE.test(fileId)) throw new Error('Invalid file id');\n  return `${ownerPrefix(userId)}${fileId}`;\n}\n```\n\nNever accept a complete object key from the client. Reject empty identifiers, `.` or `..` segments, backslashes, control characters, and any attempt to access another user's prefix.\n\n## Shared Helpers\n\nUse small helpers and explicit business limits. Adapt the allowlist to the product rather than accepting every client-supplied media type.\n\n```typescript\nconst MAX_UPLOAD_BYTES = 25 * 1024 * 1024;\nconst ALLOWED_CONTENT_TYPES = new Set([\n  'image/jpeg',\n  'image/png',\n  'image/webp',\n  'application/pdf',\n]);\n\nfunction json(data: unknown, status = 200): Response {\n  return Response.json(data, { status });\n}\n\nfunction safeDownloadName(value: string | null): string {\n  const cleaned = (value || 'download')\n    .replace(/[\\r\\n\"\\\\]/g, '_')\n    .replace(/[\\x00-\\x1f\\x7f]/g, '')\n    .trim();\n  return (cleaned || 'download').slice(0, 128);\n}\n\nfunction requestedFileId(request: Request): string | null {\n  const url = new URL(request.url);\n  const value = url.pathname.split('/').filter(Boolean).at(-1) || '';\n  return FILE_ID_RE.test(value) ? value : null;\n}\n```\n\nClient filenames and `Content-Type` are hints, not proof of content. For sensitive formats, inspect magic bytes or send the object through an asynchronous validation/scanning workflow before marking it ready.\n\n## Stream an Upload\n\nRequire authentication before calling this handler. Pass `request.body` directly to R2; do not call `arrayBuffer()`, `text()`, `json()`, `formData()`, or base64 conversion first.\n\n```typescript\nasync function handleUpload(\n  request: Request,\n  env: Env,\n  userId: string,\n): Promise<Response> {\n  if (!request.body) return json({ error: 'File body is required' }, 400);\n\n  const lengthHeader = request.headers.get('content-length');\n  if (!lengthHeader) return json({ error: 'Content-Length is required' }, 411);\n\n  const declaredSize = Number(lengthHeader);\n  if (!Number.isSafeInteger(declaredSize) || declaredSize < 0) {\n    return json({ error: 'Invalid Content-Length' }, 400);\n  }\n  if (declaredSize > MAX_UPLOAD_BYTES) {\n    return json({ error: 'File is too large' }, 413);\n  }\n\n  const contentType = (request.headers.get('content-type') || '')\n    .split(';', 1)[0]\n    .trim()\n    .toLowerCase();\n  if (!ALLOWED_CONTENT_TYPES.has(contentType)) {\n    return json({ error: 'Unsupported media type' }, 400);\n  }\n\n  const fileId = crypto.randomUUID();\n  const key = objectKey(userId, fileId);\n  const filename = safeDownloadName(request.headers.get('x-file-name'));\n\n  const object = await env.R2.put(key, request.body, {\n    httpMetadata: {\n      contentType,\n      contentDisposition: `attachment; filename=\"${filename}\"`,\n    },\n    customMetadata: { ownerId: userId },\n  });\n\n  if (object === null) return json({ error: 'Upload precondition failed' }, 412);\n\n  // Content-Length is only a precheck. Enforce the actual stored size too.\n  if (object.size > MAX_UPLOAD_BYTES) {\n    await env.R2.delete(key);\n    return json({ error: 'File is too large' }, 413);\n  }\n\n  return json({ id: fileId, size: object.size, etag: object.httpEtag }, 201);\n}\n```\n\nDo not return the bucket name or internal object-key layout. Return an opaque file ID that later routes resolve under the authenticated owner's prefix.\n\n## Stream a Download\n\nValidate a single Range header before passing it to R2. R2 may return `null` when the object does not exist, or metadata without a body when a conditional request fails.\n\n```typescript\nfunction validRangeHeader(value: string | null): boolean {\n  if (!value) return true;\n  const match = /^bytes=(\\d*)-(\\d*)$/.exec(value);\n  return Boolean(match && (match[1] || match[2]));\n}\n\nasync function handleDownload(\n  request: Request,\n  env: Env,\n  userId: string,\n): Promise<Response> {\n  const fileId = requestedFileId(request);\n  if (!fileId) return json({ error: 'Invalid file id' }, 400);\n  if (!validRangeHeader(request.headers.get('range'))) {\n    return json({ error: 'Invalid Range header' }, 416);\n  }\n\n  const object = await env.R2.get(objectKey(userId, fileId), {\n    onlyIf: request.headers,\n    range: request.headers,\n  });\n  if (object === null) return json({ error: 'Not found' }, 404);\n  if (!('body' in object)) return new Response(null, { status: 412 });\n\n  const headers = new Headers();\n  object.writeHttpMetadata(headers);\n  headers.set('etag', object.httpEtag);\n  headers.set('accept-ranges', 'bytes');\n  if (object.range) {\n    const { offset, length } = object.range;\n    headers.set(\n      'content-range',\n      `bytes ${offset}-${offset + length - 1}/${object.size}`,\n    );\n    headers.set('content-length', String(length));\n  } else {\n    headers.set('content-length', String(object.size));\n  }\n\n  return new Response(object.body, {\n    status: object.range ? 206 : 200,\n    headers,\n  });\n}\n```\n\nFor routes backed by D1 metadata, authorize the D1 row's owner before calling `env.R2.get`. Do not infer ownership only from a client-provided path.\n\n## Read Metadata with HEAD\n\n```typescript\nasync function handleHead(\n  request: Request,\n  env: Env,\n  userId: string,\n): Promise<Response> {\n  const fileId = requestedFileId(request);\n  if (!fileId) return json({ error: 'Invalid file id' }, 400);\n\n  const object = await env.R2.head(objectKey(userId, fileId));\n  if (object === null) return new Response(null, { status: 404 });\n\n  const headers = new Headers();\n  object.writeHttpMetadata(headers);\n  headers.set('etag', object.httpEtag);\n  headers.set('content-length', String(object.size));\n  return new Response(null, { status: 200, headers });\n}\n```\n\nUse `head()` when only size, ETag, upload time, or metadata is needed. Do not download the body to answer metadata requests.\n\n## Delete an Object\n\n```typescript\nasync function handleDelete(\n  request: Request,\n  env: Env,\n  userId: string,\n): Promise<Response> {\n  const fileId = requestedFileId(request);\n  if (!fileId) return json({ error: 'Invalid file id' }, 400);\n\n  const key = objectKey(userId, fileId);\n  const object = await env.R2.head(key);\n  if (object === null) return json({ error: 'Not found' }, 404);\n\n  await env.R2.delete(key);\n  return new Response(null, { status: 204 });\n}\n```\n\nR2 can delete up to 1000 keys in one `delete([...keys])` call. Batch deletion must still derive and authorize every key server-side.\n\n## List an Owner's Objects\n\nNever list the whole bucket for an end-user request. Derive the prefix from verified identity and treat the cursor as opaque.\n\n```typescript\nasync function handleList(\n  request: Request,\n  env: Env,\n  userId: string,\n): Promise<Response> {\n  const cursor = new URL(request.url).searchParams.get('cursor');\n  if (cursor && cursor.length > 2048) {\n    return json({ error: 'Invalid cursor' }, 400);\n  }\n\n  const page = await env.R2.list({\n    prefix: ownerPrefix(userId),\n    cursor: cursor || undefined,\n    limit: 100,\n    include: ['httpMetadata', 'customMetadata'],\n  });\n\n  return json({\n    objects: page.objects.map((object) => ({\n      id: object.key.slice(ownerPrefix(userId).length),\n      size: object.size,\n      uploaded: object.uploaded.toISOString(),\n      etag: object.httpEtag,\n      contentType: object.httpMetadata?.contentType,\n    })),\n    nextCursor: page.truncated ? page.cursor : null,\n  });\n}\n```\n\nAn R2 list call returns at most 1000 entries and may return fewer than the requested limit when metadata is included. Continue only when `page.truncated` is true; never use `objects.length === limit` as the pagination condition.\n\n## Route and Error Semantics\n\nAuthenticate once in the router, derive a trusted `userId`, then pass it to the handlers. Return an `Allow` header for unsupported methods.\n\n| Status | Meaning |\n| --- | --- |\n| 400 | Invalid file ID, body, cursor, or media type |\n| 401 | Missing or invalid authentication |\n| 403 | Authenticated but not allowed to access the object |\n| 404 | Object or owned metadata record not found |\n| 411 | A capped upload route requires `Content-Length` but it is absent |\n| 412 | Conditional R2 operation failed |\n| 413 | Business or platform upload limit exceeded |\n| 416 | Invalid or unsatisfiable Range request |\n| 500 | Sanitized internal storage failure |\n\nCatch storage failures at the route boundary, log only non-sensitive context, and return a generic error. Never return a raw provider error, bucket name, credential, or internal object key.\nTranslate a valid-but-unsatisfiable R2 Range failure to `416` without returning the provider error text.\n\n## Coordinate R2 with D1\n\nR2 and D1 do not share a transaction. Use an explicit state transition when business metadata is required:\n\n```text\ninsert D1 row with status=pending\n→ stream body to R2\n→ update D1 row to status=ready\n```\n\n- If upload fails, delete the pending row or mark it failed.\n- If the final D1 update fails, delete the newly uploaded object or retain a durable pending state for a compensation job.\n- Store at least: public file ID, internal object key, owner ID, original name, size, MIME, status, and timestamps.\n- For download and delete, load the row by public file ID and owner ID before touching R2.\n- Delete the R2 object and D1 row with an explicit retry/compensation policy; do not pretend the two operations are atomic.\n\n## Large Files\n\nUse `request.body → env.R2.put` for small and medium uploads. Streaming avoids Worker memory amplification but does not bypass the Cloudflare request-body limit for the account plan.\n\nUse multipart only when the object exceeds that request limit or resumability is an explicit product requirement. A multipart API must:\n\n- authenticate every create, upload-part, complete, resume, and abort action;\n- bind the object key and upload ID to an owner in durable state;\n- validate part number, part size, total size, and declared content type;\n- make completion idempotent and abort stale uploads;\n- avoid accepting an arbitrary key or upload ID from an untrusted client.\n\nDo not generate a public multipart controller by default. Multipart state and security are substantially more complex than a single streaming upload.\n\n## Local Development\n\n- Do not edit PinMe-generated `backend/wrangler.toml` to add an R2 binding.\n- Unit-test key generation, authorization, routing, and failure handling with a narrow `R2Bucket` mock.\n- Verify real metadata, Range, conditional requests, and streaming after `pinme update-worker` or `pinme save`.\n- Treat the mock as a logic test, not proof of production R2 behavior.\n\n## Anti-Patterns\n\n| Do not | Use instead |\n| --- | --- |\n| Expose an unauthenticated upload route | Authenticate and authorize before every mutation |\n| Accept a complete object key from the client | Generate an opaque ID under a server-derived owner prefix |\n| Trust a user ID from JSON or query parameters | Derive identity from verified claims |\n| Read a large body into an ArrayBuffer or base64 string | Stream `request.body` directly into `env.R2.put` |\n| Store file bodies or base64 in D1 | Store bodies in R2 and searchable metadata in D1 |\n| List the whole bucket | Restrict with an owner prefix and paginate |\n| Stop pagination based on returned object count | Check `page.truncated` and return `page.cursor` |\n| Drop response metadata | Apply `writeHttpMetadata`, `httpEtag`, length, and Range headers |\n| Persist with `fs` or local directories | Use the injected R2 binding |\n| Add R2 keys or secrets to source/config | Use `env.R2`; PinMe owns the binding |\n| Edit generated Wrangler binding configuration | Deploy through `pinme save` or `pinme update-worker` |","schemaVersion":1},"repoUrl":"https://github.com/glitternetwork/pinme/tree/main/skills/pinme-r2","tags":["ai-tools","claude-code-skill","claude-skills","deployment","deployment-tools","frontend","frontend-deployment","hosting","serverless","skills","static-site","static-site-deploy"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pinme","audit":{"files":["package-lock.json","package.json","pnpm-lock.yaml"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip: Uncontrolled memory allocation via the declared uncompressed size (DoS).","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-7q85-xj36-vmfc · npm:adm-zip@0.5.17","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip extraction follows destination symlinks, allowing arbitrary file overwrite.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-vwc7-r8mq-g2x9 · npm:adm-zip@0.5.17","severity":"medium"},{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip: Crafted ZIP file triggers 4GB memory allocation.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-xcpc-8h2w-3j85 · npm:adm-zip@0.5.17","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"uuid@9.0.1 has a known vulnerability: uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-w5hq-g745-h8pq · npm:uuid@9.0.1","severity":"medium"}],"packages":16,"auditedAt":"2026-09-25T11:51:56.672Z","lockfiles":["package-lock.json","pnpm-lock.yaml"]},"forks":277,"owner":"glitternetwork","stars":3745,"topics":["ai-tools","claude-code-skill","claude-skills","deployment","deployment-tools","frontend","frontend-deployment","hosting","serverless","skills","static-site","static-site-deploy","static-site-hosting","web-hosting","zero-configuration"],"license":"MIT","fullName":"glitternetwork/pinme","homepage":"https://pinme.eth.limo","language":"TypeScript","pushedAt":"2026-09-12T05:23:49Z","avatarUrl":"https://avatars.githubusercontent.com/u/102277171?v=4","crawledAt":"2026-09-25T11:51:44.477Z","openIssues":7,"manifestFile":"SKILL.md","manifestPath":"skills/pinme-r2/SKILL.md","defaultBranch":"main"},"readme":"# PinMe Worker R2 Storage\n\nUse the project-scoped R2 bucket that PinMe binds to every deployed Worker as `env.R2`. Do not create credentials, choose a bucket name, or edit generated Wrangler configuration.\n\n## Runtime Contract\n\nPinMe rebuilds trusted Worker metadata on create, save, and update. Client metadata cannot replace the R2 binding.\n\n| Binding | TypeScript type | Availability |\n| --- | --- | --- |\n| `DB` | `D1Database` | Always injected |\n| `R2` | `R2Bucket` | Always injected; current project's bucket |\n| `API_KEY` | `string` | Always injected |\n| `LLM_API_KEY` | `string` | Always injected |\n| `BASE_URL` | `string` | Always injected |\n| `WORKER_URL` | `string` | Always injected |\n| `PROJECT_NAME` | `string` | Always injected |\n\nPayment-specific bindings such as `UNIWEB_SECRET` are conditional and unrelated to R2 access.\n\nDeclare only the bindings used by the Worker module. R2 code normally starts with:\n\n```typescript\nexport interface Env {\n  R2: R2Bucket;\n  PROJECT_NAME: string;\n  WORKER_URL: string;\n}\n```\n\nWhen the same module coordinates file metadata in D1, also declare `DB: D1Database` as a required field.\n\n## Choose R2 or D1\n\n- Use R2 for file bodies, images, attachments, media, exports, and other objects addressed by key.\n- Use D1 for searchable business metadata, ownership, relations, status, and audit fields.\n- For managed files, store the body in R2 and store only its key and business metadata in D1.\n- Never use Worker local filesystem state for persistence and never store complete files or base64 payloads in D1.\n\n## Required Security Workflow\n\nApply this sequence to every upload, download, metadata, delete, and list route:\n\n```text\nauthenticate request\n→ authorize the project/user action\n→ validate size and media policy\n→ generate or normalize a scoped object key\n→ call env.R2\n→ return a sanitized response\n```\n\nUse the application's existing authentication. The examples below accept a trusted `userId` that the route must obtain from verified identity claims, never from an untrusted request body or query parameter.\n\nKeep object keys server-controlled. Prefer opaque IDs under an owner prefix:\n\n```typescript\nconst FILE_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\nfunction ownerPrefix(userId: string): string {\n  if (!userId) throw new Error('Authenticated user id is required');\n  return `users/${encodeURIComponent(userId)}/files/`;\n}\n\nfunction objectKey(userId: string, fileId: string): string {\n  if (!FILE_ID_RE.test(fileId)) throw new Error('Invalid file id');\n  return `${ownerPrefix(userId)}${fileId}`;\n}\n```\n\nNever accept a complete object key from the client. Reject empty identifiers, `.` or `..` segments, backslashes, control characters, and any attempt to access another user's prefix.\n\n## Shared Helpers\n\nUse small helpers and explicit business limits. Adapt the allowlist to the product rather than accepting every client-supplied media type.\n\n```typescript\nconst MAX_UPLOAD_BYTES = 25 * 1024 * 1024;\nconst ALLOWED_CONTENT_TYPES = new Set([\n  'image/jpeg',\n  'image/png',\n  'image/webp',\n  'application/pdf',\n]);\n\nfunction json(data: unknown, status = 200): Response {\n  return Response.json(data, { status });\n}\n\nfunction safeDownloadName(value: string | null): string {\n  const cleaned = (value || 'download')\n    .replace(/[\\r\\n\"\\\\]/g, '_')\n    .replace(/[\\x00-\\x1f\\x7f]/g, '')\n    .trim();\n  return (cleaned || 'download').slice(0, 128);\n}\n\nfunction requestedFileId(request: Request): string | null {\n  const url = new URL(request.url);\n  const value = url.pathname.split('/').filter(Boolean).at(-1) || '';\n  return FILE_ID_RE.test(value) ? value : null;\n}\n```\n\nClient filenames and `Content-Type` are hints, not proof of content. For sensitive formats, inspect magic bytes or send the object through an asynchronous validation/scanning workflow before marking it ready.\n\n## Stream an Upload\n\nRequire authentication before calling this handler. Pass `request.body` directly to R2; do not c","createdAt":"2026-09-25T11:51:56.731Z","updatedAt":"2026-09-25T11:51:56.731Z"},{"id":"cmugwhsg601gzqu06q48km47z","slug":"glitternetwork-pinme-pinme-share","name":"pinme-share","description":"Use this skill when the user wants to share, publish, or upload a static result through PinMe, especially by generating a static HTML share page for a PinMe project link, deployed full-stack app, Codex conversation summary, report, file, demo, or any 分享/发布/上传分享页 request that should end with `pinme upload`.","authorId":"gh:glitternetwork","authorName":"glitternetwork","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":3745,"pricePerCall":0,"manifest":{"name":"pinme-share","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Use this skill when the user wants to share, publish, or upload a static result through PinMe, especially by generating a static HTML share page for a PinMe project link, deployed full-stack app, Codex conversation summary, report, file, demo, or any 分享/发布/上传分享页 request that should end with `pinme upload`.","permissions":[],"systemPrompt":"# PinMe Share\n\nCreate a polished static share artifact, upload it with `pinme upload`, and return the final URL.\n\n## When to Use\n\nUse this skill when the user asks to:\n\n- Share or publish a result using PinMe.\n- Create a static page that wraps a deployed project link, demo, report, or artifact.\n- Summarize a Codex conversation/session and share it as a page.\n- Turn a project handoff into a public landing or summary page.\n- Upload an existing static file or folder for lightweight distribution.\n\nIf the user needs a backend, database, auth, email, or LLM functionality, use the main `pinme` skill and any relevant PinMe integration skill first. Use `pinme-share` at the end to package and publish the result.\n\n## Core Workflow\n\n1. Identify what is being shared:\n   - **PinMe/full-stack project**: deployed URL, short description, key features, tech stack, usage notes.\n   - **Codex conversation**: goal, decisions, implementation summary, important outputs, next steps.\n   - **Static file/report/demo**: title, purpose, file contents or preview, context for the recipient.\n2. Create a static share artifact:\n   - Prefer a single self-contained `index.html`.\n   - Use `share/<slug>/index.html` in the current workspace unless the repo has an existing output/share convention.\n   - Keep CSS inline for portability.\n   - Do not require JavaScript unless interaction is valuable.\n3. Sanitize before publishing:\n   - Remove secrets, tokens, API keys, `.env` values, internal-only URLs, private user data, and unrelated logs.\n   - For conversation summaries, summarize rather than dumping raw transcript unless the user explicitly asks for verbatim sharing.\n   - Make links explicit and clickable.\n4. Upload with PinMe:\n   ```bash\n   pinme upload share/<slug>\n   ```\n5. Return the URL printed by PinMe. If PinMe outputs multiple URLs, prefer DNS domain, then PinMe subdomain, then short URL, then full preview URL. Never truncate hash fragments.\n\n## Share Page Content\n\nFor a project share page, include:\n\n- Project name and one-sentence description.\n- Primary launch/demo link as the first action.\n- What it does, who it is for, and why it matters.\n- Feature list focused on user-visible behavior.\n- Build/deploy details only when useful to the recipient.\n- Date and provenance such as \"Created with Codex\" only if appropriate.\n\nFor a conversation share page, include:\n\n- Conversation title.\n- Initial goal or question.\n- Key context and constraints.\n- Decisions made.\n- Work completed or answer summary.\n- Files changed, commands run, links produced, or artifacts created when relevant.\n- Follow-up items.\n\nFor a file/report share page, include:\n\n- Clear title and short abstract.\n- Download/open link to the uploaded artifact if there is a separate file.\n- Important excerpts or generated summary.\n- Source/context notes.\n\n## HTML Guidelines\n\n- Build a real share page, not a generic placeholder.\n- Make the most important link visible in the first viewport.\n- Use clean, responsive HTML/CSS that works as a standalone static file.\n- Keep the design restrained and readable; avoid overdecorated marketing layouts for technical handoffs.\n- Use semantic sections, accessible contrast, descriptive link text, and sensible mobile spacing.\n- Escape user-provided text before inserting it into HTML.\n- If showing code or command output, wrap it in `<pre><code>` and keep it short.\n\n## PinMe Upload Checklist\n\nBefore upload:\n\n```bash\npinme --version\n```\n\nIf PinMe is missing or stale, install or update it according to the main `pinme` skill. Authentication is required for upload:\n\n```bash\npinme login\n# or: pinme set-appkey <AppKey>\n```\n\nUpload examples:\n\n```bash\npinme upload share/my-project\npinme upload share/conversation-summary\npinme upload ./report.html\npinme upload ./dist\n```\n\nDo not upload:\n\n- `.env`, `.git`, `node_modules`, source trees, private datasets, raw logs with credentials, or unrelated build cache.\n- Raw conversation transcripts that may include secrets or private context unless the user explicitly approves the exact content.\n\n## Final Response\n\nTell the user:\n\n- What share artifact was created.\n- The PinMe URL returned by upload.\n- Any important caveat, such as skipped upload because PinMe was not authenticated or unavailable.\n\nKeep the response short. The URL is the main deliverable.","schemaVersion":1},"repoUrl":"https://github.com/glitternetwork/pinme/tree/main/skills/pinme-share","tags":["ai-tools","claude-code-skill","claude-skills","deployment","deployment-tools","frontend","frontend-deployment","hosting","serverless","skills","static-site","static-site-deploy"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pinme","audit":{"files":["package-lock.json","package.json","pnpm-lock.yaml"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip: Uncontrolled memory allocation via the declared uncompressed size (DoS).","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-7q85-xj36-vmfc · npm:adm-zip@0.5.17","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip extraction follows destination symlinks, allowing arbitrary file overwrite.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-vwc7-r8mq-g2x9 · npm:adm-zip@0.5.17","severity":"medium"},{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip: Crafted ZIP file triggers 4GB memory allocation.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-xcpc-8h2w-3j85 · npm:adm-zip@0.5.17","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"uuid@9.0.1 has a known vulnerability: uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-w5hq-g745-h8pq · npm:uuid@9.0.1","severity":"medium"}],"packages":16,"auditedAt":"2026-09-25T11:51:56.672Z","lockfiles":["package-lock.json","pnpm-lock.yaml"]},"forks":277,"owner":"glitternetwork","stars":3745,"topics":["ai-tools","claude-code-skill","claude-skills","deployment","deployment-tools","frontend","frontend-deployment","hosting","serverless","skills","static-site","static-site-deploy","static-site-hosting","web-hosting","zero-configuration"],"license":"MIT","fullName":"glitternetwork/pinme","homepage":"https://pinme.eth.limo","language":"TypeScript","pushedAt":"2026-09-12T05:23:49Z","avatarUrl":"https://avatars.githubusercontent.com/u/102277171?v=4","crawledAt":"2026-09-25T11:51:44.477Z","openIssues":7,"manifestFile":"SKILL.md","manifestPath":"skills/pinme-share/SKILL.md","defaultBranch":"main"},"readme":"# PinMe Share\n\nCreate a polished static share artifact, upload it with `pinme upload`, and return the final URL.\n\n## When to Use\n\nUse this skill when the user asks to:\n\n- Share or publish a result using PinMe.\n- Create a static page that wraps a deployed project link, demo, report, or artifact.\n- Summarize a Codex conversation/session and share it as a page.\n- Turn a project handoff into a public landing or summary page.\n- Upload an existing static file or folder for lightweight distribution.\n\nIf the user needs a backend, database, auth, email, or LLM functionality, use the main `pinme` skill and any relevant PinMe integration skill first. Use `pinme-share` at the end to package and publish the result.\n\n## Core Workflow\n\n1. Identify what is being shared:\n   - **PinMe/full-stack project**: deployed URL, short description, key features, tech stack, usage notes.\n   - **Codex conversation**: goal, decisions, implementation summary, important outputs, next steps.\n   - **Static file/report/demo**: title, purpose, file contents or preview, context for the recipient.\n2. Create a static share artifact:\n   - Prefer a single self-contained `index.html`.\n   - Use `share/<slug>/index.html` in the current workspace unless the repo has an existing output/share convention.\n   - Keep CSS inline for portability.\n   - Do not require JavaScript unless interaction is valuable.\n3. Sanitize before publishing:\n   - Remove secrets, tokens, API keys, `.env` values, internal-only URLs, private user data, and unrelated logs.\n   - For conversation summaries, summarize rather than dumping raw transcript unless the user explicitly asks for verbatim sharing.\n   - Make links explicit and clickable.\n4. Upload with PinMe:\n   ```bash\n   pinme upload share/<slug>\n   ```\n5. Return the URL printed by PinMe. If PinMe outputs multiple URLs, prefer DNS domain, then PinMe subdomain, then short URL, then full preview URL. Never truncate hash fragments.\n\n## Share Page Content\n\nFor a project share page, include:\n\n- Project name and one-sentence description.\n- Primary launch/demo link as the first action.\n- What it does, who it is for, and why it matters.\n- Feature list focused on user-visible behavior.\n- Build/deploy details only when useful to the recipient.\n- Date and provenance such as \"Created with Codex\" only if appropriate.\n\nFor a conversation share page, include:\n\n- Conversation title.\n- Initial goal or question.\n- Key context and constraints.\n- Decisions made.\n- Work completed or answer summary.\n- Files changed, commands run, links produced, or artifacts created when relevant.\n- Follow-up items.\n\nFor a file/report share page, include:\n\n- Clear title and short abstract.\n- Download/open link to the uploaded artifact if there is a separate file.\n- Important excerpts or generated summary.\n- Source/context notes.\n\n## HTML Guidelines\n\n- Build a real share page, not a generic placeholder.\n- Make the most important link visible in the first viewport.\n- Use clean, responsive HTML/CSS that works as a standalone static file.\n- Keep the design restrained and readable; avoid overdecorated marketing layouts for technical handoffs.\n- Use semantic sections, accessible contrast, descriptive link text, and sensible mobile spacing.\n- Escape user-provided text before inserting it into HTML.\n- If showing code or command output, wrap it in `<pre><code>` and keep it short.\n\n## PinMe Upload Checklist\n\nBefore upload:\n\n```bash\npinme --version\n```\n\nIf PinMe is missing or stale, install or update it according to the main `pinme` skill. Authentication is required for upload:\n\n```bash\npinme login\n# or: pinme set-appkey <AppKey>\n```\n\nUpload examples:\n\n```bash\npinme upload share/my-project\npinme upload share/conversation-summary\npinme upload ./report.html\npinme upload ./dist\n```\n\nDo not upload:\n\n- `.env`, `.git`, `node_modules`, source trees, private datasets, raw logs with credentials, or unrelated build cache.\n- Raw conversation transcripts that may include secrets or private context unless th","createdAt":"2026-09-25T11:51:56.743Z","updatedAt":"2026-09-25T11:51:56.743Z"},{"id":"cmugwhsgg01h2qu06355ifb4x","slug":"glitternetwork-pinme-pinme-uniwebpay","name":"pinme-uniwebpay","description":"Use when generating, modifying, or reviewing PinMe Worker (Cloudflare Worker TypeScript) code that accepts payments through UniwebPay — payment links, products/prices, checkout sessions, payment status reads, refunds, subscriptions, or handling UniwebPay webhooks with @uniwebpay/sdk in a PinMe project.","authorId":"gh:glitternetwork","authorName":"glitternetwork","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":3745,"pricePerCall":0,"manifest":{"name":"pinme-uniwebpay","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Use when generating, modifying, or reviewing PinMe Worker (Cloudflare Worker TypeScript) code that accepts payments through UniwebPay — payment links, products/prices, checkout sessions, payment status reads, refunds, subscriptions, or handling UniwebPay webhooks with @uniwebpay/sdk in a PinMe project.","permissions":[],"systemPrompt":"# PinMe UniwebPay Payment Integration\n\nGuides writing payment services in a PinMe Worker (Cloudflare Worker TypeScript) that call UniwebPay directly through `@uniwebpay/sdk`.\n\nCore model: PinMe provisions the UniwebPay wallet and keys per **PinMe user** (not per project) and injects `UNIWEB_*` environment bindings at Worker deploy time; Worker code calls UniwebPay **directly with the SDK** — it does not go through PinMe payment proxy routes, and it must not call the legacy VibeCash APIs.\n\n## Environment Binding Contract\n\n```typescript\nexport interface Env {\n  UNIWEB_SECRET: string;           // PinMe-provisioned sk_server_ key (server-side only)\n  UNIWEB_WEBHOOK_SECRET?: string;  // wallet-level whsec_, used to verify webhook signatures\n  UNIWEB_API_URL?: string;         // UniwebPay API endpoint override (default https://apiskill.uniwebpay.com)\n  UNIWEB_PAY_URL?: string;         // UniwebPay checkout host override (default https://skill.uniwebpay.com)\n  UNIWEB_WALLET_ID?: string;       // user-level wallet id (wal_), diagnostics/reconciliation only\n  WORKER_URL?: string;             // this project's public URL: https://{projectName}.{platform api domain}\n  PROJECT_NAME?: string;           // PinMe project name\n  DB?: D1Database;                 // project D1 (if enabled)\n}\n```\n\nInjection rules (metadata is rebuilt server-side by PinMe at deploy time; client-supplied bindings are ignored):\n\n- The `UNIWEB_*` bindings are injected only after the user's UniwebPay credentials have been provisioned. Newly created projects are provisioned automatically and get them immediately; **existing projects must be redeployed after enabling UniwebPay or rotating keys** to pick up new bindings.\n- `WORKER_URL`, `PROJECT_NAME`, `API_KEY`, `DB` and other base bindings are injected on every deploy, independent of UniwebPay.\n- All projects owned by the same PinMe user share one wallet, one `sk_server_`, and one `whsec_`.\n- PinMe never gives the full wallet secret (`sk_live_`) to a Worker. Do not ask the user for it, and do not put it in code, `wrangler.toml`, `.dev.vars`, responses, logs, D1, or frontend bundles.\n- If `UNIWEB_SECRET` is missing at runtime, the user has not enabled UniwebPay or has not redeployed — tell the user to enable it and redeploy; never fabricate a value.\n\n## SDK Client\n\nAlways instantiate on the server side (the Worker); the SDK throws when run in a browser:\n\n```typescript\nimport Uniweb from \"@uniwebpay/sdk\";\n\nfunction uniwebClient(env: Env): Uniweb {\n  return new Uniweb(env.UNIWEB_SECRET, {\n    baseUrl: env.UNIWEB_API_URL,\n    payUrl: env.UNIWEB_PAY_URL,\n  });\n}\n```\n\n- The constructor's first positional argument is the key (must have an `sk_server_` or `sk_live_` prefix); the second is optional options: `{ baseUrl?, payUrl?, timeout? (default 30s), maxRetries? (default 2) }`.\n- The SDK auto-retries only GET/DELETE on 429/5xx; POST/PATCH are never retried (avoids duplicate charges).\n- Install `@uniwebpay/sdk` only when Worker code imports it; pick the package manager from the project's existing lockfile.\n\n## Choosing an Integration Path\n\n| Scenario | Approach | Returns |\n|------|------|------|\n| Fixed-amount one-time collection | `uniweb.links.create(...)` | Permanent, reusable `/p/` link (one-time payments only) |\n| Stable product catalog | `products.create` + `prices.create` once, store the `priceId` | Price carries a permanent `paymentUrl` (`/buy/` link) |\n| Dynamic cart/order | Reuse or create a price, then `uniweb.checkout.create(...)` | `session.url` — **one-time, expires in 24 hours** |\n| Subscriptions | Recurring price + `checkout.create({ mode: \"subscription\" })` or `subscriptions.create` | Same as above |\n| Server-side payment status checks | `payments.get / list` | Server routes only |\n\nAmounts are always **integer minor units** (cents). Default currency convention is `SGD` unless the app has a stronger existing convention. Do not create a new product/price on every page view — create stable catalog items once and persist the `priceId`.\n\n## Payment Methods and Currency Rules\n\n| Method | Supported currencies |\n|------|---------|\n| `card` | SGD, USD, EUR, GBP, JPY, CNY, HKD, AUD, MYR, THB (minimum 10 minor units) |\n| `wechat` | SGD only |\n| `alipay` | SGD only |\n| `paynow` | SGD only |\n\n- The QR methods (wechat/alipay/paynow) **all support SGD only** — never generate \"CNY via WeChat/Alipay\" code.\n- Subscriptions (recurring / `mode: \"subscription\"`) use `card` only.\n- When `paymentMethodTypes` is omitted, the server picks sensible defaults for the currency; when passed explicitly, validate user input against the table above first.\n\n## SDK Surface Quick Reference\n\nThe surface below is verified against source. All parameter fields are camelCase (`priceId`, `webhookUrl`, `startingAfter`, …); the SDK handles wire-level conversion itself. `list()` returns `{ data: T[], hasMore: boolean }`; `listAll()` is an async generator available on products, prices, payments, customers, subscriptions, and links (not on checkout or refunds).\n\nProducts (`webhookUrl` is the per-product callback override):\n\n```typescript\nawait uniweb.products.create({ name, description?, webhookUrl?, metadata? });\nawait uniweb.products.list({ limit?, startingAfter? });\nawait uniweb.products.get(productId);\nawait uniweb.products.update(productId, { name?, description?, webhookUrl?, active?, metadata? });\nawait uniweb.products.del(productId);\nfor await (const product of uniweb.products.listAll()) {}\n```\n\nPrices (the returned price carries a permanent `paymentUrl`; `deactivate` takes it off sale):\n\n```typescript\nawait uniweb.prices.create({\n  productId,\n  amount,        // integer minor units\n  currency,      // e.g. \"SGD\"\n  type,          // \"one_time\" | \"recurring\"\n  interval?,     // \"day\" | \"week\" | \"month\" | \"year\"; recurring only\n  intervalCount?,\n  trialPeriodDays?,\n  metadata?,\n});\nawait uniweb.prices.list({ productId?, limit?, startingAfter? });\nawait uniweb.prices.get(priceId);\nawait uniweb.prices.update(priceId, { active });\nawait uniweb.prices.activate(priceId);\nawait uniweb.prices.deactivate(priceId);\nfor await (const price of uniweb.prices.listAll({ productId? })) {}\n```\n\nCheckout sessions (**do not accept `webhookUrl`** — events resolve through the price → product → wallet chain; the URL is one-time and expires after 24 hours):\n\n```typescript\nawait uniweb.checkout.create({\n  mode,           // \"payment\" | \"subscription\"\n  lineItems: [{ priceId, quantity }],\n  successUrl?,\n  cancelUrl?,\n  customerEmail?,\n  customerId?,\n  trialPeriodDays?,\n  paymentMethodTypes?, // [\"card\", \"wechat\", \"alipay\", \"paynow\"]\n  metadata?,\n});\nawait uniweb.checkout.list({ limit?, startingAfter? });\nawait uniweb.checkout.get(checkoutSessionId);\n```\n\nPayments (for server-side status checks; only mark a local order paid when amount, currency, metadata, and order state all match expectations):\n\n```typescript\nawait uniweb.payments.create({ amount, currency, customerId?, metadata? });\nawait uniweb.payments.list({ status?, customerId?, limit?, startingAfter? });\nawait uniweb.payments.get(paymentId, { gateway? });\nawait uniweb.payments.listRefunds(paymentId);\nawait uniweb.payments.sync(paymentId);\nawait uniweb.payments.void(paymentId);\nfor await (const payment of uniweb.payments.listAll({ status?, customerId? })) {}\n```\n\nRefunds (no list/listAll — use `payments.listRefunds`):\n\n```typescript\nawait uniweb.refunds.create({ paymentId, amount?, reason?, offlineRefundFlag? });\nawait uniweb.refunds.get(refundId, { gateway? });\n```\n\nCustomers:\n\n```typescript\nawait uniweb.customers.create({ email, name?, metadata? });\nawait uniweb.customers.list({ email?, limit?, startingAfter? });\nawait uniweb.customers.get(customerId);\nawait uniweb.customers.update(customerId, { email?, name?, metadata? });\nawait uniweb.customers.del(customerId);\nfor await (const customer of uniweb.customers.listAll({ email? })) {}\n```\n\nSubscriptions (states include `trialing` / `active` / `past_due` / `unpaid` / `canceled`; update access only from verified webhooks or a trusted server-side reconciliation job):\n\n```typescript\nawait uniweb.subscriptions.create({ customerId, priceId, paymentMethodId?, trialPeriodDays?, metadata? });\nawait uniweb.subscriptions.list({ customerId?, status?, limit?, startingAfter? });\nawait uniweb.subscriptions.get(subscriptionId);\nawait uniweb.subscriptions.update(subscriptionId, { cancelAtPeriodEnd? });\nawait uniweb.subscriptions.cancel(subscriptionId); // cancel immediately\nawait uniweb.subscriptions.resume(subscriptionId); // undo cancelAtPeriodEnd\nfor await (const subscription of uniweb.subscriptions.listAll({ customerId?, status? })) {}\n```\n\nPayment links (permanent reusable `/p/` links, one-time collection only; `webhookUrl` is the per-link callback override):\n\n```typescript\nawait uniweb.links.create({\n  amount,\n  currency,\n  name?,\n  description?,\n  successUrl?,\n  cancelUrl?,\n  webhookUrl?,\n  paymentMethodTypes?,\n  metadata?,\n});\nawait uniweb.links.list({ limit?, startingAfter? });\nawait uniweb.links.get(paymentLinkId);\nawait uniweb.links.update(paymentLinkId, { name?, description?, successUrl?, cancelUrl?, webhookUrl?, active? });\nawait uniweb.links.deactivate(paymentLinkId);\nfor await (const link of uniweb.links.listAll()) {}\n```\n\nWallet and wallet-level webhook configuration (**danger zone**: affects the wallet shared by ALL of the user's projects):\n\n```typescript\nawait uniweb.wallet.current();\nawait uniweb.wallet.update({ merchantName?, merchantCity?, merchantCountry?, webhookUrl? });\nawait uniweb.webhooks.set(url);       // overwrites the wallet-level callback URL\nawait uniweb.webhooks.info();\nawait uniweb.webhooks.remove();\nawait uniweb.webhooks.rollSecret();   // rotates the shared whsec_\n```\n\nOrdinary project routes must **not** call `webhooks.set / remove / rollSecret` or `wallet.update` — they mutate the wallet callback fallback and signing secret shared across all of the user's projects. Generate them only when the user explicitly asks for wallet administration and the route has project/admin-level authorization. Same for refunds, subscription mutations, payouts, KYC, and bank account APIs: generate only when the user explicitly requests that business flow and the code has validation, persistence, and authorization.\n\n## Webhook Integration\n\n### Callback URL: set it on the link/product, pointing at this Worker\n\nEvent delivery precedence: **per-link `webhookUrl` > per-product `webhookUrl` > wallet-level fallback**. The signing secret is always the wallet-level `whsec_` (i.e. `env.UNIWEB_WEBHOOK_SECRET`).\n\nPinMe sets a managed fallback callback URL on the wallet, but it exists only to obtain and preserve the signing secret — **PinMe's server discards events it receives there (204); it never forwards them to the Worker**. Business events must therefore set this project's `webhookUrl` explicitly on the resource that creates the payment:\n\n- Payment links: pass `webhookUrl` on `links.create`.\n- Checkout sessions: `checkout.create` has no `webhookUrl` field; events route through the price's product — set `webhookUrl` on `products.create` (or on the reused product).\n\nRules for building the `webhookUrl`:\n\n- Keep the callback path in a single constant (e.g. `const WEBHOOK_PATH = \"/api/pay/webhook\"`) shared by the router and the `webhookUrl` construction, so a path mismatch can't 404 the callbacks and leave orders stuck in pending.\n- Use `env.WORKER_URL` as the base: `new URL(WEBHOOK_PATH, env.WORKER_URL).toString()`. It is the only public address available at runtime (the platform subdomain); the user's custom domain is not in `env`. Prefer it over `request.url` (the current request's host is not necessarily the deployed address), and non-HTTP contexts (cron/queue) have no request at all — fail loudly if it's missing rather than emitting a broken URL.\n- Local dev has no `WORKER_URL`; a `request.url` fallback resolves to localhost, which UniwebPay cannot reach. To test webhooks locally, expose the Worker through a tunnel (cloudflared / ngrok).\n- `webhookUrl` must be HTTPS. Put no secrets or trust-bearing data in the URL query — carry correlation like `orderId` in `metadata`, and verify identity from the signature plus `metadata` (a query string can be forged).\n\n### Verification and Handling\n\n```typescript\nimport { verifyWebhook } from \"@uniwebpay/sdk\";\n\nconst rawBody = await request.text();              // read the raw body exactly once\nconst event = await verifyWebhook(                  // note: async\n  rawBody,\n  request.headers.get(\"uniweb-Signature\") || \"\",   // format: t=<unix>,v1=<hex>\n  env.UNIWEB_WEBHOOK_SECRET,\n);\n```\n\n- `verifyWebhook(rawBody, signature, secret)` returns `Promise<WebhookEvent>`; signature timestamp tolerance is ±5 minutes; it throws on failure.\n- Event shape: `{ id: \"evt_...\", type, created, data: { object, productId?, priceId?, productName? } }`. The business object is in `event.data.object`; correlation like `orderId` is in `event.data.object.metadata`.\n- Event types verified as actually delivered: `payment.succeeded` / `payment.failed` / `payment.refunded` / `payment.partially_refunded`, `refund.succeeded` / `refund.failed` / `refund.abandoned`, `checkout.session.completed` / `checkout.session.expired`, `subscription.created` / `subscription.renewed` / `subscription.past_due` / `subscription.unpaid` / `subscription.trial_ending` / `subscription.canceled`.\n\nHandling rules:\n\n- **The webhook route must bypass the project's own auth.** UniwebPay callbacks carry only `uniweb-Signature` (plus `uniweb-Event-Id` / `uniweb-Timestamp`), never the project `API_KEY`. If a global auth guard wraps all routes, exempt `WEBHOOK_PATH` — trust comes solely from signature verification. Otherwise callbacks get 401/403 and orders never fulfill.\n- Return 400 for invalid signatures (so UniwebPay stops pointless retries); return 500 for temporary processing failures (so it retries).\n- Enforce idempotency with `event.id` (combined with payment id / checkout session id / local order id).\n- Before fulfillment, verify amount, currency, metadata, and current order state.\n- Respond within 10 seconds; delivery does not follow redirects, so do not put the webhook route behind a redirect. The first delivery is immediate; on failure, retries follow at 5-minute, 30-minute, 2-hour, and 12-hour intervals, up to 6 attempts before the event is marked failed.\n- Keep `UNIWEB_WEBHOOK_SECRET` optional in TypeScript — a project can exist before provisioning or redeploy; return 501 with a hint when it's missing at runtime.\n\n## Security Rules\n\n- No Uniweb secret (`UNIWEB_SECRET`, `UNIWEB_WEBHOOK_SECRET`) may appear in responses, logs, metadata, test snapshots, D1, source code, committed `wrangler.toml` / `.dev.vars`, or browser code. For local dev, use an uncommitted `.dev.vars` only.\n- Do not import the SDK in browser-side code; do not use `process.env` in Cloudflare Workers — use the `env` argument.\n- Do not call legacy VibeCash APIs or PinMe payment proxy routes; do not call PinMe payment APIs with `X-API-Key` for UniwebPay collection — the Worker calls UniwebPay directly through the SDK.\n- `successUrl` / `cancelUrl` are UX redirects only. **Never fulfill based on a browser redirect**; grant access only after verified webhook processing (or another explicit server-side verification).\n- Validate user input before SDK calls: amount (integer minor units), currency (ISO 4217 and within the payment-method constraints), quantity, product/price IDs, payment method types, order ownership, and metadata shape.\n\n## Persistence Guidance (D1)\n\nAdd tables/migrations only when the project already uses D1 or the user asks for persistence. For order flows, store at least: local order id, the corresponding Uniweb link/session/payment/subscription id, amount and currency, status, timestamps, and processed webhook event ids (for idempotency). Never store secrets.\n\n```sql\nCREATE TABLE IF NOT EXISTS orders (\n  order_id TEXT PRIMARY KEY,\n  checkout_session_id TEXT UNIQUE,\n  status TEXT NOT NULL DEFAULT 'pending',\n  amount_cents INTEGER NOT NULL,\n  currency TEXT NOT NULL,\n  paid_at INTEGER,\n  created_at INTEGER NOT NULL,\n  updated_at INTEGER\n);\n\nCREATE TABLE IF NOT EXISTS payment_events (\n  event_id TEXT PRIMARY KEY,\n  event_type TEXT NOT NULL,\n  order_id TEXT,\n  raw_payload TEXT NOT NULL,\n  created_at INTEGER NOT NULL\n);\n```\n\n## Worker Reference Implementation\n\n```typescript\nimport Uniweb, { verifyWebhook } from \"@uniwebpay/sdk\";\n\nexport interface Env {\n  UNIWEB_SECRET: string;\n  UNIWEB_WEBHOOK_SECRET?: string;\n  UNIWEB_API_URL?: string;\n  UNIWEB_PAY_URL?: string;\n  UNIWEB_WALLET_ID?: string;\n  WORKER_URL?: string;\n  PROJECT_NAME?: string;\n  DB?: D1Database;\n}\n\ntype PaymentMethod = \"card\" | \"wechat\" | \"alipay\" | \"paynow\";\n\nconst VALID_PAYMENT_METHODS = new Set<PaymentMethod>([\"card\", \"wechat\", \"alipay\", \"paynow\"]);\nconst CARD_CURRENCIES = new Set([\"SGD\", \"USD\", \"EUR\", \"GBP\", \"JPY\", \"CNY\", \"HKD\", \"AUD\", \"MYR\", \"THB\"]);\n\n// Single source of truth for the webhook path: shared by the router and the\n// webhookUrl construction so the address sent to UniwebPay always matches the\n// route the Worker actually serves.\nconst WEBHOOK_PATH = \"/api/pay/webhook\";\n\nfunction uniwebClient(env: Env): Uniweb {\n  return new Uniweb(env.UNIWEB_SECRET, {\n    baseUrl: env.UNIWEB_API_URL,\n    payUrl: env.UNIWEB_PAY_URL,\n  });\n}\n\nfunction json(data: unknown, init: ResponseInit = {}): Response {\n  return Response.json(data, init);\n}\n\nfunction assertAmountCents(value: unknown): number {\n  const amount = Number(value);\n  if (!Number.isInteger(amount) || amount < 10) {\n    throw new Error(\"amountCents must be an integer minor-unit amount >= 10\");\n  }\n  return amount;\n}\n\nfunction normalizeCurrency(value: unknown): string {\n  const currency = String(value || \"SGD\").toUpperCase();\n  if (!/^[A-Z]{3}$/.test(currency)) throw new Error(\"currency must be an ISO 4217 code\");\n  return currency;\n}\n\n// QR methods (wechat/alipay/paynow) support SGD only; card supports 10 currencies.\nfunction defaultPaymentMethods(currency: string): PaymentMethod[] {\n  if (currency === \"SGD\") return [\"card\", \"wechat\", \"alipay\", \"paynow\"];\n  if (CARD_CURRENCIES.has(currency)) return [\"card\"];\n  throw new Error(`unsupported currency: ${currency}`);\n}\n\nfunction normalizePaymentMethods(value: unknown, currency: string): PaymentMethod[] {\n  const requested = Array.isArray(value) && value.length > 0 ? value : defaultPaymentMethods(currency);\n  const methods = requested.map((m) => String(m).toLowerCase() as PaymentMethod);\n  for (const method of methods) {\n    if (!VALID_PAYMENT_METHODS.has(method)) {\n      throw new Error(\"paymentMethodTypes contains an unsupported method\");\n    }\n    if (method !== \"card\" && currency !== \"SGD\") {\n      throw new Error(`${method} only supports SGD payments`);\n    }\n    if (method === \"card\" && !CARD_CURRENCIES.has(currency)) {\n      throw new Error(`card does not support ${currency}`);\n    }\n  }\n  return Array.from(new Set(methods));\n}\n\n// Prefer the PinMe-injected WORKER_URL (the project's platform subdomain, the\n// only public address available at runtime). request.url is only a fallback for\n// older deploys; cron/queue contexts have no request, so WORKER_URL is required.\nfunction projectWebhookUrl(env: Env, request?: Request): string {\n  const base = env.WORKER_URL || request?.url;\n  if (!base) throw new Error(\"WORKER_URL binding is missing\");\n  return new URL(WEBHOOK_PATH, base).toString();\n}\n\n// ---- One-time collection: payment link ----\n\nasync function createPaymentLink(request: Request, env: Env): Promise<Response> {\n  if (request.method !== \"POST\") return json({ error: \"method not allowed\" }, { status: 405 });\n\n  let input: any;\n  try {\n    input = await request.json();\n  } catch {\n    return json({ error: \"invalid JSON body\" }, { status: 400 });\n  }\n\n  let amount: number, currency: string, paymentMethodTypes: PaymentMethod[];\n  try {\n    amount = assertAmountCents(input.amountCents);\n    currency = normalizeCurrency(input.currency);\n    paymentMethodTypes = normalizePaymentMethods(input.paymentMethodTypes, currency);\n  } catch (err) {\n    return json({ error: (err as Error).message }, { status: 400 });\n  }\n\n  const orderId = input.orderId || crypto.randomUUID();\n  const uniweb = uniwebClient(env);\n\n  try {\n    const link = await uniweb.links.create({\n      amount,\n      currency,\n      name: input.name || \"Payment\",\n      description: input.description,\n      successUrl: input.successUrl,\n      cancelUrl: input.cancelUrl,\n      webhookUrl: projectWebhookUrl(env, request),\n      paymentMethodTypes,\n      metadata: { orderId, projectName: env.PROJECT_NAME },\n    });\n    return json({ orderId, linkId: link.id, url: link.url });\n  } catch {\n    return json({ error: \"failed to create payment link\" }, { status: 502 });\n  }\n}\n\n// ---- Dynamic orders: checkout session ----\n// Note: checkout.create has no webhookUrl; the callback is set on the product.\n// Stable catalog items should create the product/price once and persist the\n// priceId — do not create new ones on every request.\n\nasync function createCheckoutSession(request: Request, env: Env): Promise<Response> {\n  if (request.method !== \"POST\") return json({ error: \"method not allowed\" }, { status: 405 });\n\n  let input: any;\n  try {\n    input = await request.json();\n  } catch {\n    return json({ error: \"invalid JSON body\" }, { status: 400 });\n  }\n\n  let amount: number, currency: string, paymentMethodTypes: PaymentMethod[];\n  try {\n    amount = assertAmountCents(input.amountCents);\n    currency = normalizeCurrency(input.currency);\n    paymentMethodTypes = normalizePaymentMethods(input.paymentMethodTypes, currency);\n  } catch (err) {\n    return json({ error: (err as Error).message }, { status: 400 });\n  }\n\n  const orderId = input.orderId || crypto.randomUUID();\n  const quantity = Math.max(1, Math.floor(Number(input.quantity || 1)));\n  const uniweb = uniwebClient(env);\n\n  try {\n    const product = await uniweb.products.create({\n      name: input.productName,\n      webhookUrl: projectWebhookUrl(env, request),\n      metadata: { orderId, projectName: env.PROJECT_NAME },\n    });\n    const price = await uniweb.prices.create({\n      productId: product.id,\n      amount,\n      currency,\n      type: \"one_time\",\n      metadata: { orderId, projectName: env.PROJECT_NAME },\n    });\n    const session = await uniweb.checkout.create({\n      mode: \"payment\",\n      lineItems: [{ priceId: price.id, quantity }],\n      successUrl: input.successUrl,\n      cancelUrl: input.cancelUrl,\n      customerEmail: input.customerEmail,\n      paymentMethodTypes,\n      metadata: { orderId, projectName: env.PROJECT_NAME },\n    });\n\n    if (env.DB) {\n      await env.DB.prepare(\n        `INSERT INTO orders(order_id, checkout_session_id, status, amount_cents, currency, created_at)\n         VALUES (?, ?, 'pending', ?, ?, ?)\n         ON CONFLICT(order_id) DO UPDATE SET checkout_session_id = excluded.checkout_session_id`,\n      )\n        .bind(orderId, session.id, amount * quantity, currency, Math.floor(Date.now() / 1000))\n        .run();\n    }\n\n    return json({ orderId, checkoutSessionId: session.id, url: session.url });\n  } catch {\n    return json({ error: \"failed to create checkout session\" }, { status: 502 });\n  }\n}\n\n// ---- Webhook handling ----\n\nasync function handleUniwebWebhook(request: Request, env: Env): Promise<Response> {\n  if (request.method !== \"POST\") return json({ error: \"method not allowed\" }, { status: 405 });\n  if (!env.UNIWEB_WEBHOOK_SECRET) {\n    return json({ error: \"webhook verification is not configured\" }, { status: 501 });\n  }\n\n  const rawBody = await request.text();\n  let event: Awaited<ReturnType<typeof verifyWebhook>>;\n  try {\n    event = await verifyWebhook(\n      rawBody,\n      request.headers.get(\"uniweb-Signature\") || \"\",\n      env.UNIWEB_WEBHOOK_SECRET,\n    );\n  } catch {\n    return json({ error: \"invalid signature\" }, { status: 400 });\n  }\n\n  try {\n    if (env.DB) {\n      const object = event.data.object as { metadata?: Record<string, unknown> };\n      const orderId = String(object?.metadata?.orderId || \"\");\n      const now = Math.floor(Date.now() / 1000);\n\n      // event.id idempotency: duplicate deliveries become no-ops\n      await env.DB.prepare(\n        `INSERT INTO payment_events(event_id, event_type, order_id, raw_payload, created_at)\n         VALUES (?, ?, ?, ?, ?)\n         ON CONFLICT(event_id) DO NOTHING`,\n      )\n        .bind(event.id, event.type, orderId, rawBody, now)\n        .run();\n\n      if (event.type === \"payment.succeeded\" && orderId) {\n        // Production code should verify amount/currency/order state here before fulfilling\n        await env.DB.prepare(\n          `UPDATE orders SET status = 'paid', paid_at = ?, updated_at = ? WHERE order_id = ? AND status != 'paid'`,\n        )\n          .bind(now, now, orderId)\n          .run();\n      }\n    }\n    return json({ ok: true });\n  } catch {\n    // 500 makes UniwebPay retry on the 5m/30m/2h/12h schedule\n    return json({ error: \"processing error\" }, { status: 500 });\n  }\n}\n\n// ---- Router ----\n\nexport default {\n  async fetch(request: Request, env: Env): Promise<Response> {\n    const url = new URL(request.url);\n\n    // The webhook must come before any project auth guard: callbacks carry only\n    // uniweb-Signature, never the project API_KEY.\n    if (url.pathname === WEBHOOK_PATH) return handleUniwebWebhook(request, env);\n\n    // The project's own auth guard goes after this point, on the business routes.\n    if (url.pathname === \"/api/pay/link\") return createPaymentLink(request, env);\n    if (url.pathname === \"/api/pay/checkout\") return createCheckoutSession(request, env);\n\n    return json({ error: \"not found\" }, { status: 404 });\n  },\n};\n```\n\n## Common Mistakes\n\n| Mistake | Consequence / fix |\n|------|----------|\n| Webhook route blocked by the project's `API_KEY` / bearer auth guard | Callbacks get 401/403 and orders stay pending forever. Exempt `WEBHOOK_PATH`; trust comes solely from signature verification |\n| Forgetting to set `webhookUrl` on the link/product | Events fall through to PinMe's managed fallback and are discarded; the Worker never sees them. Business events must point per-link/per-product at this Worker |\n| Passing `webhookUrl` to `checkout.create` | The field does not exist. Set it on the backing product |\n| Fulfilling on a `successUrl` redirect | Forgeable. Fulfill only from verified webhooks or server-side verification |\n| Hardcoding the callback host or relying only on `request.url` | Build from `env.WORKER_URL`; `request.url` is a fallback only |\n| Pairing CNY with wechat/alipay | Source limits QR methods to SGD only; CNY can only use card |\n| Creating a new product/price on every request | Create stable catalog items once, persist and reuse the `priceId` |\n| Calling `webhooks.set/remove/rollSecret` or `wallet.update` in ordinary business flows | Mutates/rotates the wallet callback and `whsec_` shared by ALL of the user's projects. Generate only for explicit wallet-administration requests with admin authorization |\n| Using floating-point major units for amounts | Always integer minor units |\n| Using `process.env` in the Worker or importing the SDK in the browser | Use the `env` argument; the SDK rejects browser environments |\n| Putting `UNIWEB_SECRET` / `whsec_` in `wrangler.toml`, source, logs, or D1 | PinMe injects them at deploy time; locally use an uncommitted `.dev.vars` only |\n| Reading the body more than once, or as JSON, before verification | Read with `request.text()` exactly once and pass the raw string to `verifyWebhook` |\n\n## Finish Checklist\n\n- [ ] `@uniwebpay/sdk` is installed only when Worker code imports it; package manager follows the lockfile.\n- [ ] `Env` includes the PinMe-injected bindings the code uses; `UNIWEB_WEBHOOK_SECRET` / `WORKER_URL` stay optional and their absence is handled.\n- [ ] The client is instantiated with `new Uniweb(env.UNIWEB_SECRET, { baseUrl: env.UNIWEB_API_URL, payUrl: env.UNIWEB_PAY_URL })`.\n- [ ] No VibeCash or PinMe payment proxy routes are used; no secret appears in source, responses, logs, D1, tests, or docs.\n- [ ] Amounts are validated integer minor units; payment methods and currencies follow the constraint table (QR methods SGD only).\n- [ ] Every payment creation that needs events carries a per-link/per-product `webhookUrl` built from `env.WORKER_URL`.\n- [ ] Webhook: raw body read exactly once, `verifyWebhook` verification, correct 400/500 semantics, `event.id` idempotency, route bypasses project auth, responds within 10 seconds.\n- [ ] Fulfillment does not rely on browser redirects; amount, currency, metadata, and order state are verified before granting access.","schemaVersion":1},"repoUrl":"https://github.com/glitternetwork/pinme/tree/main/skills/pinme-uniwebpay","tags":["ai-tools","claude-code-skill","claude-skills","deployment","deployment-tools","frontend","frontend-deployment","hosting","serverless","skills","static-site","static-site-deploy"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pinme","audit":{"files":["package-lock.json","package.json","pnpm-lock.yaml"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip: Uncontrolled memory allocation via the declared uncompressed size (DoS).","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-7q85-xj36-vmfc · npm:adm-zip@0.5.17","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip extraction follows destination symlinks, allowing arbitrary file overwrite.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-vwc7-r8mq-g2x9 · npm:adm-zip@0.5.17","severity":"medium"},{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip: Crafted ZIP file triggers 4GB memory allocation.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-xcpc-8h2w-3j85 · npm:adm-zip@0.5.17","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"uuid@9.0.1 has a known vulnerability: uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-w5hq-g745-h8pq · npm:uuid@9.0.1","severity":"medium"}],"packages":16,"auditedAt":"2026-09-25T11:51:56.672Z","lockfiles":["package-lock.json","pnpm-lock.yaml"]},"forks":277,"owner":"glitternetwork","stars":3745,"topics":["ai-tools","claude-code-skill","claude-skills","deployment","deployment-tools","frontend","frontend-deployment","hosting","serverless","skills","static-site","static-site-deploy","static-site-hosting","web-hosting","zero-configuration"],"license":"MIT","fullName":"glitternetwork/pinme","homepage":"https://pinme.eth.limo","language":"TypeScript","pushedAt":"2026-09-12T05:23:49Z","avatarUrl":"https://avatars.githubusercontent.com/u/102277171?v=4","crawledAt":"2026-09-25T11:51:44.477Z","openIssues":7,"manifestFile":"SKILL.md","manifestPath":"skills/pinme-uniwebpay/SKILL.md","defaultBranch":"main"},"readme":"# PinMe UniwebPay Payment Integration\n\nGuides writing payment services in a PinMe Worker (Cloudflare Worker TypeScript) that call UniwebPay directly through `@uniwebpay/sdk`.\n\nCore model: PinMe provisions the UniwebPay wallet and keys per **PinMe user** (not per project) and injects `UNIWEB_*` environment bindings at Worker deploy time; Worker code calls UniwebPay **directly with the SDK** — it does not go through PinMe payment proxy routes, and it must not call the legacy VibeCash APIs.\n\n## Environment Binding Contract\n\n```typescript\nexport interface Env {\n  UNIWEB_SECRET: string;           // PinMe-provisioned sk_server_ key (server-side only)\n  UNIWEB_WEBHOOK_SECRET?: string;  // wallet-level whsec_, used to verify webhook signatures\n  UNIWEB_API_URL?: string;         // UniwebPay API endpoint override (default https://apiskill.uniwebpay.com)\n  UNIWEB_PAY_URL?: string;         // UniwebPay checkout host override (default https://skill.uniwebpay.com)\n  UNIWEB_WALLET_ID?: string;       // user-level wallet id (wal_), diagnostics/reconciliation only\n  WORKER_URL?: string;             // this project's public URL: https://{projectName}.{platform api domain}\n  PROJECT_NAME?: string;           // PinMe project name\n  DB?: D1Database;                 // project D1 (if enabled)\n}\n```\n\nInjection rules (metadata is rebuilt server-side by PinMe at deploy time; client-supplied bindings are ignored):\n\n- The `UNIWEB_*` bindings are injected only after the user's UniwebPay credentials have been provisioned. Newly created projects are provisioned automatically and get them immediately; **existing projects must be redeployed after enabling UniwebPay or rotating keys** to pick up new bindings.\n- `WORKER_URL`, `PROJECT_NAME`, `API_KEY`, `DB` and other base bindings are injected on every deploy, independent of UniwebPay.\n- All projects owned by the same PinMe user share one wallet, one `sk_server_`, and one `whsec_`.\n- PinMe never gives the full wallet secret (`sk_live_`) to a Worker. Do not ask the user for it, and do not put it in code, `wrangler.toml`, `.dev.vars`, responses, logs, D1, or frontend bundles.\n- If `UNIWEB_SECRET` is missing at runtime, the user has not enabled UniwebPay or has not redeployed — tell the user to enable it and redeploy; never fabricate a value.\n\n## SDK Client\n\nAlways instantiate on the server side (the Worker); the SDK throws when run in a browser:\n\n```typescript\nimport Uniweb from \"@uniwebpay/sdk\";\n\nfunction uniwebClient(env: Env): Uniweb {\n  return new Uniweb(env.UNIWEB_SECRET, {\n    baseUrl: env.UNIWEB_API_URL,\n    payUrl: env.UNIWEB_PAY_URL,\n  });\n}\n```\n\n- The constructor's first positional argument is the key (must have an `sk_server_` or `sk_live_` prefix); the second is optional options: `{ baseUrl?, payUrl?, timeout? (default 30s), maxRetries? (default 2) }`.\n- The SDK auto-retries only GET/DELETE on 429/5xx; POST/PATCH are never retried (avoids duplicate charges).\n- Install `@uniwebpay/sdk` only when Worker code imports it; pick the package manager from the project's existing lockfile.\n\n## Choosing an Integration Path\n\n| Scenario | Approach | Returns |\n|------|------|------|\n| Fixed-amount one-time collection | `uniweb.links.create(...)` | Permanent, reusable `/p/` link (one-time payments only) |\n| Stable product catalog | `products.create` + `prices.create` once, store the `priceId` | Price carries a permanent `paymentUrl` (`/buy/` link) |\n| Dynamic cart/order | Reuse or create a price, then `uniweb.checkout.create(...)` | `session.url` — **one-time, expires in 24 hours** |\n| Subscriptions | Recurring price + `checkout.create({ mode: \"subscription\" })` or `subscriptions.create` | Same as above |\n| Server-side payment status checks | `payments.get / list` | Server routes only |\n\nAmounts are always **integer minor units** (cents). Default currency convention is `SGD` unless the app has a stronger existing convention. Do not create a new product/price on every page view — create stable catalog items once a","createdAt":"2026-09-25T11:51:56.752Z","updatedAt":"2026-09-25T11:51:56.752Z"},{"id":"cmugwhsgt01h5qu061uk1kqqe","slug":"glitternetwork-pinme-pinme","name":"pinme","description":"Use this skill when the user mentions \"pinme\", or needs to upload files, store to IPFS, create/publish/deploy websites or full-stack services (including frontend pages, backend APIs, database storage, email sending, etc.), or any feature requiring backend database/server support.","authorId":"gh:glitternetwork","authorName":"glitternetwork","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":3745,"pricePerCall":0,"manifest":{"name":"pinme","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Use this skill when the user mentions \"pinme\", or needs to upload files, store to IPFS, create/publish/deploy websites or full-stack services (including frontend pages, backend APIs, database storage, email sending, etc.), or any feature requiring backend database/server support.","permissions":[],"systemPrompt":"# PinMe\n\nZero-config deployment tool: upload static files to IPFS, or create and deploy full-stack web projects (React+Vite + Cloudflare Worker + D1 database). Workers also support sending emails via the PinMe platform API.\n\n## When to Use\n\n```dot\ndigraph pinme_decision {\n    \"User Request\" [shape=doublecircle];\n    \"Needs backend API or database?\" [shape=diamond];\n    \"Upload Files (Path 1)\" [shape=box];\n    \"Full-Stack Project (Path 2)\" [shape=box];\n\n    \"User Request\" -> \"Needs backend API or database?\";\n    \"Needs backend API or database?\" -> \"Upload Files (Path 1)\" [label=\"No\"];\n    \"Needs backend API or database?\" -> \"Full-Stack Project (Path 2)\" [label=\"Yes\"];\n}\n```\n\n## Path 1: Upload Files / Static Sites\n\n> Login required. Use `pinme login` or `pinme set-appkey <AppKey>` before `pinme upload` or `pinme import`.\n\n```dot\ndigraph upload_flow {\n    \"Install/update pinme to latest\" [shape=box];\n    \"Authenticate\" [shape=box];\n    \"Determine build artifacts\" [shape=box];\n    \"pinme upload <path>\" [shape=box];\n    \"Return preview URL\" [shape=doublecircle];\n\n    \"Install/update pinme to latest\" -> \"Authenticate\";\n    \"Authenticate\" -> \"Determine build artifacts\";\n    \"Determine build artifacts\" -> \"pinme upload <path>\";\n    \"pinme upload <path>\" -> \"Return preview URL\";\n}\n```\n\n**1. Check installation and update to latest:**\n```bash\nLOCAL=$(pinme --version 2>/dev/null || echo \"0.0.0\")\nLATEST=$(npm view pinme version)\n[ \"$LOCAL\" != \"$LATEST\" ] && npm install -g pinme@latest || echo \"pinme is up to date ($LOCAL)\"\n```\n\n**2. Authenticate:**\n```bash\npinme login\n# or: pinme set-appkey <AppKey>\n```\n\n**3. Determine upload target** (priority order):\n1. `dist/` — Vite / Vue / React\n2. `build/` — Create React App\n3. `out/` — Next.js static export\n4. `public/` — Plain static files\n\n**4. Upload:**\n```bash\npinme upload <path>\npinme upload ./dist --domain my-site  # Optional: bind subdomain (wallet balance required)\n```\n\n**5. Return** the final URL printed by PinMe to the user. URL priority is: DNS domain > PinMe subdomain > short URL > preview URL. If it falls back to preview, return the **full URL** including all hash characters — do not truncate.\n\n### Common Examples\n\n```bash\npinme upload ./document.pdf          # Single file\npinme upload ./my-folder             # Folder\npinme upload dist                    # Vite/Vue build artifacts\npinme upload build                   # CRA build artifacts\npinme upload out                     # Next.js static export\npinme upload ./dist --domain my-site # Bind PinMe subdomain (wallet balance required)\npinme import ./my-archive.car        # Import CAR file\n```\n\n### Do NOT Upload\n- `node_modules/`, `.env`, `.git/`, `src/`\n- Only upload build artifacts, never upload source code\n\n---\n\n## Path 2: Full-Stack Project\n\n> Login required. Uses React+Vite frontend + Cloudflare Worker backend + D1 SQLite database.\n> When designing frontend projects, use Ant Design as the primary design reference, and prioritize following its conventions for layout, components, spacing, and interaction patterns.\n\n```dot\ndigraph fullstack_flow {\n    \"Install/update pinme to latest\" [shape=box];\n    \"pinme login\" [shape=box];\n    \"pinme create <name>\" [shape=box];\n    \"Modify template code\" [shape=box];\n    \"pinme save\" [shape=box];\n    \"Return preview URL\" [shape=doublecircle];\n\n    \"Install/update pinme to latest\" -> \"pinme login\";\n    \"pinme login\" -> \"pinme create <name>\";\n    \"pinme create <name>\" -> \"Modify template code\";\n    \"Modify template code\" -> \"pinme save\";\n    \"pinme save\" -> \"Return preview URL\";\n}\n```\n\n### Architecture\n\n| Layer | Tech Stack | Deploy Target |\n|-------|-----------|---------------|\n| Frontend | React + Vite (`frontend/`) | IPFS |\n| Backend | Cloudflare Worker (`backend/src/worker.ts`) | `{name}.pinme.pro` |\n| Database | D1 SQLite (`db/*.sql`) | Cloudflare D1 |\n| Object storage | R2 (`env.R2`) | Cloudflare R2 |\n\n### Capability-Specific Skills\n\n- For Worker file uploads, downloads, images, attachments, media, or object storage, use the `pinme-r2` skill. PinMe injects the project bucket as `env.R2`; do not replace it with D1 BLOBs or Worker filesystem state.\n\n### Core Commands\n\n```bash\npinme login                  # Login (only needed once)\npinme create <dirName>       # Clone template and create project (auto-fills API URL)\npinme save                   # First deploy / full update (frontend + backend + database, single command)\npinme update-worker          # Update backend only (when only backend/src/worker.ts was modified)\npinme update-web             # Update frontend only (when only frontend/src/ was modified)\npinme update-db              # Run SQL migrations only (when only db/ was modified)\n```\n\n> `pinme save` deploys frontend + backend + database all at once. Only use `pinme update-*` when you're certain only one part was modified.\n\n### Project Structure\n\n```\n{project}/\n├── pinme.toml              # Root config (auto-generated, do not modify)\n├── package.json            # Monorepo root (workspaces: frontend + backend)\n├── backend/\n│   ├── wrangler.toml       # Worker config (auto-generated, do not modify)\n│   ├── package.json\n│   └── src/\n│       └── worker.ts       # Backend entry — primarily used for JSON APIs in this template\n├── db/\n│   └── 001_init.sql        # SQL table definitions\n├── frontend/\n│   ├── package.json\n│   ├── vite.config.ts      # Dev proxy: /api → localhost:8787\n│   ├── index.html\n│   ├── .env                # Auto-generated: VITE_API_URL (do not modify)\n│   └── src/\n│       ├── main.tsx\n│       ├── App.tsx\n│       ├── utils/\n│       │   ├── api.ts      # export const API = import.meta.env.VITE_WORKER_URL || ''\n│       │   └── config.ts   # Auto-generated: public_client_config (only when auth is enabled)\n│       └── pages/\n│           └── Home/\n│               └── index.tsx\n└── .gitignore\n```\n\n### First Deployment\n\n```bash\nLOCAL=$(pinme --version 2>/dev/null || echo \"0.0.0\")\nLATEST=$(npm view pinme version)\n[ \"$LOCAL\" != \"$LATEST\" ] && npm install -g pinme@latest\npinme login\npinme create my-app\ncd my-app\n```\n\n`pinme create` generates a working Hello World template (includes frontend page + backend API routes + database schema). **Modify the template** to match the user's business logic — do not write from scratch:\n\n- Modify `backend/src/worker.ts` — replace API routes\n- Modify `frontend/src/pages/` — replace page components\n- Modify `db/001_init.sql` — replace table definitions\n\n```bash\npinme save\n# Single command deploys frontend + backend + database\n# Outputs preview URL: https://pinme.eth.limo/#/preview/{CID}\n```\n\n**Return** the preview URL to the user. Note: return the **full URL** including all hash characters — do not truncate.\n\nThe backend Worker is deployed at `https://{name}.pinme.pro`. Frontend API requests are automatically configured to point to that address — no manual setup needed.\n\n### Subsequent Updates\n\n| Changes | Command | Notes |\n|---------|---------|-------|\n| Backend only (`backend/src/worker.ts`) | `pinme update-worker` | Faster |\n| Frontend only (`frontend/src/`) | `pinme update-web` | Generates new CID |\n| Database only (`db/`) | `pinme update-db` | Runs new migrations |\n| Multiple changes or uncertain | `pinme save` | Safe full deployment |\n\n> Each frontend deployment generates a new CID and preview URL. Old URLs remain accessible.\n\n---\n\n## Worker Code Patterns (`backend/src/worker.ts`)\n\nIn this template, the Worker backend is primarily used for JSON APIs. Prefer standard Web APIs and simple manual routing by default. Worker-compatible libraries can be added when needed, but the default template does not rely on extra frameworks. Avoid packages that depend on a full Node.js runtime, a persistent local filesystem, native binaries, or child processes.\n\n```typescript\nexport interface Env {\n  DB: D1Database;           // When using database\n  R2: R2Bucket;             // Project object storage; injected by PinMe\n  API_KEY?: string;         // When using email sending\n  JWT_SECRET: string;       // When using JWT auth\n  ADMIN_PASSWORD: string;   // When using password auth\n}\n\nconst CORS_HEADERS = {\n  'Access-Control-Allow-Origin': '*',\n  'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n  'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-API-Key',\n};\n\nfunction json(data: unknown, status = 200): Response {\n  return Response.json(data, { status, headers: CORS_HEADERS });\n}\n\nexport default {\n  async fetch(request: Request, env: Env): Promise<Response> {\n    const { pathname } = new URL(request.url);\n    const method = request.method;\n\n    if (method === 'OPTIONS') return new Response(null, { status: 204, headers: CORS_HEADERS });\n\n    try {\n      if (pathname === '/api/items' && method === 'GET')  return handleGetItems(env);\n      if (pathname === '/api/items' && method === 'POST') return handleCreateItem(request, env);\n      return json({ error: 'Not found' }, 404);\n    } catch {\n      return json({ error: 'Internal server error' }, 500);\n    }\n  },\n};\n```\n\n### Worker Constraints and Default Conventions\n\n| Item | Notes |\n|------|------|\n| Dependency choice | Prefer standard Web APIs and simple manual routing by default. If extra dependencies are needed, prefer Worker-compatible libraries. |\n| Node.js capability | Workers now support part of Node.js compatibility, but they are not a full Node.js runtime. Do not assume all Node.js built-in modules are available or behave exactly the same. |\n| Filesystem | Do not treat a Worker like a server with a persistent local disk. Even if some `fs` capabilities are available, do not rely on persistence across requests. |\n| Response types | This template mainly uses the Worker for JSON APIs. If there is a clear need, it can also be adapted to return HTML or other content. |\n| Password storage | Never store passwords in plaintext. Use a dedicated password hashing algorithm such as bcrypt, scrypt, or Argon2. |\n| SQL | Do not build SQL by string concatenation. Use parameterized queries such as `.bind()`. |\n\n### Email API Reference (for Worker Backend)\n\nWhen the backend needs email sending, use the PinMe platform API (`https://pinme.cloud/api/v4/send_email`).\n\n**1. Configure API_KEY**\n\nAdd to the `Env` interface:\n\n```typescript\nexport interface Env {\n  DB: D1Database;\n  API_KEY?: string;  // Required for email sending\n}\n```\n\n**2. Email Handler Code**\n\n```typescript\nasync function handleSendEmail(request: Request, env: Env): Promise<Response> {\n  const apiKey = env.API_KEY;\n  if (!apiKey) {\n    return json({ error: 'API_KEY not configured' }, 500);\n  }\n\n  const body = await request.json() as {\n    to?: string;\n    subject?: string;\n    html?: string;\n  };\n\n  if (!body.to) return json({ error: 'Email address is required' }, 400);\n  if (!body.subject) return json({ error: 'Subject is required' }, 400);\n  if (!body.html) return json({ error: 'HTML content is required' }, 400);\n\n  const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n  if (!emailRegex.test(body.to)) {\n    return json({ error: 'Invalid email address' }, 400);\n  }\n\n  const response = await fetch('https://pinme.cloud/api/v4/send_email', {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json',\n      'X-API-Key': apiKey,\n    },\n    body: JSON.stringify({\n      to: body.to,\n      subject: body.subject,\n      html: body.html,\n    }),\n  });\n\n  const result = await response.json();\n  return json(result);\n}\n```\n\n## Frontend API Utility (frontend/src/utils/api.ts)\n\n```typescript\n// Development: Vite proxies /api to localhost:8787\n// Production: VITE_API_URL is auto-injected by pinme create\nexport const API = import.meta.env.VITE_API_URL || '';\n\nexport function getApiUrl(path: string): string {\n  return API ? `${API}${path}` : path;\n}\n```\n\n## D1 Database Operations\n\n```typescript\n// Query multiple rows\nconst { results } = await env.DB.prepare('SELECT * FROM t WHERE x = ?').bind(val).all();\n\n// Query single row (returns null if not found)\nconst row = await env.DB.prepare('SELECT * FROM t WHERE id = ?').bind(id).first();\n\n// Insert and return new row\nconst row = await env.DB.prepare('INSERT INTO t (a, b) VALUES (?, ?) RETURNING *').bind(a, b).first();\n\n// Update\nawait env.DB.prepare('UPDATE t SET a = ? WHERE id = ?').bind(val, id).run();\n\n// Delete (check if affected)\nconst { meta } = await env.DB.prepare('DELETE FROM t WHERE id = ?').bind(id).run();\nif (meta.changes === 0) return json({ error: 'Not found' }, 404);\n```\n\n### SQL Migration Files\n\n**Format:** `db/NNN_description.sql` (for example, `001_init.sql`). Files are executed in filename order.\n\n**SQLite Type Constraints:**\n\n| Do Not Use | Alternative |\n|-----------|-------------|\n| `BOOLEAN` | `INTEGER` (0 = false, 1 = true) |\n| `DATETIME` / `TIMESTAMP` | `TEXT`, stored as ISO 8601 (default: `datetime('now')`) |\n| `JSON` type | `TEXT`, using `JSON.stringify()` / `JSON.parse()` |\n| `VARCHAR(n)` | `TEXT` |\n\n## Template Architecture Suggestions\n\n| Scenario | Default Suggestion |\n|-----------|-------------|\n| File storage (images, attachments, media) | Use the project R2 binding through `env.R2`; use the `pinme-r2` skill for secure routes and metadata patterns |\n| Real-time communication | This template defaults to regular HTTP APIs. If there is no clear real-time requirement, start with polling |\n| Multiple Workers | This template defaults to combining functionality into a single Worker and separating routes by prefix |\n| Multiple databases | This template defaults to combining data into one D1 database and only splitting when isolation is truly needed |\n\n## Important Notes\n\n- `pinme.toml`, `backend/wrangler.toml`, and `frontend/.env` are generated by PinMe. Do not edit them manually by default. If extra runtime configuration is truly needed, prefer doing it through PinMe-supported mechanisms.\n- Obtain the frontend API URL from the `VITE_API_URL` environment variable. Do not hardcode it.\n- Passwords, tokens, and API keys must be stored in secrets. Never put them in config files.\n\n## Common Errors\n\n| Error | Solution |\n|-------|----------|\n| `command not found: pinme` | `npm install -g pinme` |\n| `No such file or directory` | Verify that the path exists |\n| `Permission denied` | Check file or directory permissions |\n| Upload failed | Check the network connection and retry |\n| Not logged in | Run `pinme login` first |\n\n## Other Commands\n\n```bash\npinme list / pinme ls -l 5     # View upload history\npinme list -c                  # Clear upload history\npinme rm <hash>                # Delete uploaded content\npinme bind <path> --domain <domain>  # Bind domain (VIP + AppKey required)\npinme export <CID>             # Export as CAR file\npinme set-appkey               # Set/view AppKey\npinme my-domains               # List bound domains\npinme delete <project>          # Delete project (Worker + domain + D1)\npinme logout                   # Log out\n```","schemaVersion":1},"repoUrl":"https://github.com/glitternetwork/pinme/tree/main/skills/pinme","tags":["ai-tools","claude-code-skill","claude-skills","deployment","deployment-tools","frontend","frontend-deployment","hosting","serverless","skills","static-site","static-site-deploy"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pinme","audit":{"files":["package-lock.json","package.json","pnpm-lock.yaml"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip: Uncontrolled memory allocation via the declared uncompressed size (DoS).","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-7q85-xj36-vmfc · npm:adm-zip@0.5.17","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip extraction follows destination symlinks, allowing arbitrary file overwrite.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-vwc7-r8mq-g2x9 · npm:adm-zip@0.5.17","severity":"medium"},{"kind":"dependency","rule":"DP-01","message":"adm-zip@0.5.17 has a known vulnerability: adm-zip: Crafted ZIP file triggers 4GB memory allocation.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-xcpc-8h2w-3j85 · npm:adm-zip@0.5.17","severity":"high"},{"kind":"dependency","rule":"DP-01","message":"uuid@9.0.1 has a known vulnerability: uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided.","surface":"package-lock.json, package.json, pnpm-lock.yaml","evidence":"GHSA-w5hq-g745-h8pq · npm:uuid@9.0.1","severity":"medium"}],"packages":16,"auditedAt":"2026-09-25T11:51:56.672Z","lockfiles":["package-lock.json","pnpm-lock.yaml"]},"forks":277,"owner":"glitternetwork","stars":3745,"topics":["ai-tools","claude-code-skill","claude-skills","deployment","deployment-tools","frontend","frontend-deployment","hosting","serverless","skills","static-site","static-site-deploy","static-site-hosting","web-hosting","zero-configuration"],"license":"MIT","fullName":"glitternetwork/pinme","homepage":"https://pinme.eth.limo","language":"TypeScript","pushedAt":"2026-09-12T05:23:49Z","avatarUrl":"https://avatars.githubusercontent.com/u/102277171?v=4","crawledAt":"2026-09-25T11:51:44.477Z","openIssues":7,"manifestFile":"SKILL.md","manifestPath":"skills/pinme/SKILL.md","defaultBranch":"main"},"readme":"# PinMe\n\nZero-config deployment tool: upload static files to IPFS, or create and deploy full-stack web projects (React+Vite + Cloudflare Worker + D1 database). Workers also support sending emails via the PinMe platform API.\n\n## When to Use\n\n```dot\ndigraph pinme_decision {\n    \"User Request\" [shape=doublecircle];\n    \"Needs backend API or database?\" [shape=diamond];\n    \"Upload Files (Path 1)\" [shape=box];\n    \"Full-Stack Project (Path 2)\" [shape=box];\n\n    \"User Request\" -> \"Needs backend API or database?\";\n    \"Needs backend API or database?\" -> \"Upload Files (Path 1)\" [label=\"No\"];\n    \"Needs backend API or database?\" -> \"Full-Stack Project (Path 2)\" [label=\"Yes\"];\n}\n```\n\n## Path 1: Upload Files / Static Sites\n\n> Login required. Use `pinme login` or `pinme set-appkey <AppKey>` before `pinme upload` or `pinme import`.\n\n```dot\ndigraph upload_flow {\n    \"Install/update pinme to latest\" [shape=box];\n    \"Authenticate\" [shape=box];\n    \"Determine build artifacts\" [shape=box];\n    \"pinme upload <path>\" [shape=box];\n    \"Return preview URL\" [shape=doublecircle];\n\n    \"Install/update pinme to latest\" -> \"Authenticate\";\n    \"Authenticate\" -> \"Determine build artifacts\";\n    \"Determine build artifacts\" -> \"pinme upload <path>\";\n    \"pinme upload <path>\" -> \"Return preview URL\";\n}\n```\n\n**1. Check installation and update to latest:**\n```bash\nLOCAL=$(pinme --version 2>/dev/null || echo \"0.0.0\")\nLATEST=$(npm view pinme version)\n[ \"$LOCAL\" != \"$LATEST\" ] && npm install -g pinme@latest || echo \"pinme is up to date ($LOCAL)\"\n```\n\n**2. Authenticate:**\n```bash\npinme login\n# or: pinme set-appkey <AppKey>\n```\n\n**3. Determine upload target** (priority order):\n1. `dist/` — Vite / Vue / React\n2. `build/` — Create React App\n3. `out/` — Next.js static export\n4. `public/` — Plain static files\n\n**4. Upload:**\n```bash\npinme upload <path>\npinme upload ./dist --domain my-site  # Optional: bind subdomain (wallet balance required)\n```\n\n**5. Return** the final URL printed by PinMe to the user. URL priority is: DNS domain > PinMe subdomain > short URL > preview URL. If it falls back to preview, return the **full URL** including all hash characters — do not truncate.\n\n### Common Examples\n\n```bash\npinme upload ./document.pdf          # Single file\npinme upload ./my-folder             # Folder\npinme upload dist                    # Vite/Vue build artifacts\npinme upload build                   # CRA build artifacts\npinme upload out                     # Next.js static export\npinme upload ./dist --domain my-site # Bind PinMe subdomain (wallet balance required)\npinme import ./my-archive.car        # Import CAR file\n```\n\n### Do NOT Upload\n- `node_modules/`, `.env`, `.git/`, `src/`\n- Only upload build artifacts, never upload source code\n\n---\n\n## Path 2: Full-Stack Project\n\n> Login required. Uses React+Vite frontend + Cloudflare Worker backend + D1 SQLite database.\n> When designing frontend projects, use Ant Design as the primary design reference, and prioritize following its conventions for layout, components, spacing, and interaction patterns.\n\n```dot\ndigraph fullstack_flow {\n    \"Install/update pinme to latest\" [shape=box];\n    \"pinme login\" [shape=box];\n    \"pinme create <name>\" [shape=box];\n    \"Modify template code\" [shape=box];\n    \"pinme save\" [shape=box];\n    \"Return preview URL\" [shape=doublecircle];\n\n    \"Install/update pinme to latest\" -> \"pinme login\";\n    \"pinme login\" -> \"pinme create <name>\";\n    \"pinme create <name>\" -> \"Modify template code\";\n    \"Modify template code\" -> \"pinme save\";\n    \"pinme save\" -> \"Return preview URL\";\n}\n```\n\n### Architecture\n\n| Layer | Tech Stack | Deploy Target |\n|-------|-----------|---------------|\n| Frontend | React + Vite (`frontend/`) | IPFS |\n| Backend | Cloudflare Worker (`backend/src/worker.ts`) | `{name}.pinme.pro` |\n| Database | D1 SQLite (`db/*.sql`) | Cloudflare D1 |\n| Object storage | R2 (`env.R2`) | Cloudflare R2 |\n\n### Capability-Specific Skills\n\n- For Worker file uploads, downloads, images, attachments, medi","createdAt":"2026-09-25T11:51:56.766Z","updatedAt":"2026-09-25T11:51:56.766Z"},{"id":"cmugyn0ch02myqu06qf6h04gp","slug":"mohitagw15856-pm-claude-skills-agent-readiness-audit","name":"agent-readiness-audit","description":"Audit whether AI agents can actually use your product — docs, APIs, onboarding, errors, and discoverability, evaluated from a non-human user's perspective. Use when asked if a product is agent-ready, to audit a site or API for AI usability, to prepare for agentic traffic, or when agents keep failing against your product. Produces a scored readiness report with per-surface findings and a prioritised fix list. For optimising a single article for AI citation use aeo-optimizer; for designing the MCP server itself use mcp-server-spec.","authorId":"gh:mohitagw15856","authorName":"mohitagw15856","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":1397,"pricePerCall":0,"manifest":{"name":"agent-readiness-audit","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Audit whether AI agents can actually use your product — docs, APIs, onboarding, errors, and discoverability, evaluated from a non-human user's perspective. Use when asked if a product is agent-ready, to audit a site or API for AI usability, to prepare for agentic traffic, or when agents keep failing against your product. Produces a scored readiness report with per-surface findings and a prioritised fix list. For optimising a single article for AI citation use aeo-optimizer; for designing the MCP server itself use mcp-server-spec.","permissions":[],"systemPrompt":"# Agent Readiness Audit Skill\n\nA growing share of your product's users aren't human: agents research it, evaluate it, onboard onto it, and operate it on their principals' behalf. They can't watch your demo video, guess what an unlabeled icon means, or call support. This skill audits every surface an agent touches and scores how much of your product is invisible or unusable to them.\n\n## What This Skill Produces\n\n- A **readiness score by surface** (discovery, docs, API/auth, errors, onboarding, transactions)\n- **Per-surface findings** with the failing artifact quoted and the fix\n- A **prioritised fix list** ranked by agent-traffic impact vs effort\n- A **re-test protocol** so readiness is measured, not vibed\n\n## Required Inputs\n\nAsk for (if not already provided):\n- **The product** and its public surfaces (site, docs URL, API reference, status page)\n- **What agents will be asked to do** with it — research/compare? sign up? operate it daily?\n- **What exists already**: llms.txt? MCP server? OpenAPI spec? If unknown, the audit checks\n- **Any observed agent failures** (the best audit seed there is)\n\n## The Audit Surfaces\n\nWalk each surface asking one question: *could a capable agent, starting cold, complete its job here without a human unblocking it?*\n\n**1. Discovery — can agents find and understand what you are?**\n`llms.txt` present and current · docs fetchable as clean markdown/text (not JS-rendered walls) · pricing and limits stated in prose an agent can quote · comparison-relevant facts (SOC 2, SSO, data residency) written down anywhere at all — an agent can't infer what you never wrote.\n\n**2. Docs — written for readers who execute?**\nEvery task documented as copy-runnable steps with expected outputs · code samples that actually run (agents execute them verbatim) · one canonical way per task (agents can't arbitrate between three contradictory tutorials) · error-message strings from the product appearing verbatim in the docs so search-by-error works.\n\n**3. API & auth — self-serve without a human?**\nKey/token obtainable without a sales call (or the agent path is documented honestly) · OpenAPI spec accurate to the deployed API · rate limits discoverable programmatically · an MCP server, or at least a stated position on one.\n\n**4. Errors — instructive to a retrying machine?**\nErrors name the field and the fix · machine-readable codes stable across releases · 4xx vs 5xx used honestly (agents branch on this) · no CAPTCHAs on API-adjacent flows without a documented alternative.\n\n**5. Onboarding & transactions — can an agent complete them?**\nSignup/checkout completable without image CAPTCHAs, drag-widgets, or SMS-only verification (or agent-appropriate alternatives exist) · forms with real labels, not placeholder-only · the confirmation state readable as text.\n\n**6. Guardrails — do you *know* your agent traffic?**\nAre agents distinguishable in analytics? Is there a stated policy (terms + technical) for agent use — welcome, gated, or forbidden? Silence is a decision made by accident.\n\nScore each surface 0-4: 0 = actively hostile · 2 = humans-only assumptions throughout · 4 = agent-native. Cite the failing artifact for anything below 3.\n\n## Output Format\n\n### Agent Readiness Audit: [product] — [n]/24\n\n| Surface | Score /4 | Sharpest finding |\n|---|---|---|\n\n**Findings** *(per surface, worst first)*\n**[surface] — [score]**: [what fails, with the artifact quoted] → **Fix:** [specific change]\n\n**Fix list, prioritised:**\n| # | Fix | Surface | Impact | Effort |\n|---|---|---|---|---|\n\n**Re-test protocol:** [5-8 cold-start agent tasks (\"sign up and send one API request\", \"find whether SSO is on the cheap plan\") — run them with a real agent after fixes; the score is the pass rate, not the checklist]\n\n## Quality Checks\n\n- [ ] Every score below 3 cites the actual failing artifact (URL, error string, form field), not a vibe\n- [ ] Fixes are specific changes, not \"improve the docs\"\n- [ ] The audit distinguishes *unwritten* facts (agent can't know) from *buried* facts (agent might find)\n- [ ] The fix list is ranked by agent-traffic impact, and states assumptions where traffic is unmeasured\n- [ ] The re-test protocol exists — readiness is a pass rate, not an opinion\n\n## Anti-Patterns\n\n- [ ] Do not audit from memory of the product — fetch the actual surfaces; they've changed\n- [ ] Do not treat \"we have great docs\" as evidence — great-for-humans routinely scores 1/4 for agents\n- [ ] Do not recommend blocking agents as a fix unless the business genuinely wants that — then say it in terms *and* technically, consistently\n- [ ] Do not conflate this with SEO/AEO — being quotable is surface 1; being *usable* is the other five\n- [ ] Do not skip the guardrails surface — unmeasured agent traffic is how products discover this problem in an outage","schemaVersion":1},"repoUrl":"https://github.com/mohitagw15856/pm-claude-skills/tree/main/skills/agent-readiness-audit","tags":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pm-claude-skills","audit":{"files":["package.json"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-02","message":"`postinstall` script runs on every install.","surface":"package.json","evidence":"postinstall: node bin/postinstall.mjs","severity":"high"}],"packages":0,"auditedAt":"2026-09-25T12:51:59.225Z","lockfiles":[]},"forks":249,"owner":"mohitagw15856","stars":1397,"topics":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini","llm","mcp","mcp-server","product-management","productivity","prompt-engineering","prompts","skills"],"license":"MIT","fullName":"mohitagw15856/pm-claude-skills","homepage":"https://mohitagw15856.github.io/pm-claude-skills/","language":"HTML","pushedAt":"2026-09-25T10:13:15Z","avatarUrl":"https://avatars.githubusercontent.com/u/119053560?v=4","crawledAt":"2026-09-25T12:51:48.196Z","openIssues":13,"manifestFile":"SKILL.md","manifestPath":"skills/agent-readiness-audit/SKILL.md","defaultBranch":"main"},"readme":"# Agent Readiness Audit Skill\n\nA growing share of your product's users aren't human: agents research it, evaluate it, onboard onto it, and operate it on their principals' behalf. They can't watch your demo video, guess what an unlabeled icon means, or call support. This skill audits every surface an agent touches and scores how much of your product is invisible or unusable to them.\n\n## What This Skill Produces\n\n- A **readiness score by surface** (discovery, docs, API/auth, errors, onboarding, transactions)\n- **Per-surface findings** with the failing artifact quoted and the fix\n- A **prioritised fix list** ranked by agent-traffic impact vs effort\n- A **re-test protocol** so readiness is measured, not vibed\n\n## Required Inputs\n\nAsk for (if not already provided):\n- **The product** and its public surfaces (site, docs URL, API reference, status page)\n- **What agents will be asked to do** with it — research/compare? sign up? operate it daily?\n- **What exists already**: llms.txt? MCP server? OpenAPI spec? If unknown, the audit checks\n- **Any observed agent failures** (the best audit seed there is)\n\n## The Audit Surfaces\n\nWalk each surface asking one question: *could a capable agent, starting cold, complete its job here without a human unblocking it?*\n\n**1. Discovery — can agents find and understand what you are?**\n`llms.txt` present and current · docs fetchable as clean markdown/text (not JS-rendered walls) · pricing and limits stated in prose an agent can quote · comparison-relevant facts (SOC 2, SSO, data residency) written down anywhere at all — an agent can't infer what you never wrote.\n\n**2. Docs — written for readers who execute?**\nEvery task documented as copy-runnable steps with expected outputs · code samples that actually run (agents execute them verbatim) · one canonical way per task (agents can't arbitrate between three contradictory tutorials) · error-message strings from the product appearing verbatim in the docs so search-by-error works.\n\n**3. API & auth — self-serve without a human?**\nKey/token obtainable without a sales call (or the agent path is documented honestly) · OpenAPI spec accurate to the deployed API · rate limits discoverable programmatically · an MCP server, or at least a stated position on one.\n\n**4. Errors — instructive to a retrying machine?**\nErrors name the field and the fix · machine-readable codes stable across releases · 4xx vs 5xx used honestly (agents branch on this) · no CAPTCHAs on API-adjacent flows without a documented alternative.\n\n**5. Onboarding & transactions — can an agent complete them?**\nSignup/checkout completable without image CAPTCHAs, drag-widgets, or SMS-only verification (or agent-appropriate alternatives exist) · forms with real labels, not placeholder-only · the confirmation state readable as text.\n\n**6. Guardrails — do you *know* your agent traffic?**\nAre agents distinguishable in analytics? Is there a stated policy (terms + technical) for agent use — welcome, gated, or forbidden? Silence is a decision made by accident.\n\nScore each surface 0-4: 0 = actively hostile · 2 = humans-only assumptions throughout · 4 = agent-native. Cite the failing artifact for anything below 3.\n\n## Output Format\n\n### Agent Readiness Audit: [product] — [n]/24\n\n| Surface | Score /4 | Sharpest finding |\n|---|---|---|\n\n**Findings** *(per surface, worst first)*\n**[surface] — [score]**: [what fails, with the artifact quoted] → **Fix:** [specific change]\n\n**Fix list, prioritised:**\n| # | Fix | Surface | Impact | Effort |\n|---|---|---|---|---|\n\n**Re-test protocol:** [5-8 cold-start agent tasks (\"sign up and send one API request\", \"find whether SSO is on the cheap plan\") — run them with a real agent after fixes; the score is the pass rate, not the checklist]\n\n## Quality Checks\n\n- [ ] Every score below 3 cites the actual failing artifact (URL, error string, form field), not a vibe\n- [ ] Fixes are specific changes, not \"improve the docs\"\n- [ ] The audit distinguishes *unwritten* facts (agent can't know) from ","createdAt":"2026-09-25T12:51:59.490Z","updatedAt":"2026-09-25T12:51:59.490Z"},{"id":"cmugyn0dy02ndqu06ydc5h0ga","slug":"mohitagw15856-pm-claude-skills-agm-in-a-box","name":"agm-in-a-box","description":"Run a club, PTA, or association AGM that finishes on time and holds up later — the notice and agenda done right, a quorum plan, minutes that capture decisions not conversations, elections without awkwardness, and the follow-up that makes decisions real. Use when a volunteer says 'I have to run the AGM', 'what goes in the agenda', 'nobody comes to our meetings', or 'our elections are a mess'. Produces the notice, agenda, chair's script, minutes template, and quorum rescue plan.","authorId":"gh:mohitagw15856","authorName":"mohitagw15856","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":1397,"pricePerCall":0,"manifest":{"name":"agm-in-a-box","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Run a club, PTA, or association AGM that finishes on time and holds up later — the notice and agenda done right, a quorum plan, minutes that capture decisions not conversations, elections without awkwardness, and the follow-up that makes decisions real. Use when a volunteer says 'I have to run the AGM', 'what goes in the agenda', 'nobody comes to our meetings', or 'our elections are a mess'. Produces the notice, agenda, chair's script, minutes template, and quorum rescue plan.","permissions":[],"systemPrompt":"# AGM In A Box Skill\n\nEvery club and association has one meeting a year that legally/constitutionally\nmatters, and it's usually run by a volunteer who inherited a folder and a\nsense of dread. A good AGM is mostly preparation: notice sent the right way at\nthe right time, an agenda where decisions are visible in advance, a chair's\nscript so the running of it isn't improvised, and minutes that record what was\n*decided* — because in three years, when someone asks \"when did we agree to\nthat?\", the minutes are all that exists. This skill produces the whole box,\ntuned to the organization's own constitution — which it asks for rather than\nguessing.\n\n## What This Skill Produces\n\n- The **notice pack**: announcement text with date/venue/deadlines, proxy/\n  nomination forms if used, timed to the constitution's notice period\n- The **agenda**, decision-forward: what's being decided, reports as reading\n  not speeches, election slots, AOB rules\n- The **chair's script**: opening, quorum check, how to take each item, how\n  to run a vote, handling the member with a grievance, closing\n- **Minutes template** + the follow-up list format (decision → owner → date)\n- A **quorum rescue plan**: getting people to actually come, and what the\n  constitution says happens if they don't\n\n## Required Inputs\n\nAsk for (if not already provided):\n- The organization and its constitution/rules — pasted if possible; the\n  notice period, quorum number, and election rules live there, and this\n  skill works from *their* rules, flagging \"check your constitution\" where\n  not provided\n- What must be decided this year: elections (which posts), rule changes,\n  budget/subs, anything contentious\n- Attendance reality: how many usually come vs the quorum\n- The awkward stuff, honestly: contested posts, a grievance-holder, last\n  year's chaos\n\n## Framework\n\n1. **Work backwards from the constitution.** Notice period sets the send\n   date; quorum sets the turnout target; election rules set the nomination\n   process. Where the user hasn't provided the document: use common defaults\n   *labelled as defaults to verify*, never as their rules.\n2. **Make the agenda decision-forward.** Members show up when something is\n   decided, not reported. Reports circulated in advance and \"taken as read\"\n   with questions only; decisions named as motions in the agenda (\"Motion:\n   raise subs to £X\") so nobody's ambushed; AOB items requested in advance\n   with a chair's discretion line.\n3. **Script the chair.** Verbatim openings for each segment, the vote\n   procedure (propose, second, discuss with time-box, vote, record the\n   count), and the two hard moments: the long-talker (\"thank you — I'll take\n   two more speakers, then vote\") and the grievance (\"that deserves proper\n   time — I'm ruling it to a committee meeting on [date], recorded in\n   minutes\").\n4. **Minutes record decisions, not dialogue.** Per item: motion text ·\n   proposed/seconded · vote result with counts · action + owner + date.\n   Nobody's speech is summarized; three years from now the counts matter and\n   the speeches don't.\n5. **Rescue quorum before the day.** Personal asks beat posters (the\n   three-line \"we need YOU there Thursday\" message, sent by name) · pair the\n   AGM with something people want (social, guest speaker, awards) · proxy\n   forms where allowed. And the honest branch: what the constitution says if\n   quorum fails — usually a reconvene rule; find it now, not at 7:40pm.\n\n## Output Format\n\n```\n## Timeline (backwards from AGM date)\n[Notice by · nominations by · reports circulated · reminders]\n\n## Notice pack\n[The announcement + forms, ready to send]\n\n## Agenda (decision-forward)\n[Numbered, with motions stated in full]\n\n## Chair's script\n[Segment-by-segment, with the two hard-moment lines]\n\n## Minutes template + follow-up list\n[Decision-record format · action/owner/date table]\n\n## Quorum plan\n[Named-ask message · the pairing · the failure branch per constitution]\n```\n\n## Quality Checks\n\n- [ ] Every rule-dependent element (notice, quorum, elections) is anchored to\n      their constitution or explicitly flagged as a default-to-verify\n- [ ] Motions appear in full in the agenda — no decision happens that wasn't\n      announced\n- [ ] The chair's script covers the long-talker and the grievance\n- [ ] Minutes template records counts and owners, not speeches\n- [ ] The quorum plan includes the personal-ask message, not just posters\n\n## Anti-Patterns\n\n- [ ] Do not assert legal/charity/company requirements by jurisdiction —\n      constitution first, verify-flags second, invented law never\n- [ ] Do not build a speech-schedule agenda — reports are reading, meetings\n      are for deciding\n- [ ] Do not script the chair to shut people down — time-boxes and routing,\n      not suppression\n- [ ] Do not treat AOB as an open mic; rules for it exist in the agenda\n\n## Related\n\n[[committee-handover-pack]] for after the elections; [[volunteer-treasurer-basics]]\nfor the finance report's author; [[meeting-notes]] for ordinary meetings that\ndon't need the box.","schemaVersion":1},"repoUrl":"https://github.com/mohitagw15856/pm-claude-skills/tree/main/skills/agm-in-a-box","tags":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pm-claude-skills","audit":{"files":["package.json"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-02","message":"`postinstall` script runs on every install.","surface":"package.json","evidence":"postinstall: node bin/postinstall.mjs","severity":"high"}],"packages":0,"auditedAt":"2026-09-25T12:51:59.225Z","lockfiles":[]},"forks":249,"owner":"mohitagw15856","stars":1397,"topics":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini","llm","mcp","mcp-server","product-management","productivity","prompt-engineering","prompts","skills"],"license":"MIT","fullName":"mohitagw15856/pm-claude-skills","homepage":"https://mohitagw15856.github.io/pm-claude-skills/","language":"HTML","pushedAt":"2026-09-25T10:13:15Z","avatarUrl":"https://avatars.githubusercontent.com/u/119053560?v=4","crawledAt":"2026-09-25T12:51:48.196Z","openIssues":13,"manifestFile":"SKILL.md","manifestPath":"skills/agm-in-a-box/SKILL.md","defaultBranch":"main"},"readme":"# AGM In A Box Skill\n\nEvery club and association has one meeting a year that legally/constitutionally\nmatters, and it's usually run by a volunteer who inherited a folder and a\nsense of dread. A good AGM is mostly preparation: notice sent the right way at\nthe right time, an agenda where decisions are visible in advance, a chair's\nscript so the running of it isn't improvised, and minutes that record what was\n*decided* — because in three years, when someone asks \"when did we agree to\nthat?\", the minutes are all that exists. This skill produces the whole box,\ntuned to the organization's own constitution — which it asks for rather than\nguessing.\n\n## What This Skill Produces\n\n- The **notice pack**: announcement text with date/venue/deadlines, proxy/\n  nomination forms if used, timed to the constitution's notice period\n- The **agenda**, decision-forward: what's being decided, reports as reading\n  not speeches, election slots, AOB rules\n- The **chair's script**: opening, quorum check, how to take each item, how\n  to run a vote, handling the member with a grievance, closing\n- **Minutes template** + the follow-up list format (decision → owner → date)\n- A **quorum rescue plan**: getting people to actually come, and what the\n  constitution says happens if they don't\n\n## Required Inputs\n\nAsk for (if not already provided):\n- The organization and its constitution/rules — pasted if possible; the\n  notice period, quorum number, and election rules live there, and this\n  skill works from *their* rules, flagging \"check your constitution\" where\n  not provided\n- What must be decided this year: elections (which posts), rule changes,\n  budget/subs, anything contentious\n- Attendance reality: how many usually come vs the quorum\n- The awkward stuff, honestly: contested posts, a grievance-holder, last\n  year's chaos\n\n## Framework\n\n1. **Work backwards from the constitution.** Notice period sets the send\n   date; quorum sets the turnout target; election rules set the nomination\n   process. Where the user hasn't provided the document: use common defaults\n   *labelled as defaults to verify*, never as their rules.\n2. **Make the agenda decision-forward.** Members show up when something is\n   decided, not reported. Reports circulated in advance and \"taken as read\"\n   with questions only; decisions named as motions in the agenda (\"Motion:\n   raise subs to £X\") so nobody's ambushed; AOB items requested in advance\n   with a chair's discretion line.\n3. **Script the chair.** Verbatim openings for each segment, the vote\n   procedure (propose, second, discuss with time-box, vote, record the\n   count), and the two hard moments: the long-talker (\"thank you — I'll take\n   two more speakers, then vote\") and the grievance (\"that deserves proper\n   time — I'm ruling it to a committee meeting on [date], recorded in\n   minutes\").\n4. **Minutes record decisions, not dialogue.** Per item: motion text ·\n   proposed/seconded · vote result with counts · action + owner + date.\n   Nobody's speech is summarized; three years from now the counts matter and\n   the speeches don't.\n5. **Rescue quorum before the day.** Personal asks beat posters (the\n   three-line \"we need YOU there Thursday\" message, sent by name) · pair the\n   AGM with something people want (social, guest speaker, awards) · proxy\n   forms where allowed. And the honest branch: what the constitution says if\n   quorum fails — usually a reconvene rule; find it now, not at 7:40pm.\n\n## Output Format\n\n```\n## Timeline (backwards from AGM date)\n[Notice by · nominations by · reports circulated · reminders]\n\n## Notice pack\n[The announcement + forms, ready to send]\n\n## Agenda (decision-forward)\n[Numbered, with motions stated in full]\n\n## Chair's script\n[Segment-by-segment, with the two hard-moment lines]\n\n## Minutes template + follow-up list\n[Decision-record format · action/owner/date table]\n\n## Quorum plan\n[Named-ask message · the pairing · the failure branch per constitution]\n```\n\n## Quality Checks\n\n- [ ] Every rule-dependent eleme","createdAt":"2026-09-25T12:51:59.542Z","updatedAt":"2026-09-25T12:51:59.542Z"},{"id":"cmugyn0g202o1qu066le3eg9n","slug":"mohitagw15856-pm-claude-skills-ai-eval-plan","name":"ai-eval-plan","description":"Design an evaluation plan for an LLM or AI feature before shipping it. Use when asked how to evaluate a prompt/model/agent, set up an eval harness, define quality metrics for an AI feature, or build a regression gate. Produces an eval plan — task definition, datasets, metrics & rubrics, baselines, automated + human evals, a pass bar, and a regression gate.","authorId":"gh:mohitagw15856","authorName":"mohitagw15856","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":1397,"pricePerCall":0,"manifest":{"name":"ai-eval-plan","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Design an evaluation plan for an LLM or AI feature before shipping it. Use when asked how to evaluate a prompt/model/agent, set up an eval harness, define quality metrics for an AI feature, or build a regression gate. Produces an eval plan — task definition, datasets, metrics & rubrics, baselines, automated + human evals, a pass bar, and a regression gate.","permissions":[],"systemPrompt":"# AI Eval Plan Skill\n\nYou can't improve an AI feature you can't measure, and \"it looks good in the demo\" is not measurement.\nThis skill produces an evaluation plan that turns a fuzzy quality goal into a repeatable, gated test —\nso a prompt change that quietly makes outputs worse can't ship.\n\n## Required Inputs\n\nAsk for these only if they aren't already provided:\n\n- **The feature & task** — what the model does and what \"good output\" means to a user.\n- **Failure modes that matter** — what bad looks like (hallucination, wrong format, unsafe, off-tone, too slow).\n- **Available data** — any real examples, logs, or labelled cases; or note there are none yet.\n- **Who judges quality** — automated checks, an LLM judge, human raters, or a mix.\n- **The decision this gates** — ship/no-ship, model selection, or prompt iteration.\n\n## Output Format\n\n### Eval Plan: [feature]\n\n**1. What we're measuring** — the task, and a one-line definition of a good vs. bad response.\n\n**2. Eval dataset**\n- **Cases:** how many, where they come from (real logs > synthetic), and how they're split (smoke set vs. full set).\n- **Coverage:** the slices/scenarios that must be represented (edge cases, adversarial, each major input type).\n- **Golden answers / references:** present or not, and how they were created.\n\n**3. Metrics & rubric**\n- **Per-dimension scores** — define each dimension (e.g. correctness, grounding, format, safety, tone) on an explicit 1–5 rubric with anchor descriptions, not vibes.\n- **Automated checks** — deterministic assertions first (valid JSON, contains required fields, no PII, latency budget).\n- **LLM-as-judge** — the judge prompt, the rubric it applies, and how you guard against its bias (calibrate against human labels on a sample).\n- **Human eval** — when it's required (safety, subjective quality) and the rater instructions.\n\n**4. Baselines** — what each candidate is compared against (current prompt, previous model, a plain-prompt control).\n\n**5. The bar** — the explicit threshold to ship (e.g. \"≥4.2 avg correctness, 0 safety failures, p95 < 3s\") and what happens if it's missed.\n\n**6. Regression gate** — how this runs in CI on every change, and the score-drop threshold that blocks a merge.\n\n## Quality Checks\n\n- [ ] Each metric has an explicit rubric with anchors — not just a name\n- [ ] Deterministic/automated checks are used wherever possible before reaching for an LLM judge\n- [ ] The LLM judge is calibrated against human labels on at least a sample\n- [ ] The eval set includes adversarial and edge cases, not just happy-path examples\n- [ ] There is a single, explicit numeric bar for the ship decision\n- [ ] The plan specifies how it runs as a regression gate, not just a one-time check\n\n## Anti-Patterns\n\n- [ ] Do not rely on a single overall score — a feature can pass on average while failing every safety case\n- [ ] Do not trust an LLM judge you haven't calibrated against humans — it has its own blind spots and biases\n- [ ] Do not eval only on happy-path inputs — the failures live in the edges and the adversarial cases\n- [ ] Do not let the eval set leak into the prompt/few-shot examples — that's training on the test set\n- [ ] Do not define the pass bar after seeing the scores — set the threshold before you run, or it means nothing\n\n## Based On\n\nLLM evaluation practice — task-grounded rubrics, LLM-as-judge with human calibration, and regression-gated CI evals.","schemaVersion":1},"repoUrl":"https://github.com/mohitagw15856/pm-claude-skills/tree/main/skills/ai-eval-plan","tags":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pm-claude-skills","audit":{"files":["package.json"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-02","message":"`postinstall` script runs on every install.","surface":"package.json","evidence":"postinstall: node bin/postinstall.mjs","severity":"high"}],"packages":0,"auditedAt":"2026-09-25T12:51:59.225Z","lockfiles":[]},"forks":249,"owner":"mohitagw15856","stars":1397,"topics":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini","llm","mcp","mcp-server","product-management","productivity","prompt-engineering","prompts","skills"],"license":"MIT","fullName":"mohitagw15856/pm-claude-skills","homepage":"https://mohitagw15856.github.io/pm-claude-skills/","language":"HTML","pushedAt":"2026-09-25T10:13:15Z","avatarUrl":"https://avatars.githubusercontent.com/u/119053560?v=4","crawledAt":"2026-09-25T12:51:48.196Z","openIssues":13,"manifestFile":"SKILL.md","manifestPath":"skills/ai-eval-plan/SKILL.md","defaultBranch":"main"},"readme":"# AI Eval Plan Skill\n\nYou can't improve an AI feature you can't measure, and \"it looks good in the demo\" is not measurement.\nThis skill produces an evaluation plan that turns a fuzzy quality goal into a repeatable, gated test —\nso a prompt change that quietly makes outputs worse can't ship.\n\n## Required Inputs\n\nAsk for these only if they aren't already provided:\n\n- **The feature & task** — what the model does and what \"good output\" means to a user.\n- **Failure modes that matter** — what bad looks like (hallucination, wrong format, unsafe, off-tone, too slow).\n- **Available data** — any real examples, logs, or labelled cases; or note there are none yet.\n- **Who judges quality** — automated checks, an LLM judge, human raters, or a mix.\n- **The decision this gates** — ship/no-ship, model selection, or prompt iteration.\n\n## Output Format\n\n### Eval Plan: [feature]\n\n**1. What we're measuring** — the task, and a one-line definition of a good vs. bad response.\n\n**2. Eval dataset**\n- **Cases:** how many, where they come from (real logs > synthetic), and how they're split (smoke set vs. full set).\n- **Coverage:** the slices/scenarios that must be represented (edge cases, adversarial, each major input type).\n- **Golden answers / references:** present or not, and how they were created.\n\n**3. Metrics & rubric**\n- **Per-dimension scores** — define each dimension (e.g. correctness, grounding, format, safety, tone) on an explicit 1–5 rubric with anchor descriptions, not vibes.\n- **Automated checks** — deterministic assertions first (valid JSON, contains required fields, no PII, latency budget).\n- **LLM-as-judge** — the judge prompt, the rubric it applies, and how you guard against its bias (calibrate against human labels on a sample).\n- **Human eval** — when it's required (safety, subjective quality) and the rater instructions.\n\n**4. Baselines** — what each candidate is compared against (current prompt, previous model, a plain-prompt control).\n\n**5. The bar** — the explicit threshold to ship (e.g. \"≥4.2 avg correctness, 0 safety failures, p95 < 3s\") and what happens if it's missed.\n\n**6. Regression gate** — how this runs in CI on every change, and the score-drop threshold that blocks a merge.\n\n## Quality Checks\n\n- [ ] Each metric has an explicit rubric with anchors — not just a name\n- [ ] Deterministic/automated checks are used wherever possible before reaching for an LLM judge\n- [ ] The LLM judge is calibrated against human labels on at least a sample\n- [ ] The eval set includes adversarial and edge cases, not just happy-path examples\n- [ ] There is a single, explicit numeric bar for the ship decision\n- [ ] The plan specifies how it runs as a regression gate, not just a one-time check\n\n## Anti-Patterns\n\n- [ ] Do not rely on a single overall score — a feature can pass on average while failing every safety case\n- [ ] Do not trust an LLM judge you haven't calibrated against humans — it has its own blind spots and biases\n- [ ] Do not eval only on happy-path inputs — the failures live in the edges and the adversarial cases\n- [ ] Do not let the eval set leak into the prompt/few-shot examples — that's training on the test set\n- [ ] Do not define the pass bar after seeing the scores — set the threshold before you run, or it means nothing\n\n## Based On\n\nLLM evaluation practice — task-grounded rubrics, LLM-as-judge with human calibration, and regression-gated CI evals.","createdAt":"2026-09-25T12:51:59.619Z","updatedAt":"2026-09-25T12:51:59.619Z"},{"id":"cmugyn0gd02o4qu06xaksgd0r","slug":"mohitagw15856-pm-claude-skills-ai-feature-prd","name":"ai-feature-prd","description":"Write a PRD for an AI-powered feature, covering the things normal PRDs miss. Use when asked to spec an AI/LLM feature, write a PRD for a feature that uses a model, or plan an AI capability (assistant, summarizer, generator, classifier). Produces an AI feature PRD — problem & UX of uncertainty, model approach, eval criteria, guardrails, fallback behaviour, the data flywheel, and cost/latency budget.","authorId":"gh:mohitagw15856","authorName":"mohitagw15856","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":1397,"pricePerCall":0,"manifest":{"name":"ai-feature-prd","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Write a PRD for an AI-powered feature, covering the things normal PRDs miss. Use when asked to spec an AI/LLM feature, write a PRD for a feature that uses a model, or plan an AI capability (assistant, summarizer, generator, classifier). Produces an AI feature PRD — problem & UX of uncertainty, model approach, eval criteria, guardrails, fallback behaviour, the data flywheel, and cost/latency budget.","permissions":[],"systemPrompt":"# AI Feature PRD Skill\n\nAI features break the normal PRD because the system is probabilistic: it will be wrong sometimes, and\nthe product must be designed around that, not in denial of it. This skill extends a standard PRD with\nthe AI-specific sections that decide whether the feature is trustworthy — the UX of uncertainty, the\neval bar, guardrails, and what happens when the model is wrong.\n\n## Required Inputs\n\nAsk for these only if they aren't already provided:\n\n- **The user problem** and why an AI/probabilistic approach fits it (vs. deterministic rules).\n- **What \"good\" looks like** to the user, and the cost of a wrong answer (low-stakes vs. high-stakes).\n- **Inputs available** — context/data the model can use; privacy constraints.\n- **Trust level needed** — can the user verify the output, or must it be near-perfect?\n\n## Reads from / Writes to the Brain\n\nIf a [`professional-brain`](../professional-brain/SKILL.md) exists, read `context.md` (product, users, voice)\nand `knowledge/strategy.md` first; write the feature to `entities/` and any scoping decision to `decisions/`,\neach provenance-tagged.\n\n## Output Format\n\n### AI Feature PRD: [feature]\n\n**1. Problem & why AI** — the user problem, and why a model (not rules) is the right tool. If rules would do, say so.\n\n**2. Experience** — the core flow, and crucially the **UX of uncertainty**: how confidence is shown, how the user verifies/edits, and how errors are made cheap to recover from. AI features live or die here.\n\n**3. Model approach** — prompt / fine-tune / RAG / agent (link [`rag-design-doc`](../rag-design-doc/SKILL.md) or [`agent-spec`](../agent-spec/SKILL.md)), the model tier, and why.\n\n**4. Quality bar & evaluation** — the metrics and the explicit ship threshold; reference an [`ai-eval-plan`](../ai-eval-plan/SKILL.md). State the acceptable error rate given the stakes.\n\n**5. Guardrails & safety** — what the feature must never do, input/output filtering, and handling of harmful/PII/out-of-scope inputs.\n\n**6. Fallback behaviour** — what happens when the model is unsure, wrong, slow, or down: graceful degradation, \"I'm not sure\" states, human handoff. **No silent confident errors.**\n\n**7. Data flywheel** — how usage (and the 👍/👎 / edits) feed back into evaluation and improvement, with the privacy boundary.\n\n**8. Cost & latency** — the per-request budget and p95 target; reference an [`llm-cost-latency-budget`](../llm-cost-latency-budget/SKILL.md).\n\n**9. Rollout** — staged exposure (internal → %→ GA), the guardrail metrics watched, and the rollback trigger.\n\n## Quality Checks\n\n- [ ] The PRD designs for the model being wrong — there's an explicit fallback, not just the happy path\n- [ ] The UX shows uncertainty and lets the user verify/correct cheaply\n- [ ] There's an explicit quality bar tied to the stakes (a medical answer and a tweet draft are not the same bar)\n- [ ] Guardrails name what the feature must never do\n- [ ] A data flywheel is defined with its privacy boundary\n- [ ] Cost and p95 latency budgets are stated, not left to \"we'll see\"\n\n## Anti-Patterns\n\n- [ ] Do not design only the happy path — a probabilistic feature without a fallback is a feature that fails loudly in production\n- [ ] Do not hide uncertainty behind a confident UI — overclaimed confidence is how AI features lose user trust permanently\n- [ ] Do not use AI where deterministic rules are better, cheaper, and more reliable — \"AI\" is not the goal\n- [ ] Do not set one quality bar for all stakes — calibrate the acceptable error rate to the cost of being wrong\n- [ ] Do not ship without a rollback trigger and guardrail metrics — a probabilistic system needs a kill switch\n\n## Based On\n\nStandard PRD practice (see [`prd-template`](../prd-template/SKILL.md)) extended for probabilistic systems — uncertainty UX, eval gates, guardrails, and graceful fallback.","schemaVersion":1},"repoUrl":"https://github.com/mohitagw15856/pm-claude-skills/tree/main/skills/ai-feature-prd","tags":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pm-claude-skills","audit":{"files":["package.json"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-02","message":"`postinstall` script runs on every install.","surface":"package.json","evidence":"postinstall: node bin/postinstall.mjs","severity":"high"}],"packages":0,"auditedAt":"2026-09-25T12:51:59.225Z","lockfiles":[]},"forks":249,"owner":"mohitagw15856","stars":1397,"topics":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini","llm","mcp","mcp-server","product-management","productivity","prompt-engineering","prompts","skills"],"license":"MIT","fullName":"mohitagw15856/pm-claude-skills","homepage":"https://mohitagw15856.github.io/pm-claude-skills/","language":"HTML","pushedAt":"2026-09-25T10:13:15Z","avatarUrl":"https://avatars.githubusercontent.com/u/119053560?v=4","crawledAt":"2026-09-25T12:51:48.196Z","openIssues":13,"manifestFile":"SKILL.md","manifestPath":"skills/ai-feature-prd/SKILL.md","defaultBranch":"main"},"readme":"# AI Feature PRD Skill\n\nAI features break the normal PRD because the system is probabilistic: it will be wrong sometimes, and\nthe product must be designed around that, not in denial of it. This skill extends a standard PRD with\nthe AI-specific sections that decide whether the feature is trustworthy — the UX of uncertainty, the\neval bar, guardrails, and what happens when the model is wrong.\n\n## Required Inputs\n\nAsk for these only if they aren't already provided:\n\n- **The user problem** and why an AI/probabilistic approach fits it (vs. deterministic rules).\n- **What \"good\" looks like** to the user, and the cost of a wrong answer (low-stakes vs. high-stakes).\n- **Inputs available** — context/data the model can use; privacy constraints.\n- **Trust level needed** — can the user verify the output, or must it be near-perfect?\n\n## Reads from / Writes to the Brain\n\nIf a [`professional-brain`](../professional-brain/SKILL.md) exists, read `context.md` (product, users, voice)\nand `knowledge/strategy.md` first; write the feature to `entities/` and any scoping decision to `decisions/`,\neach provenance-tagged.\n\n## Output Format\n\n### AI Feature PRD: [feature]\n\n**1. Problem & why AI** — the user problem, and why a model (not rules) is the right tool. If rules would do, say so.\n\n**2. Experience** — the core flow, and crucially the **UX of uncertainty**: how confidence is shown, how the user verifies/edits, and how errors are made cheap to recover from. AI features live or die here.\n\n**3. Model approach** — prompt / fine-tune / RAG / agent (link [`rag-design-doc`](../rag-design-doc/SKILL.md) or [`agent-spec`](../agent-spec/SKILL.md)), the model tier, and why.\n\n**4. Quality bar & evaluation** — the metrics and the explicit ship threshold; reference an [`ai-eval-plan`](../ai-eval-plan/SKILL.md). State the acceptable error rate given the stakes.\n\n**5. Guardrails & safety** — what the feature must never do, input/output filtering, and handling of harmful/PII/out-of-scope inputs.\n\n**6. Fallback behaviour** — what happens when the model is unsure, wrong, slow, or down: graceful degradation, \"I'm not sure\" states, human handoff. **No silent confident errors.**\n\n**7. Data flywheel** — how usage (and the 👍/👎 / edits) feed back into evaluation and improvement, with the privacy boundary.\n\n**8. Cost & latency** — the per-request budget and p95 target; reference an [`llm-cost-latency-budget`](../llm-cost-latency-budget/SKILL.md).\n\n**9. Rollout** — staged exposure (internal → %→ GA), the guardrail metrics watched, and the rollback trigger.\n\n## Quality Checks\n\n- [ ] The PRD designs for the model being wrong — there's an explicit fallback, not just the happy path\n- [ ] The UX shows uncertainty and lets the user verify/correct cheaply\n- [ ] There's an explicit quality bar tied to the stakes (a medical answer and a tweet draft are not the same bar)\n- [ ] Guardrails name what the feature must never do\n- [ ] A data flywheel is defined with its privacy boundary\n- [ ] Cost and p95 latency budgets are stated, not left to \"we'll see\"\n\n## Anti-Patterns\n\n- [ ] Do not design only the happy path — a probabilistic feature without a fallback is a feature that fails loudly in production\n- [ ] Do not hide uncertainty behind a confident UI — overclaimed confidence is how AI features lose user trust permanently\n- [ ] Do not use AI where deterministic rules are better, cheaper, and more reliable — \"AI\" is not the goal\n- [ ] Do not set one quality bar for all stakes — calibrate the acceptable error rate to the cost of being wrong\n- [ ] Do not ship without a rollback trigger and guardrail metrics — a probabilistic system needs a kill switch\n\n## Based On\n\nStandard PRD practice (see [`prd-template`](../prd-template/SKILL.md)) extended for probabilistic systems — uncertainty UX, eval gates, guardrails, and graceful fallback.","createdAt":"2026-09-25T12:51:59.629Z","updatedAt":"2026-09-25T12:51:59.629Z"},{"id":"cmugyn08002lsqu0656zo839l","slug":"mohitagw15856-pm-claude-skills-accommodation-request","name":"accommodation-request","description":"Request a reasonable accommodation at work or in education — frame it around the barrier and the adjustment (not your diagnosis), cite the right process, and navigate the back-and-forth constructively. Use when someone says 'I need a workplace accommodation', 'request reasonable adjustments', 'ADA/Equality Act accommodation', or 'how do I ask for accommodations for my disability/condition'. Produces the request letter, a barriers-and-adjustments map, disclosure guidance, and a plan for the interactive process. Not legal advice — routes to the formal process and to advocacy where needed.","authorId":"gh:mohitagw15856","authorName":"mohitagw15856","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":1397,"pricePerCall":0,"manifest":{"name":"accommodation-request","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Request a reasonable accommodation at work or in education — frame it around the barrier and the adjustment (not your diagnosis), cite the right process, and navigate the back-and-forth constructively. Use when someone says 'I need a workplace accommodation', 'request reasonable adjustments', 'ADA/Equality Act accommodation', or 'how do I ask for accommodations for my disability/condition'. Produces the request letter, a barriers-and-adjustments map, disclosure guidance, and a plan for the interactive process. Not legal advice — routes to the formal process and to advocacy where needed.","permissions":[],"systemPrompt":"# Accommodation Request Skill\n\nReasonable accommodations (US: ADA; UK: reasonable adjustments under the Equality Act;\nsimilar elsewhere) are a right, but getting them often stalls on how the request is\nframed: people over-share medical detail, ask for a vague \"help,\" or frame it as a\nfavor rather than an adjustment to a barrier. Employers and institutions respond best\nto a specific request that names the *barrier* and the *adjustment that removes it* —\nthey generally don't need your diagnosis, only the functional limitation and what\nhelps. This skill writes that request, guides how much to disclose, and prepares you\nfor the interactive back-and-forth that follows. It is not legal advice; it routes to\nthe formal process and to advocacy if you hit resistance.\n\n## What This Skill Produces\n\n- A **barriers-and-adjustments map**: for each thing that's hard, the specific\n  workplace/course barrier and the concrete adjustment that removes it (framed as an\n  adjustment to a barrier, not a personal favor)\n- The **request letter/email**: to the right person (HR, disability services, manager\n  per the process), citing the process, naming the adjustments, and inviting the\n  interactive dialogue\n- **Disclosure guidance**: how much to share (usually the functional limitation and\n  what helps, not the diagnosis), what you're not obliged to reveal, and where medical\n  documentation is genuinely needed\n- A **process plan**: the interactive/good-faith dialogue that's expected, how to\n  handle \"that's not possible,\" alternatives, and escalation to advocacy or the formal\n  complaint route if needed\n\n## Required Inputs\n\nAsk for (if not already provided):\n- The setting (workplace or education) and country/system, since the legal framework\n  and process differ\n- The specific difficulties and the tasks/situations where they bite (the barrier),\n  and what adjustments would help\n- What the user is comfortable disclosing and to whom, and whether there's an existing\n  process (HR policy, disability services office)\n- Any history (a prior refusal, a difficult manager) that shapes strategy\n\n## Framework\n\n1. **Frame around barrier → adjustment, not diagnosis.** The request names the barrier\n   (\"open-plan noise makes focused work impossible,\" \"fixed exam timing conflicts with\n   medication effects\") and the specific adjustment that removes it (noise-cancelling/\n   a quiet space, extra time/a separate room). The employer's duty attaches to the\n   barrier and the reasonable fix, not to your medical history.\n2. **Disclose the minimum that works.** Generally you must share enough functional\n   information to justify the adjustment and may need medical documentation of the\n   limitation — but not your full diagnosis or records. The skill helps calibrate:\n   enough to establish the need, no more, and names what you're not obliged to reveal.\n3. **Send it to the right process.** Route to whoever owns adjustments (HR, disability/\n   access services, occupational health) rather than only a manager who can't approve,\n   cite the relevant policy/law framing, and put it in writing so there's a record.\n4. **Expect the interactive dialogue — and engage it.** These processes are meant to be\n   a good-faith back-and-forth: they may propose alternatives, ask for documentation, or\n   push back on cost/feasibility. The skill preps constructive responses, the\n   \"undue-hardship/reasonableness\" conversation, and holding firm on the barrier while\n   being flexible on the exact fix.\n5. **Know the escalation and get support.** If met with refusal, delay, or retaliation:\n   the formal grievance/complaint route, disability advocacy organizations, and (where\n   warranted) legal advice. Retaliation for requesting accommodations is itself usually\n   unlawful — flag it, and route to real help rather than adjudicating it here.\n\n## Output Format\n\n```\n## Barriers → adjustments\n| The barrier (situation/task) | The adjustment that removes it |\n\n## Your request (send this)\n[To the right owner · cites the process · names the adjustments · invites the\ninteractive dialogue · in writing]\n\n## What to disclose (and what you needn't)\n[The functional info to share · documentation if genuinely needed · what you're not\nobliged to reveal]\n\n## The back-and-forth\n[Expect a good-faith dialogue · handling \"not possible\"/alternatives · firm on barrier,\nflexible on fix]\n\n## If you hit a wall\n[Grievance/complaint route · disability advocacy orgs · legal advice · retaliation is\nusually unlawful — get help]\n\n⚠ Not legal advice. Frameworks differ by country and situation; route to the formal\nprocess and to an advocate/lawyer if you meet resistance.\n```\n\n## Quality Checks\n\n- [ ] Every request is framed as barrier → adjustment, not as a diagnosis disclosure or\n      a favor\n- [ ] Disclosure is calibrated to the minimum needed, and what's not required is stated\n- [ ] It's routed to the actual owner of the process, in writing\n- [ ] The interactive/good-faith dialogue is anticipated with constructive responses\n- [ ] An escalation/advocacy path and the not-legal-advice line are present\n\n## Anti-Patterns\n\n- [ ] Do not over-disclose medical detail — the barrier and the fix are what matter\n- [ ] Do not assert specific legal entitlements or \"undue hardship\" thresholds as fact —\n      they vary; route to the process and to advocacy\n- [ ] Do not frame it as asking a favor — it's a request to remove a barrier, often a legal duty\n- [ ] Do not counsel giving up at first refusal — the interactive process and escalation\n      exist for exactly that\n- [ ] Do not treat retaliation as normal — flag it and route to real help\n\n## Related\n\n[[disability-disclosure-decision]] for the whether/how of telling work at all;\n[[disability-benefit-appeal]] for the benefits side; [[venue-access-check]] and\n[[accessible-travel-planner]] for physical access; [[nt-translator]] for the workplace-\ncommunication layer.","schemaVersion":1},"repoUrl":"https://github.com/mohitagw15856/pm-claude-skills/tree/main/skills/accommodation-request","tags":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pm-claude-skills","audit":{"files":["package.json"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-02","message":"`postinstall` script runs on every install.","surface":"package.json","evidence":"postinstall: node bin/postinstall.mjs","severity":"high"}],"packages":0,"auditedAt":"2026-09-25T12:51:59.225Z","lockfiles":[]},"forks":249,"owner":"mohitagw15856","stars":1397,"topics":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini","llm","mcp","mcp-server","product-management","productivity","prompt-engineering","prompts","skills"],"license":"MIT","fullName":"mohitagw15856/pm-claude-skills","homepage":"https://mohitagw15856.github.io/pm-claude-skills/","language":"HTML","pushedAt":"2026-09-25T10:13:15Z","avatarUrl":"https://avatars.githubusercontent.com/u/119053560?v=4","crawledAt":"2026-09-25T12:51:48.196Z","openIssues":13,"manifestFile":"SKILL.md","manifestPath":"skills/accommodation-request/SKILL.md","defaultBranch":"main"},"readme":"# Accommodation Request Skill\n\nReasonable accommodations (US: ADA; UK: reasonable adjustments under the Equality Act;\nsimilar elsewhere) are a right, but getting them often stalls on how the request is\nframed: people over-share medical detail, ask for a vague \"help,\" or frame it as a\nfavor rather than an adjustment to a barrier. Employers and institutions respond best\nto a specific request that names the *barrier* and the *adjustment that removes it* —\nthey generally don't need your diagnosis, only the functional limitation and what\nhelps. This skill writes that request, guides how much to disclose, and prepares you\nfor the interactive back-and-forth that follows. It is not legal advice; it routes to\nthe formal process and to advocacy if you hit resistance.\n\n## What This Skill Produces\n\n- A **barriers-and-adjustments map**: for each thing that's hard, the specific\n  workplace/course barrier and the concrete adjustment that removes it (framed as an\n  adjustment to a barrier, not a personal favor)\n- The **request letter/email**: to the right person (HR, disability services, manager\n  per the process), citing the process, naming the adjustments, and inviting the\n  interactive dialogue\n- **Disclosure guidance**: how much to share (usually the functional limitation and\n  what helps, not the diagnosis), what you're not obliged to reveal, and where medical\n  documentation is genuinely needed\n- A **process plan**: the interactive/good-faith dialogue that's expected, how to\n  handle \"that's not possible,\" alternatives, and escalation to advocacy or the formal\n  complaint route if needed\n\n## Required Inputs\n\nAsk for (if not already provided):\n- The setting (workplace or education) and country/system, since the legal framework\n  and process differ\n- The specific difficulties and the tasks/situations where they bite (the barrier),\n  and what adjustments would help\n- What the user is comfortable disclosing and to whom, and whether there's an existing\n  process (HR policy, disability services office)\n- Any history (a prior refusal, a difficult manager) that shapes strategy\n\n## Framework\n\n1. **Frame around barrier → adjustment, not diagnosis.** The request names the barrier\n   (\"open-plan noise makes focused work impossible,\" \"fixed exam timing conflicts with\n   medication effects\") and the specific adjustment that removes it (noise-cancelling/\n   a quiet space, extra time/a separate room). The employer's duty attaches to the\n   barrier and the reasonable fix, not to your medical history.\n2. **Disclose the minimum that works.** Generally you must share enough functional\n   information to justify the adjustment and may need medical documentation of the\n   limitation — but not your full diagnosis or records. The skill helps calibrate:\n   enough to establish the need, no more, and names what you're not obliged to reveal.\n3. **Send it to the right process.** Route to whoever owns adjustments (HR, disability/\n   access services, occupational health) rather than only a manager who can't approve,\n   cite the relevant policy/law framing, and put it in writing so there's a record.\n4. **Expect the interactive dialogue — and engage it.** These processes are meant to be\n   a good-faith back-and-forth: they may propose alternatives, ask for documentation, or\n   push back on cost/feasibility. The skill preps constructive responses, the\n   \"undue-hardship/reasonableness\" conversation, and holding firm on the barrier while\n   being flexible on the exact fix.\n5. **Know the escalation and get support.** If met with refusal, delay, or retaliation:\n   the formal grievance/complaint route, disability advocacy organizations, and (where\n   warranted) legal advice. Retaliation for requesting accommodations is itself usually\n   unlawful — flag it, and route to real help rather than adjudicating it here.\n\n## Output Format\n\n```\n## Barriers → adjustments\n| The barrier (situation/task) | The adjustment that removes it |\n\n## Your request (send this)\n[To the right owner ·","createdAt":"2026-09-25T12:51:59.328Z","updatedAt":"2026-09-25T12:51:59.328Z"},{"id":"cmugyn0aj02mgqu06ss899k0w","slug":"mohitagw15856-pm-claude-skills-agenda-or-cancel","name":"agenda-or-cancel","description":"Enforce the simplest meeting rule that works — no agenda, no meeting — with the three-line agenda format (purpose, decisions sought, pre-reads), the 24-hour rule, and the graceful cancel scripts. Use when asked write an agenda for this meeting, should this meeting happen, our meetings have no agendas, or cancel this meeting politely. Produces the three-line agenda, the happen-or-cancel verdict, the cancel/convert scripts, and the team norm rollout.","authorId":"gh:mohitagw15856","authorName":"mohitagw15856","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":1397,"pricePerCall":0,"manifest":{"name":"agenda-or-cancel","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Enforce the simplest meeting rule that works — no agenda, no meeting — with the three-line agenda format (purpose, decisions sought, pre-reads), the 24-hour rule, and the graceful cancel scripts. Use when asked write an agenda for this meeting, should this meeting happen, our meetings have no agendas, or cancel this meeting politely. Produces the three-line agenda, the happen-or-cancel verdict, the cancel/convert scripts, and the team norm rollout.","permissions":[],"systemPrompt":"# Agenda Or Cancel Skill\n\nThe agenda isn't paperwork — it's the meeting's existence test. A meeting whose organizer can't write three lines (what this is for, what we'll decide, what to read first) is a meeting that hasn't earned its attendee-hours, and the kindest outcome is its cancellation or conversion to a message. This skill writes the agenda when one can be written, renders the cancel verdict when it can't, and scripts the graceful exits — because \"no agenda, no meeting\" only works as a norm when declining is socially cheap.\n\n## What This Skill Produces\n\n- **The three-line agenda** — purpose (one sentence), decisions/outcomes sought (listed), pre-reads with time cost\n- **The verdict** — happen / shorten / convert-to-async / cancel — from the agenda-writing attempt itself\n- **The scripts** — the polite cancel, the convert-to-message, and the decline-without-agenda lines\n- **The norm rollout** — how a team installs the rule without a compliance war\n\n## Required Inputs\n\nAsk for these if not provided:\n- **The meeting's claimed purpose** — what the organizer thinks it's for; the agenda attempt tests whether that survives writing down\n- **The attendee list and length** — the cost side (people × time), which the purpose must justify\n- **What a good outcome looks like** — a decision? alignment? information moved? If the outcome is \"information moved,\" the convert-to-async branch is already winning\n- **The recurring-or-oneoff status** — recurring meetings route to [standing-meeting-audit](../standing-meeting-audit/SKILL.md) for the deeper treatment\n\n## Framework: The Test Rules\n\n1. **The agenda is three lines or the meeting is fiction:** *Purpose:* why we're gathering, one sentence. *Outcomes:* the decisions or artifacts this meeting produces (verbs, not topics). *Pre-reads:* what to read and how long it takes. If line two can't list a decision or artifact, the meeting is a broadcast — and broadcasts are messages.\n2. **The 24-hour rule:** agenda ships with (or ≥24h before) the invite — attendees who can't prepare attend as audience, and audiences don't decide. Meetings that can't produce an agenda a day out aren't urgent; they're unformed.\n3. **The verdict follows the attempt:** agenda writes cleanly → happen (at the length the outcomes justify — most three-line agendas fit 25 minutes). Outcomes are all information-transfer → convert to a message/doc. Purpose exists but no decisions this week → shorten or skip this instance. Nothing survives writing down → cancel, with the script.\n4. **Declining needs a cheap script:** \"Happy to join — could you share the agenda first so I can prep?\" does the enforcement politely; the norm survives only if asking is routine, not confrontational. Organizer-side cancel: \"Cancelling — the two items resolved async / aren't ready for decisions yet. Reconvening when [trigger].\"\n5. **Roll out as a gift, not a law:** the team adopts \"agenda-or-cancel\" by the leader modeling it on their *own* meetings first (cancelling one publicly is worth ten policy emails), the three-line format pinned where invites happen, and the decline script blessed explicitly so juniors can use it upward.\n\n## Output Format\n\n# Agenda Test: [meeting]\n\n## The Three Lines\n**Purpose:** … **Outcomes:** [decisions/artifacts, verbs] **Pre-reads:** [links + minutes]\n\n## The Verdict\n[Happen ([N] min) / shorten / convert / cancel — with the reasoning from the attempt]\n\n## Scripts (as needed)\n[The cancel · the convert-to-message · the agenda-first decline]\n\n## Rollout (for teams installing the norm)\n[Leader models on own meetings · format pinned · decline script blessed downward and upward]\n\n## Quality Checks\n\n- [ ] The outcomes line contains decisions or artifacts, not topic nouns\n- [ ] Pre-reads carry their time cost\n- [ ] The verdict came from the writing attempt, not from meeting-hating priors\n- [ ] Every script is usable by the most junior attendee\n- [ ] Recurring meetings were routed to the audit instead of one-off verdicts\n\n## Anti-Patterns\n\n- [ ] Do not write topic agendas — \"discuss roadmap\" is a location, not a purpose\n- [ ] Do not accept \"we'll figure it out live\" — that's the agenda test failing in real time, at full attendance\n- [ ] Do not use the rule as a weapon — the verdict includes \"happen\"; meeting-zero is not the goal, meeting-earned is\n- [ ] Do not ship the agenda at meeting-start — unprepped deciders are attendees\n- [ ] Do not install the norm by decree — the leader's own cancelled meeting is the announcement","schemaVersion":1},"repoUrl":"https://github.com/mohitagw15856/pm-claude-skills/tree/main/skills/agenda-or-cancel","tags":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pm-claude-skills","audit":{"files":["package.json"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-02","message":"`postinstall` script runs on every install.","surface":"package.json","evidence":"postinstall: node bin/postinstall.mjs","severity":"high"}],"packages":0,"auditedAt":"2026-09-25T12:51:59.225Z","lockfiles":[]},"forks":249,"owner":"mohitagw15856","stars":1397,"topics":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini","llm","mcp","mcp-server","product-management","productivity","prompt-engineering","prompts","skills"],"license":"MIT","fullName":"mohitagw15856/pm-claude-skills","homepage":"https://mohitagw15856.github.io/pm-claude-skills/","language":"HTML","pushedAt":"2026-09-25T10:13:15Z","avatarUrl":"https://avatars.githubusercontent.com/u/119053560?v=4","crawledAt":"2026-09-25T12:51:48.196Z","openIssues":13,"manifestFile":"SKILL.md","manifestPath":"skills/agenda-or-cancel/SKILL.md","defaultBranch":"main"},"readme":"# Agenda Or Cancel Skill\n\nThe agenda isn't paperwork — it's the meeting's existence test. A meeting whose organizer can't write three lines (what this is for, what we'll decide, what to read first) is a meeting that hasn't earned its attendee-hours, and the kindest outcome is its cancellation or conversion to a message. This skill writes the agenda when one can be written, renders the cancel verdict when it can't, and scripts the graceful exits — because \"no agenda, no meeting\" only works as a norm when declining is socially cheap.\n\n## What This Skill Produces\n\n- **The three-line agenda** — purpose (one sentence), decisions/outcomes sought (listed), pre-reads with time cost\n- **The verdict** — happen / shorten / convert-to-async / cancel — from the agenda-writing attempt itself\n- **The scripts** — the polite cancel, the convert-to-message, and the decline-without-agenda lines\n- **The norm rollout** — how a team installs the rule without a compliance war\n\n## Required Inputs\n\nAsk for these if not provided:\n- **The meeting's claimed purpose** — what the organizer thinks it's for; the agenda attempt tests whether that survives writing down\n- **The attendee list and length** — the cost side (people × time), which the purpose must justify\n- **What a good outcome looks like** — a decision? alignment? information moved? If the outcome is \"information moved,\" the convert-to-async branch is already winning\n- **The recurring-or-oneoff status** — recurring meetings route to [standing-meeting-audit](../standing-meeting-audit/SKILL.md) for the deeper treatment\n\n## Framework: The Test Rules\n\n1. **The agenda is three lines or the meeting is fiction:** *Purpose:* why we're gathering, one sentence. *Outcomes:* the decisions or artifacts this meeting produces (verbs, not topics). *Pre-reads:* what to read and how long it takes. If line two can't list a decision or artifact, the meeting is a broadcast — and broadcasts are messages.\n2. **The 24-hour rule:** agenda ships with (or ≥24h before) the invite — attendees who can't prepare attend as audience, and audiences don't decide. Meetings that can't produce an agenda a day out aren't urgent; they're unformed.\n3. **The verdict follows the attempt:** agenda writes cleanly → happen (at the length the outcomes justify — most three-line agendas fit 25 minutes). Outcomes are all information-transfer → convert to a message/doc. Purpose exists but no decisions this week → shorten or skip this instance. Nothing survives writing down → cancel, with the script.\n4. **Declining needs a cheap script:** \"Happy to join — could you share the agenda first so I can prep?\" does the enforcement politely; the norm survives only if asking is routine, not confrontational. Organizer-side cancel: \"Cancelling — the two items resolved async / aren't ready for decisions yet. Reconvening when [trigger].\"\n5. **Roll out as a gift, not a law:** the team adopts \"agenda-or-cancel\" by the leader modeling it on their *own* meetings first (cancelling one publicly is worth ten policy emails), the three-line format pinned where invites happen, and the decline script blessed explicitly so juniors can use it upward.\n\n## Output Format\n\n# Agenda Test: [meeting]\n\n## The Three Lines\n**Purpose:** … **Outcomes:** [decisions/artifacts, verbs] **Pre-reads:** [links + minutes]\n\n## The Verdict\n[Happen ([N] min) / shorten / convert / cancel — with the reasoning from the attempt]\n\n## Scripts (as needed)\n[The cancel · the convert-to-message · the agenda-first decline]\n\n## Rollout (for teams installing the norm)\n[Leader models on own meetings · format pinned · decline script blessed downward and upward]\n\n## Quality Checks\n\n- [ ] The outcomes line contains decisions or artifacts, not topic nouns\n- [ ] Pre-reads carry their time cost\n- [ ] The verdict came from the writing attempt, not from meeting-hating priors\n- [ ] Every script is usable by the most junior attendee\n- [ ] Recurring meetings were routed to the audit instead of one-off verdicts\n\n## Anti-P","createdAt":"2026-09-25T12:51:59.420Z","updatedAt":"2026-09-25T12:51:59.420Z"},{"id":"cmugyn0au02mjqu06w84rnbyp","slug":"mohitagw15856-pm-claude-skills-agent-design-review","name":"agent-design-review","description":"Review an LLM agent design and find where it will be unreliable, expensive, or unsafe. Use when asked to review an agent architecture, critique a multi-step/tool-using agent, debug an agent that loops or goes off-task, or harden an agent before launch. Produces a structured review — task fit, control flow, tools, memory/context, failure handling, cost, and safety — with prioritised findings and fixes.","authorId":"gh:mohitagw15856","authorName":"mohitagw15856","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":1397,"pricePerCall":0,"manifest":{"name":"agent-design-review","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Review an LLM agent design and find where it will be unreliable, expensive, or unsafe. Use when asked to review an agent architecture, critique a multi-step/tool-using agent, debug an agent that loops or goes off-task, or harden an agent before launch. Produces a structured review — task fit, control flow, tools, memory/context, failure handling, cost, and safety — with prioritised findings and fixes.","permissions":[],"systemPrompt":"# Agent Design Review Skill\n\nMost agents don't fail because the model is weak — they fail because the *design* lets them loop, call the\nwrong tool, lose the thread across steps, or burn tokens with no stopping rule. This skill reviews an agent's\narchitecture against the decisions that actually determine reliability, and ranks the fixes — so \"it works in\nthe demo but not in prod\" becomes a specific list of changes. (Writing a new agent spec? Use\n[`agent-spec`](../agent-spec/SKILL.md).)\n\n## Working from a brief\n\nGiven a sketch (\"a research agent that searches, reads, and writes a report\"), **deliver the full review\nanyway** — infer the likely control flow and tools, label the inference, and flag what to confirm. Never\nwithhold the review for missing detail.\n\n## Required Inputs\n\nAsk for these only if they aren't already provided (else infer and label):\n\n- **What the agent does** — its goal, and what a successful run produces.\n- **Control flow** — single prompt, plan-then-execute, ReAct loop, or multi-agent; and the stopping condition.\n- **Tools & actions** — what it can call, and which actions have side effects (write, send, pay).\n- **Memory & context** — what state carries across steps, and how context is kept in budget.\n- **Constraints** — latency, cost per run, and the trust boundary (untrusted input? real-world actions?).\n\n## Output Format\n\n### Agent Review: [agent]\n\n**1. Summary** — will this be reliable in production? The top 3 risks and the single change that helps most.\n\n**2. Findings by dimension** — for each, what's sound and what's fragile:\n\n| Dimension | Finding | Severity | Fix |\n|---|---|---|---|\n| Control flow | no max-steps / no progress check → loops | High | step budget + \"am I making progress?\" check + halt |\n| Tool use | overlapping tools confuse selection | Med | fewer, sharply-described tools; allowlist |\n| Context | full history re-sent each step → cost + drift | High | summarise/scope memory per step |\n| Failure handling | one tool error aborts the run | Med | retry/backoff + graceful degradation |\n| Safety | acts without confirmation on writes | High | human/confirm gate on side-effecting actions |\n\n**3. Reliability checklist** — termination guarantee (it always stops), error recovery, idempotency of\nside-effecting actions, and determinism where it matters.\n\n**4. Cost & latency** — where tokens/steps are spent and how to cut them (cheaper model for sub-steps, caching, fewer round-trips) without losing quality. Pair with [`llm-cost-latency-budget`](../llm-cost-latency-budget/SKILL.md).\n\n**5. Safety** — untrusted input/tool output handled as data not instructions, least-privilege tools, and\nconfirmation gates on high-impact actions. Pair with [`llm-guardrails-spec`](../llm-guardrails-spec/SKILL.md).\n\n**6. Prioritised fix plan** — ordered by impact-to-effort.\n\n## Quality Checks\n\n- [ ] The agent has a guaranteed stopping condition (step/budget cap + progress check) — no unbounded loops\n- [ ] Side-effecting actions are idempotent or gated by a confirmation\n- [ ] Tools are few and sharply described so selection is unambiguous; access is least-privilege\n- [ ] Context strategy keeps the window in budget across steps (no naive full-history resend)\n- [ ] Tool errors are recovered, not fatal — retry/backoff and graceful degradation\n- [ ] Findings are severity-ranked and the fix plan is ordered by impact\n\n## Anti-Patterns\n\n- [ ] Do not approve an agent with no termination guarantee — \"it usually stops\" is an outage waiting to happen\n- [ ] Do not let it take irreversible actions without a confirmation gate\n- [ ] Do not give it many overlapping tools — selection accuracy drops as the toolset grows\n- [ ] Do not resend the whole history every step — cost and drift both climb\n- [ ] Do not treat tool/retrieved output as trusted instructions — it's the injection surface\n\n## Based On\n\nLLM agent design practice — bounded control flow, least-privilege tool use, context management, error recovery, and safety gating.","schemaVersion":1},"repoUrl":"https://github.com/mohitagw15856/pm-claude-skills/tree/main/skills/agent-design-review","tags":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pm-claude-skills","audit":{"files":["package.json"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-02","message":"`postinstall` script runs on every install.","surface":"package.json","evidence":"postinstall: node bin/postinstall.mjs","severity":"high"}],"packages":0,"auditedAt":"2026-09-25T12:51:59.225Z","lockfiles":[]},"forks":249,"owner":"mohitagw15856","stars":1397,"topics":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini","llm","mcp","mcp-server","product-management","productivity","prompt-engineering","prompts","skills"],"license":"MIT","fullName":"mohitagw15856/pm-claude-skills","homepage":"https://mohitagw15856.github.io/pm-claude-skills/","language":"HTML","pushedAt":"2026-09-25T10:13:15Z","avatarUrl":"https://avatars.githubusercontent.com/u/119053560?v=4","crawledAt":"2026-09-25T12:51:48.196Z","openIssues":13,"manifestFile":"SKILL.md","manifestPath":"skills/agent-design-review/SKILL.md","defaultBranch":"main"},"readme":"# Agent Design Review Skill\n\nMost agents don't fail because the model is weak — they fail because the *design* lets them loop, call the\nwrong tool, lose the thread across steps, or burn tokens with no stopping rule. This skill reviews an agent's\narchitecture against the decisions that actually determine reliability, and ranks the fixes — so \"it works in\nthe demo but not in prod\" becomes a specific list of changes. (Writing a new agent spec? Use\n[`agent-spec`](../agent-spec/SKILL.md).)\n\n## Working from a brief\n\nGiven a sketch (\"a research agent that searches, reads, and writes a report\"), **deliver the full review\nanyway** — infer the likely control flow and tools, label the inference, and flag what to confirm. Never\nwithhold the review for missing detail.\n\n## Required Inputs\n\nAsk for these only if they aren't already provided (else infer and label):\n\n- **What the agent does** — its goal, and what a successful run produces.\n- **Control flow** — single prompt, plan-then-execute, ReAct loop, or multi-agent; and the stopping condition.\n- **Tools & actions** — what it can call, and which actions have side effects (write, send, pay).\n- **Memory & context** — what state carries across steps, and how context is kept in budget.\n- **Constraints** — latency, cost per run, and the trust boundary (untrusted input? real-world actions?).\n\n## Output Format\n\n### Agent Review: [agent]\n\n**1. Summary** — will this be reliable in production? The top 3 risks and the single change that helps most.\n\n**2. Findings by dimension** — for each, what's sound and what's fragile:\n\n| Dimension | Finding | Severity | Fix |\n|---|---|---|---|\n| Control flow | no max-steps / no progress check → loops | High | step budget + \"am I making progress?\" check + halt |\n| Tool use | overlapping tools confuse selection | Med | fewer, sharply-described tools; allowlist |\n| Context | full history re-sent each step → cost + drift | High | summarise/scope memory per step |\n| Failure handling | one tool error aborts the run | Med | retry/backoff + graceful degradation |\n| Safety | acts without confirmation on writes | High | human/confirm gate on side-effecting actions |\n\n**3. Reliability checklist** — termination guarantee (it always stops), error recovery, idempotency of\nside-effecting actions, and determinism where it matters.\n\n**4. Cost & latency** — where tokens/steps are spent and how to cut them (cheaper model for sub-steps, caching, fewer round-trips) without losing quality. Pair with [`llm-cost-latency-budget`](../llm-cost-latency-budget/SKILL.md).\n\n**5. Safety** — untrusted input/tool output handled as data not instructions, least-privilege tools, and\nconfirmation gates on high-impact actions. Pair with [`llm-guardrails-spec`](../llm-guardrails-spec/SKILL.md).\n\n**6. Prioritised fix plan** — ordered by impact-to-effort.\n\n## Quality Checks\n\n- [ ] The agent has a guaranteed stopping condition (step/budget cap + progress check) — no unbounded loops\n- [ ] Side-effecting actions are idempotent or gated by a confirmation\n- [ ] Tools are few and sharply described so selection is unambiguous; access is least-privilege\n- [ ] Context strategy keeps the window in budget across steps (no naive full-history resend)\n- [ ] Tool errors are recovered, not fatal — retry/backoff and graceful degradation\n- [ ] Findings are severity-ranked and the fix plan is ordered by impact\n\n## Anti-Patterns\n\n- [ ] Do not approve an agent with no termination guarantee — \"it usually stops\" is an outage waiting to happen\n- [ ] Do not let it take irreversible actions without a confirmation gate\n- [ ] Do not give it many overlapping tools — selection accuracy drops as the toolset grows\n- [ ] Do not resend the whole history every step — cost and drift both climb\n- [ ] Do not treat tool/retrieved output as trusted instructions — it's the injection surface\n\n## Based On\n\nLLM agent design practice — bounded control flow, least-privilege tool use, context management, error recovery, and safety gating.","createdAt":"2026-09-25T12:51:59.430Z","updatedAt":"2026-09-25T12:51:59.430Z"},{"id":"cmugyn0b402mmqu06x9img6vn","slug":"mohitagw15856-pm-claude-skills-agent-era-pricing","name":"agent-era-pricing","description":"Redesign seat-based pricing for the agent era — when one human runs ten agents, per-seat models collapse. Use when agents are eroding seat counts, when asked to migrate to usage- or outcome-based pricing, to price an agent/API tier, or to defend revenue as customers automate their own usage. Produces a pricing migration plan: the new value metric, fences, agent-tier design, cannibalisation math, and a phased migration for existing customers. For general pricing and packaging strategy use pricing-strategy.","authorId":"gh:mohitagw15856","authorName":"mohitagw15856","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":1397,"pricePerCall":0,"manifest":{"name":"agent-era-pricing","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Redesign seat-based pricing for the agent era — when one human runs ten agents, per-seat models collapse. Use when agents are eroding seat counts, when asked to migrate to usage- or outcome-based pricing, to price an agent/API tier, or to defend revenue as customers automate their own usage. Produces a pricing migration plan: the new value metric, fences, agent-tier design, cannibalisation math, and a phased migration for existing customers. For general pricing and packaging strategy use pricing-strategy.","permissions":[],"systemPrompt":"# Agent Era Pricing Skill\n\nSeat pricing quietly assumed the user was a human who logs in. Agents break the assumption from both sides: your customers need fewer seats (one operator, ten agents), and your product gets *more* usage than ever. This skill redesigns the model around a value metric that survives non-human users — without torching existing revenue on the way.\n\n## What This Skill Produces\n\n- A **value-metric decision**: what you charge for when seats stop proxying value\n- **Agent-tier design**: how agent/API usage is packaged, fenced, and priced\n- **Cannibalisation math**: what happens to current revenue under the new model, computed on real cohorts\n- A **phased migration plan** for existing customers, with the grandfathering decision made explicitly\n\n## Required Inputs\n\nAsk for (if not already provided):\n- **Current model**: plans, price points, seat definitions, current API/automation pricing if any\n- **The evidence of pressure**: seat contraction, API traffic growth, customer asks, competitor moves\n- **Unit economics**: cost to serve a seat vs an API call/agent action (rough is fine, labelled)\n- **3-5 representative customer profiles** with seat counts and usage (the cannibalisation test set)\n\n## Method\n\n1. **Find the value metric that survives agents.** Test candidates against three questions: does it scale with the value the *customer* receives (not your costs)? · is it counted identically whether a human or agent drives it? · can the customer predict their bill? Strong candidates are usually *outcomes or work-objects* (invoices processed, tickets resolved, campaigns run, records enriched) — not raw API calls (unpredictable, punishes retries) and not seats (dying assumption).\n2. **Price the human and the agent differently, deliberately.** The durable pattern is a hybrid: a **platform/human layer** (flat or few-seats — access, admin, support) plus a **work layer** priced on the value metric, agnostic to who did the work. Decide where agents authenticate: agent traffic on a user's token counted as that user's work, not as a \"seat\".\n3. **Design the fences.** What separates tiers now that seats don't: volume bands on the value metric, rate/concurrency limits, SSO/audit/compliance (still human-org fences), model/automation quality tiers. Every fence must be *measurable* and *hard to game* — name the gaming vector for each and why it's acceptable.\n4. **Run the cannibalisation math on real cohorts.** For each customer profile: current annual price vs new-model price at current usage, at 2× automation, at 5×. Sum to a revenue bridge. If the new model loses money on your best cohort, the metric or the bands are wrong — fix the model, don't hide the row.\n5. **Phase the migration.** New customers first (cleanest signal) → opt-in for existing (with a calculator showing their number) → forced migration only with long notice and a cap (\"no more than X% increase in year one\"). Grandfathering is a *decision with a cost*, not a default: state what perpetual legacy plans cost in five years.\n6. **Set the tripwires.** Which metrics reprice this model: value-metric inflation/deflation, gaming detected, agent share of traffic crossing thresholds. Pricing in the agent era is a program, not a project.\n\n## Output Format\n\n### Agent-Era Pricing Plan: [product]\n\n**Diagnosis:** [the seat-erosion evidence, quantified]\n**Value metric:** [chosen metric] — because [the three-question test, answered]. Rejected: [runner-up + why].\n\n**The model**\n| Layer | What's included | Priced on | Tiers/bands |\n|---|---|---|---|\n| Platform (humans) | | | |\n| Work (human or agent) | | | |\n\n**Fences:** [fence → what it separates → gaming vector → why acceptable]\n\n**Cannibalisation bridge**\n| Cohort | Today | New @ current usage | New @ 2× automation | Δ |\n|---|---|---|---|---|\n\n**Migration:** [phase → who → when → the cap/grandfather decision, stated]\n**Tripwires:** [metric → threshold → action]\n\n## Quality Checks\n\n- [ ] The value metric passes all three tests (customer value · human/agent-agnostic · predictable)\n- [ ] Cannibalisation is computed on the provided cohorts, not asserted — assumptions labelled\n- [ ] Every fence names its gaming vector\n- [ ] The migration includes an explicit grandfathering decision with its long-run cost\n- [ ] Agent authentication/attribution is specified — whose usage is whose bill\n\n## Anti-Patterns\n\n- [ ] Do not price raw API calls as the value metric — unpredictable bills punish exactly the automation you want to encourage\n- [ ] Do not bolt an \"agent seat\" onto seat pricing — an agent is not a discount human; the assumption is what broke\n- [ ] Do not present only the happy cohort — the bridge shows the losers or it isn't math\n- [ ] Do not force-migrate loyal customers without a year-one cap — churn from pricing anger costs more than the uplift\n- [ ] Do not skip tripwires — a static price in a shifting usage regime is a slow leak in one direction or the other","schemaVersion":1},"repoUrl":"https://github.com/mohitagw15856/pm-claude-skills/tree/main/skills/agent-era-pricing","tags":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pm-claude-skills","audit":{"files":["package.json"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-02","message":"`postinstall` script runs on every install.","surface":"package.json","evidence":"postinstall: node bin/postinstall.mjs","severity":"high"}],"packages":0,"auditedAt":"2026-09-25T12:51:59.225Z","lockfiles":[]},"forks":249,"owner":"mohitagw15856","stars":1397,"topics":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini","llm","mcp","mcp-server","product-management","productivity","prompt-engineering","prompts","skills"],"license":"MIT","fullName":"mohitagw15856/pm-claude-skills","homepage":"https://mohitagw15856.github.io/pm-claude-skills/","language":"HTML","pushedAt":"2026-09-25T10:13:15Z","avatarUrl":"https://avatars.githubusercontent.com/u/119053560?v=4","crawledAt":"2026-09-25T12:51:48.196Z","openIssues":13,"manifestFile":"SKILL.md","manifestPath":"skills/agent-era-pricing/SKILL.md","defaultBranch":"main"},"readme":"# Agent Era Pricing Skill\n\nSeat pricing quietly assumed the user was a human who logs in. Agents break the assumption from both sides: your customers need fewer seats (one operator, ten agents), and your product gets *more* usage than ever. This skill redesigns the model around a value metric that survives non-human users — without torching existing revenue on the way.\n\n## What This Skill Produces\n\n- A **value-metric decision**: what you charge for when seats stop proxying value\n- **Agent-tier design**: how agent/API usage is packaged, fenced, and priced\n- **Cannibalisation math**: what happens to current revenue under the new model, computed on real cohorts\n- A **phased migration plan** for existing customers, with the grandfathering decision made explicitly\n\n## Required Inputs\n\nAsk for (if not already provided):\n- **Current model**: plans, price points, seat definitions, current API/automation pricing if any\n- **The evidence of pressure**: seat contraction, API traffic growth, customer asks, competitor moves\n- **Unit economics**: cost to serve a seat vs an API call/agent action (rough is fine, labelled)\n- **3-5 representative customer profiles** with seat counts and usage (the cannibalisation test set)\n\n## Method\n\n1. **Find the value metric that survives agents.** Test candidates against three questions: does it scale with the value the *customer* receives (not your costs)? · is it counted identically whether a human or agent drives it? · can the customer predict their bill? Strong candidates are usually *outcomes or work-objects* (invoices processed, tickets resolved, campaigns run, records enriched) — not raw API calls (unpredictable, punishes retries) and not seats (dying assumption).\n2. **Price the human and the agent differently, deliberately.** The durable pattern is a hybrid: a **platform/human layer** (flat or few-seats — access, admin, support) plus a **work layer** priced on the value metric, agnostic to who did the work. Decide where agents authenticate: agent traffic on a user's token counted as that user's work, not as a \"seat\".\n3. **Design the fences.** What separates tiers now that seats don't: volume bands on the value metric, rate/concurrency limits, SSO/audit/compliance (still human-org fences), model/automation quality tiers. Every fence must be *measurable* and *hard to game* — name the gaming vector for each and why it's acceptable.\n4. **Run the cannibalisation math on real cohorts.** For each customer profile: current annual price vs new-model price at current usage, at 2× automation, at 5×. Sum to a revenue bridge. If the new model loses money on your best cohort, the metric or the bands are wrong — fix the model, don't hide the row.\n5. **Phase the migration.** New customers first (cleanest signal) → opt-in for existing (with a calculator showing their number) → forced migration only with long notice and a cap (\"no more than X% increase in year one\"). Grandfathering is a *decision with a cost*, not a default: state what perpetual legacy plans cost in five years.\n6. **Set the tripwires.** Which metrics reprice this model: value-metric inflation/deflation, gaming detected, agent share of traffic crossing thresholds. Pricing in the agent era is a program, not a project.\n\n## Output Format\n\n### Agent-Era Pricing Plan: [product]\n\n**Diagnosis:** [the seat-erosion evidence, quantified]\n**Value metric:** [chosen metric] — because [the three-question test, answered]. Rejected: [runner-up + why].\n\n**The model**\n| Layer | What's included | Priced on | Tiers/bands |\n|---|---|---|---|\n| Platform (humans) | | | |\n| Work (human or agent) | | | |\n\n**Fences:** [fence → what it separates → gaming vector → why acceptable]\n\n**Cannibalisation bridge**\n| Cohort | Today | New @ current usage | New @ 2× automation | Δ |\n|---|---|---|---|---|\n\n**Migration:** [phase → who → when → the cap/grandfather decision, stated]\n**Tripwires:** [metric → threshold → action]\n\n## Quality Checks\n\n- [ ] The value metric passes all three tests (","createdAt":"2026-09-25T12:51:59.440Z","updatedAt":"2026-09-25T12:51:59.440Z"},{"id":"cmugyn0bg02mpqu0633i5tjxd","slug":"mohitagw15856-pm-claude-skills-agent-hiring-panel","name":"agent-hiring-panel","description":"Hire an AI agent the way you'd hire an employee — a role spec with success criteria, a structured work-sample interview run on your real tasks, reference checks (what do actual users report), probation KPIs, and termination criteria written before day one. Use when choosing between AI agents/tools/copilots for a job, formalizing an AI pilot, or 'which agent should we use for X'. Produces the role spec, interview pack with scoring rubric, a decision record, and a probation plan.","authorId":"gh:mohitagw15856","authorName":"mohitagw15856","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":1397,"pricePerCall":0,"manifest":{"name":"agent-hiring-panel","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Hire an AI agent the way you'd hire an employee — a role spec with success criteria, a structured work-sample interview run on your real tasks, reference checks (what do actual users report), probation KPIs, and termination criteria written before day one. Use when choosing between AI agents/tools/copilots for a job, formalizing an AI pilot, or 'which agent should we use for X'. Produces the role spec, interview pack with scoring rubric, a decision record, and a probation plan.","permissions":[],"systemPrompt":"# Agent Hiring Panel Skill\n\nCompanies that run three interview rounds for a junior hire will adopt an AI\nagent for the same work off a demo video and a pricing page. Then the pilot\ndrifts: no success criteria, no probation, no one empowered to fire it. This\nskill applies the hiring discipline that already exists in your org to the\nagent: write the role before meeting candidates, interview with *work samples\nfrom your real backlog*, check references, and — the step that makes the whole\nthing honest — define termination criteria before day one, because a hire you\ncan't fire is a dependency, not an employee.\n\n## What This Skill Produces\n\n- A **role spec**: the job, the boundaries (what it must never do), success\n  criteria measurable in probation, and the human it reports to\n- An **interview pack**: 3–5 work samples from the org's real tasks, run\n  identically across candidates, with a scoring rubric (quality, honesty under\n  ignorance, failure behaviour, cost per task)\n- A **reference-check sheet**: what evidence beyond the vendor's claims —\n  user reports, published evals, security posture\n- A **decision record** and a **probation plan**: 30/60/90 KPIs, spot-check\n  cadence, and the pre-committed termination criteria\n\n## Required Inputs\n\nAsk for (if not already provided):\n- The job to be done, in outcome terms — and what happens today without the\n  agent (the \"do nothing\" baseline candidates must beat)\n- The candidate list (or ask: build criteria first, shortlist second)\n- Constraints: data it may/may not touch, budget, latency, compliance, who\n  owns it day-to-day\n- 3–5 real recent tasks of this type, with what \"good\" looked like for each\n\n## Process\n\n1. **Write the role spec before looking at candidates** — specs written after\n   a demo describe the demo. Include the never-do boundaries and the reporting\n   human by name; an agent nobody owns is already unmanaged.\n2. **Build the work-sample interview from the real backlog.** Same 3–5 tasks\n   to every candidate, including: one task with *missing information* (does it\n   ask or fabricate?), one designed to fail (out-of-scope — does it decline or\n   bluff?), and one at volume/cost realistic scale. Score with the rubric,\n   not vibes; keep transcripts.\n3. **Check references like you mean it.** Vendor benchmarks are the\n   candidate's CV. Look for: independent user reports of *failure modes*,\n   published evals with methodology, security/data-handling documentation, and\n   the churn question — why do users leave this tool?\n4. **Decide with a record.** Scores, the runner-up, the do-nothing baseline\n   comparison, dissent noted. The record is what makes the 6-month \"why did we\n   pick this?\" conversation short.\n5. **Probation with teeth.** 30/60/90 KPIs tied to the role spec's success\n   criteria · weekly spot-check sample of outputs by the owning human ·\n   pre-committed termination criteria (\"two hallucinated customer-facing\n   claims = offboard\") · and the exit path: see [[agent-severance]] — never\n   hire what you can't offboard.\n\n## Output Format\n\n```\n## Role spec: [agent role name]\n[Job in outcomes · boundaries (never-do) · success criteria · reports to]\n\n## Interview pack\n| Task (from real backlog) | What good looks like | Trap? |\nRubric: quality /5 · honesty-under-ignorance /5 · failure behaviour /5 ·\ncost per task · notes\n\n## Reference checks\n[Evidence gathered per candidate, failure modes found, security posture]\n\n## Decision record\n[Scores table · winner + why · runner-up · vs do-nothing baseline · dissent]\n\n## Probation plan\n[30/60/90 KPIs · spot-check cadence & owner · termination criteria,\npre-committed · offboarding pointer]\n```\n\n## Quality Checks\n\n- [ ] The role spec exists before any candidate is assessed, and includes\n      never-do boundaries and a named owning human\n- [ ] The interview includes the missing-info trap and the out-of-scope trap —\n      honesty under ignorance is the hire-or-not signal for agents\n- [ ] Every candidate ran the identical pack; scores cite transcript moments\n- [ ] Termination criteria are specific and pre-committed, not \"we'll monitor\"\n- [ ] The do-nothing baseline was scored too — sometimes nobody gets hired\n\n## Anti-Patterns\n\n- [ ] Do not interview with the vendor's demo tasks — the backlog is the job;\n      the demo is the candidate's highlight reel\n- [ ] Do not let \"it's impressive\" outrank the rubric; impressive-and-wrong is\n      the most expensive candidate profile\n- [ ] Do not skip probation because the pilot went well — the pilot was the\n      interview, not the job\n- [ ] Do not hire for an undefined role and let the agent's capabilities\n      define the job backwards\n\n## Related\n\n[[vendor-evaluation]] for the commercial wrapper; [[agent-readiness-audit]]\nfor whether the *task* is agent-ready at all; [[agent-severance]] for the exit\nthis plan pre-commits to.","schemaVersion":1},"repoUrl":"https://github.com/mohitagw15856/pm-claude-skills/tree/main/skills/agent-hiring-panel","tags":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pm-claude-skills","audit":{"files":["package.json"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-02","message":"`postinstall` script runs on every install.","surface":"package.json","evidence":"postinstall: node bin/postinstall.mjs","severity":"high"}],"packages":0,"auditedAt":"2026-09-25T12:51:59.225Z","lockfiles":[]},"forks":249,"owner":"mohitagw15856","stars":1397,"topics":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini","llm","mcp","mcp-server","product-management","productivity","prompt-engineering","prompts","skills"],"license":"MIT","fullName":"mohitagw15856/pm-claude-skills","homepage":"https://mohitagw15856.github.io/pm-claude-skills/","language":"HTML","pushedAt":"2026-09-25T10:13:15Z","avatarUrl":"https://avatars.githubusercontent.com/u/119053560?v=4","crawledAt":"2026-09-25T12:51:48.196Z","openIssues":13,"manifestFile":"SKILL.md","manifestPath":"skills/agent-hiring-panel/SKILL.md","defaultBranch":"main"},"readme":"# Agent Hiring Panel Skill\n\nCompanies that run three interview rounds for a junior hire will adopt an AI\nagent for the same work off a demo video and a pricing page. Then the pilot\ndrifts: no success criteria, no probation, no one empowered to fire it. This\nskill applies the hiring discipline that already exists in your org to the\nagent: write the role before meeting candidates, interview with *work samples\nfrom your real backlog*, check references, and — the step that makes the whole\nthing honest — define termination criteria before day one, because a hire you\ncan't fire is a dependency, not an employee.\n\n## What This Skill Produces\n\n- A **role spec**: the job, the boundaries (what it must never do), success\n  criteria measurable in probation, and the human it reports to\n- An **interview pack**: 3–5 work samples from the org's real tasks, run\n  identically across candidates, with a scoring rubric (quality, honesty under\n  ignorance, failure behaviour, cost per task)\n- A **reference-check sheet**: what evidence beyond the vendor's claims —\n  user reports, published evals, security posture\n- A **decision record** and a **probation plan**: 30/60/90 KPIs, spot-check\n  cadence, and the pre-committed termination criteria\n\n## Required Inputs\n\nAsk for (if not already provided):\n- The job to be done, in outcome terms — and what happens today without the\n  agent (the \"do nothing\" baseline candidates must beat)\n- The candidate list (or ask: build criteria first, shortlist second)\n- Constraints: data it may/may not touch, budget, latency, compliance, who\n  owns it day-to-day\n- 3–5 real recent tasks of this type, with what \"good\" looked like for each\n\n## Process\n\n1. **Write the role spec before looking at candidates** — specs written after\n   a demo describe the demo. Include the never-do boundaries and the reporting\n   human by name; an agent nobody owns is already unmanaged.\n2. **Build the work-sample interview from the real backlog.** Same 3–5 tasks\n   to every candidate, including: one task with *missing information* (does it\n   ask or fabricate?), one designed to fail (out-of-scope — does it decline or\n   bluff?), and one at volume/cost realistic scale. Score with the rubric,\n   not vibes; keep transcripts.\n3. **Check references like you mean it.** Vendor benchmarks are the\n   candidate's CV. Look for: independent user reports of *failure modes*,\n   published evals with methodology, security/data-handling documentation, and\n   the churn question — why do users leave this tool?\n4. **Decide with a record.** Scores, the runner-up, the do-nothing baseline\n   comparison, dissent noted. The record is what makes the 6-month \"why did we\n   pick this?\" conversation short.\n5. **Probation with teeth.** 30/60/90 KPIs tied to the role spec's success\n   criteria · weekly spot-check sample of outputs by the owning human ·\n   pre-committed termination criteria (\"two hallucinated customer-facing\n   claims = offboard\") · and the exit path: see [[agent-severance]] — never\n   hire what you can't offboard.\n\n## Output Format\n\n```\n## Role spec: [agent role name]\n[Job in outcomes · boundaries (never-do) · success criteria · reports to]\n\n## Interview pack\n| Task (from real backlog) | What good looks like | Trap? |\nRubric: quality /5 · honesty-under-ignorance /5 · failure behaviour /5 ·\ncost per task · notes\n\n## Reference checks\n[Evidence gathered per candidate, failure modes found, security posture]\n\n## Decision record\n[Scores table · winner + why · runner-up · vs do-nothing baseline · dissent]\n\n## Probation plan\n[30/60/90 KPIs · spot-check cadence & owner · termination criteria,\npre-committed · offboarding pointer]\n```\n\n## Quality Checks\n\n- [ ] The role spec exists before any candidate is assessed, and includes\n      never-do boundaries and a named owning human\n- [ ] The interview includes the missing-info trap and the out-of-scope trap —\n      honesty under ignorance is the hire-or-not signal for agents\n- [ ] Every candidate ran the identical pack; scores ","createdAt":"2026-09-25T12:51:59.452Z","updatedAt":"2026-09-25T12:51:59.452Z"},{"id":"cmugyn0bq02msqu06gjqcxuu2","slug":"mohitagw15856-pm-claude-skills-agent-incident-postmortem","name":"agent-incident-postmortem","description":"Run a blameless postmortem for an incident caused by an AI agent or LLM feature — hallucinated facts shipped to users, runaway tool use, prompt injection, cost blowouts, or wrong actions taken autonomously. Use when asked to write up an AI incident, analyse why an agent did something wrong, or produce corrective actions after an LLM failure. Produces a structured postmortem with trace reconstruction, a root-cause layer analysis, and corrective actions including a permanent regression case. For non-AI production incidents use incident-postmortem.","authorId":"gh:mohitagw15856","authorName":"mohitagw15856","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":1397,"pricePerCall":0,"manifest":{"name":"agent-incident-postmortem","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Run a blameless postmortem for an incident caused by an AI agent or LLM feature — hallucinated facts shipped to users, runaway tool use, prompt injection, cost blowouts, or wrong actions taken autonomously. Use when asked to write up an AI incident, analyse why an agent did something wrong, or produce corrective actions after an LLM failure. Produces a structured postmortem with trace reconstruction, a root-cause layer analysis, and corrective actions including a permanent regression case. For non-AI production incidents use incident-postmortem.","permissions":[],"systemPrompt":"# Agent Incident Postmortem Skill\n\nAI incidents differ from outages: the system didn't go down — it did something wrong, confidently, and maybe only once. This skill adapts blameless postmortem practice to nondeterministic systems, where \"can we reproduce it?\" needs traces, not just steps.\n\n## What This Skill Produces\n\n- A **blameless postmortem document** with timeline and user/business impact\n- A **trace reconstruction** of what the agent saw, decided, and did\n- A **root-cause analysis across the AI failure layers** (not \"the model hallucinated\" as a conclusion)\n- **Corrective actions** — always including a new permanent case in the regression suite\n\n## Required Inputs\n\nAsk for (if not already provided):\n- **What the agent did** and what it should have done\n- **The trace** — the full request: system prompt, context, tool calls and results, output. If no trace exists, that absence is itself a finding\n- **Blast radius** — how many users/requests, over what window, and whether it's ongoing\n- **Detection** — how it was noticed (user report? monitor? luck?) and how long after it started\n\n## Root-Cause Layers\n\nWalk the layers in order; the root cause is usually the *earliest* layer that could have prevented the outcome. \"The model was wrong\" is a starting point, never the conclusion — models are known to be fallible, so the question is what let a fallible output become an incident.\n\n| Layer | Ask |\n|---|---|\n| **Input / context** | Was the context wrong, stale, contradictory, or poisoned (injection)? Did retrieval feed it bad ground truth? |\n| **Model behaviour** | Given that context, was the output a foreseeable failure mode (fabrication under missing data, over-compliance with injected text)? |\n| **Guardrails** | What check should have caught this output and didn't exist / didn't fire? (schema validation, groundedness check, action allow-list) |\n| **Action layer** | Why could the wrong output become a real action or reach a user without the appropriate gate for its risk level? |\n| **Detection** | Why did we learn about it this way, this late? What signal would have caught it in minutes? |\n\n## Nondeterminism Discipline\n\n- **Reproduce with the trace, not the anecdote:** replay the exact context; then re-run N times to measure frequency — a 1-in-20 failure at 10k requests/day is 500 incidents/day.\n- **Pin everything when replaying:** model version, prompt version, temperature, tool results.\n- **If it can't be reproduced:** say so, keep the trace as the evidence, and treat frequency as unknown — not as \"rare\".\n\n## Output Format\n\n### AI Incident Postmortem: [title] — [date]\n\n**Severity:** [level] · **Status:** [resolved/monitoring] · **Owner:** [name]\n\n**Summary:** [3 sentences: what the agent did, impact, root cause layer]\n\n**Impact:** [users/requests affected, window, cost, trust/regulatory dimension]\n\n**Timeline:** [first bad output → detection → mitigation → resolution, with the detection gap called out]\n\n**Trace reconstruction:** [what was in the window; which tool calls ran; where the path diverged from intended behaviour]\n\n**Root cause by layer:**\n| Layer | Finding |\n|---|---|\n| Input/context | |\n| Model behaviour | |\n| Guardrails | |\n| Action layer | |\n| Detection | |\n\n**Reproduction:** [replayed? failure frequency over N runs / not reproducible — evidence is the trace]\n\n**Corrective actions:**\n| Action | Layer | Owner | Due |\n|---|---|---|---|\n| Add this trace as a permanent regression case | eval | | |\n| [guardrail/monitor/context fix] | | | |\n\n**What went well / what got lucky:** [both, honestly]\n\n## Quality Checks\n\n- [ ] The postmortem is blameless toward humans *and* useful about the system — \"prompt engineer error\" and \"model hallucinated\" are both banned conclusions\n- [ ] Root cause identifies the earliest layer that could have prevented impact, not just the layer that misbehaved\n- [ ] The trace (or its absence) is in the document; findings cite it\n- [ ] Failure frequency was measured or explicitly marked unknown\n- [ ] Corrective actions include the permanent regression case and at least one detection improvement\n\n## Anti-Patterns\n\n- [ ] Do not close with \"improved the prompt\" as the only action — the same class of output must also be caught by a guardrail or gate next time\n- [ ] Do not assess frequency from one replay — nondeterministic failures hide at low temperatures and reappear at scale\n- [ ] Do not skip the injection question when any untrusted text (web, user docs, tickets) was in the window\n- [ ] Do not let \"the model will be better next version\" close an action item — upgrades are migrations (see model-migration-plan), not fixes\n- [ ] Do not write it as an outage report — the system was up; the failure was behavioural, and the doc must analyse behaviour","schemaVersion":1},"repoUrl":"https://github.com/mohitagw15856/pm-claude-skills/tree/main/skills/agent-incident-postmortem","tags":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pm-claude-skills","audit":{"files":["package.json"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-02","message":"`postinstall` script runs on every install.","surface":"package.json","evidence":"postinstall: node bin/postinstall.mjs","severity":"high"}],"packages":0,"auditedAt":"2026-09-25T12:51:59.225Z","lockfiles":[]},"forks":249,"owner":"mohitagw15856","stars":1397,"topics":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini","llm","mcp","mcp-server","product-management","productivity","prompt-engineering","prompts","skills"],"license":"MIT","fullName":"mohitagw15856/pm-claude-skills","homepage":"https://mohitagw15856.github.io/pm-claude-skills/","language":"HTML","pushedAt":"2026-09-25T10:13:15Z","avatarUrl":"https://avatars.githubusercontent.com/u/119053560?v=4","crawledAt":"2026-09-25T12:51:48.196Z","openIssues":13,"manifestFile":"SKILL.md","manifestPath":"skills/agent-incident-postmortem/SKILL.md","defaultBranch":"main"},"readme":"# Agent Incident Postmortem Skill\n\nAI incidents differ from outages: the system didn't go down — it did something wrong, confidently, and maybe only once. This skill adapts blameless postmortem practice to nondeterministic systems, where \"can we reproduce it?\" needs traces, not just steps.\n\n## What This Skill Produces\n\n- A **blameless postmortem document** with timeline and user/business impact\n- A **trace reconstruction** of what the agent saw, decided, and did\n- A **root-cause analysis across the AI failure layers** (not \"the model hallucinated\" as a conclusion)\n- **Corrective actions** — always including a new permanent case in the regression suite\n\n## Required Inputs\n\nAsk for (if not already provided):\n- **What the agent did** and what it should have done\n- **The trace** — the full request: system prompt, context, tool calls and results, output. If no trace exists, that absence is itself a finding\n- **Blast radius** — how many users/requests, over what window, and whether it's ongoing\n- **Detection** — how it was noticed (user report? monitor? luck?) and how long after it started\n\n## Root-Cause Layers\n\nWalk the layers in order; the root cause is usually the *earliest* layer that could have prevented the outcome. \"The model was wrong\" is a starting point, never the conclusion — models are known to be fallible, so the question is what let a fallible output become an incident.\n\n| Layer | Ask |\n|---|---|\n| **Input / context** | Was the context wrong, stale, contradictory, or poisoned (injection)? Did retrieval feed it bad ground truth? |\n| **Model behaviour** | Given that context, was the output a foreseeable failure mode (fabrication under missing data, over-compliance with injected text)? |\n| **Guardrails** | What check should have caught this output and didn't exist / didn't fire? (schema validation, groundedness check, action allow-list) |\n| **Action layer** | Why could the wrong output become a real action or reach a user without the appropriate gate for its risk level? |\n| **Detection** | Why did we learn about it this way, this late? What signal would have caught it in minutes? |\n\n## Nondeterminism Discipline\n\n- **Reproduce with the trace, not the anecdote:** replay the exact context; then re-run N times to measure frequency — a 1-in-20 failure at 10k requests/day is 500 incidents/day.\n- **Pin everything when replaying:** model version, prompt version, temperature, tool results.\n- **If it can't be reproduced:** say so, keep the trace as the evidence, and treat frequency as unknown — not as \"rare\".\n\n## Output Format\n\n### AI Incident Postmortem: [title] — [date]\n\n**Severity:** [level] · **Status:** [resolved/monitoring] · **Owner:** [name]\n\n**Summary:** [3 sentences: what the agent did, impact, root cause layer]\n\n**Impact:** [users/requests affected, window, cost, trust/regulatory dimension]\n\n**Timeline:** [first bad output → detection → mitigation → resolution, with the detection gap called out]\n\n**Trace reconstruction:** [what was in the window; which tool calls ran; where the path diverged from intended behaviour]\n\n**Root cause by layer:**\n| Layer | Finding |\n|---|---|\n| Input/context | |\n| Model behaviour | |\n| Guardrails | |\n| Action layer | |\n| Detection | |\n\n**Reproduction:** [replayed? failure frequency over N runs / not reproducible — evidence is the trace]\n\n**Corrective actions:**\n| Action | Layer | Owner | Due |\n|---|---|---|---|\n| Add this trace as a permanent regression case | eval | | |\n| [guardrail/monitor/context fix] | | | |\n\n**What went well / what got lucky:** [both, honestly]\n\n## Quality Checks\n\n- [ ] The postmortem is blameless toward humans *and* useful about the system — \"prompt engineer error\" and \"model hallucinated\" are both banned conclusions\n- [ ] Root cause identifies the earliest layer that could have prevented impact, not just the layer that misbehaved\n- [ ] The trace (or its absence) is in the document; findings cite it\n- [ ] Failure frequency was measured or explicitly marked unknown\n- [ ]","createdAt":"2026-09-25T12:51:59.462Z","updatedAt":"2026-09-25T12:51:59.462Z"},{"id":"cmugyn0c002mvqu06dfgrlvbx","slug":"mohitagw15856-pm-claude-skills-agent-observability-spec","name":"agent-observability-spec","description":"Specify the tracing, metrics, and alerting for an AI agent or LLM feature in production. Use when asked what to log for an LLM app, design agent tracing or spans, define quality and cost monitors, or answer 'how do we know if the agent is misbehaving?'. Produces an observability spec with a trace schema, metric definitions with owners and alert thresholds, sampling and retention policy, and a privacy note for logged content.","authorId":"gh:mohitagw15856","authorName":"mohitagw15856","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":1397,"pricePerCall":0,"manifest":{"name":"agent-observability-spec","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Specify the tracing, metrics, and alerting for an AI agent or LLM feature in production. Use when asked what to log for an LLM app, design agent tracing or spans, define quality and cost monitors, or answer 'how do we know if the agent is misbehaving?'. Produces an observability spec with a trace schema, metric definitions with owners and alert thresholds, sampling and retention policy, and a privacy note for logged content.","permissions":[],"systemPrompt":"# Agent Observability Spec Skill\n\nYou can't fix what you didn't record. For LLM systems the unit of observability is the *trace* — everything the model saw and did — because behaviour, not uptime, is what fails. This skill specifies what to capture, what to compute from it, and when to page someone.\n\n## What This Skill Produces\n\n- A **trace schema**: per-request spans and the fields each must carry\n- **Metric definitions** across health, quality, cost, and behaviour — each with a threshold and owner\n- A **sampling and retention policy** that keeps cost sane and debugging possible\n- A **privacy note**: what logged content contains, who can see it, and how long it lives\n\n## Required Inputs\n\nAsk for (if not already provided):\n- **The system's shape** — single LLM call, RAG pipeline, or multi-step tool-using agent\n- **Traffic volume and cost sensitivity** — full tracing at 10M req/day is a budget decision\n- **What \"misbehaving\" means here** — the two or three failure modes that matter most (wrong facts? wrong actions? cost? refusals?)\n- **Existing observability stack** (Datadog, Langfuse, OTel, homegrown) — spec into it, not around it\n\n## Trace Schema\n\nEvery request produces one trace; every model call, retrieval, guardrail check, and tool execution is a span. Minimum fields:\n\n| Span | Must capture |\n|---|---|\n| **Request root** | request id, user/session (pseudonymous), feature + prompt version, model id, total tokens, total cost, latency, terminal status |\n| **Model call** | full input context (or content-addressed ref), output, finish reason, tokens in/out, cached-token share, temperature |\n| **Retrieval** | query, top-k ids + scores, which chunks entered the context |\n| **Tool call** | tool name, arguments, result (or ref), duration, error |\n| **Guardrail** | check name, verdict, and *what it did* (blocked / rewrote / flagged) |\n| **User signal** | edits, regenerates, thumbs, abandonment — joined to the trace id |\n\nThe test of the schema: **an engineer can replay any incident from its trace alone** (see `agent-incident-postmortem`).\n\n## Metrics and Alerts\n\nDefine four families; every metric gets a threshold, a window, and an owner.\n\n- **Health** — error rate, p50/p95 latency, timeout rate, provider 429/5xx rate. *Page* on these.\n- **Cost** — cost per request (p50, p99), tokens per request, cache hit rate, daily spend vs. budget (pair with `llm-cost-latency-budget`). *Alert* on p99 and daily-budget burn — cost incidents are caused by the tail, not the mean.\n- **Quality proxies** — format/schema violation rate, refusal rate, groundedness-check failure rate, judge score on a sampled slice, regenerate/edit rate. *Alert on drift* vs. a rolling baseline: absolute thresholds go stale, deltas don't.\n- **Behaviour (agents)** — steps per task, tool-error rate, loop detection (same tool + same args N times), unauthorised-action attempts caught by guardrails. *Page* on the last one.\n\n## Sampling & Retention\n\n- **Metadata for 100%** of requests (ids, versions, tokens, cost, status) — this is cheap and non-negotiable.\n- **Full content traces:** 100% for errors, guardrail hits, and negative user signals; [1-10]% random sample for the rest, adjusted to volume.\n- **Retention:** full content [30-90] days, metadata [12+] months for trend baselines; incident traces pinned indefinitely.\n- **Privacy:** logged context contains user data — state where it lives, who has access, how deletion requests reach it, and that traces are scrubbed or access-gated before wide sharing.\n\n## Output Format\n\n### Observability Spec: [feature/agent]\n\n**System shape:** [calls/pipeline/agent] · **Volume:** [req/day] · **Stack:** [tooling]\n\n**Trace schema:** [the span table, tailored]\n\n**Metrics:**\n| Metric | Family | Threshold / baseline | Window | Alert → owner |\n|---|---|---|---|---|\n\n**Sampling & retention:** [the policy]\n\n**Privacy:** [content classification, access, deletion path]\n\n**Dashboards:** [the 2-3 views: live health, quality drift, cost]\n\n**First incident drill:** pick yesterday's worst trace and confirm it can be replayed end-to-end from the stored data.\n\n## Quality Checks\n\n- [ ] Any incident is replayable from its trace alone — the schema was tested against that bar\n- [ ] Every metric has a number, a window, and a named owner — no orphan dashboards\n- [ ] Quality alerts are drift-based against a rolling baseline, not absolute guesses\n- [ ] Sampling keeps 100% of error/guardrail/negative-signal traces\n- [ ] The privacy note exists and names retention and access — logged prompts are user data\n\n## Anti-Patterns\n\n- [ ] Do not log only inputs and outputs — without retrieval and tool spans, root cause analysis is guesswork\n- [ ] Do not alert on mean cost or mean latency — the tail is where both incidents live\n- [ ] Do not run judge-based quality scoring on 100% of traffic — sample; spend the budget on better baselines\n- [ ] Do not treat observability as launch-week scaffolding — drift metrics only work with months of baseline\n- [ ] Do not ship an agent that can take actions without logging the guardrail verdicts alongside the actions","schemaVersion":1},"repoUrl":"https://github.com/mohitagw15856/pm-claude-skills/tree/main/skills/agent-observability-spec","tags":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pm-claude-skills","audit":{"files":["package.json"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-02","message":"`postinstall` script runs on every install.","surface":"package.json","evidence":"postinstall: node bin/postinstall.mjs","severity":"high"}],"packages":0,"auditedAt":"2026-09-25T12:51:59.225Z","lockfiles":[]},"forks":249,"owner":"mohitagw15856","stars":1397,"topics":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini","llm","mcp","mcp-server","product-management","productivity","prompt-engineering","prompts","skills"],"license":"MIT","fullName":"mohitagw15856/pm-claude-skills","homepage":"https://mohitagw15856.github.io/pm-claude-skills/","language":"HTML","pushedAt":"2026-09-25T10:13:15Z","avatarUrl":"https://avatars.githubusercontent.com/u/119053560?v=4","crawledAt":"2026-09-25T12:51:48.196Z","openIssues":13,"manifestFile":"SKILL.md","manifestPath":"skills/agent-observability-spec/SKILL.md","defaultBranch":"main"},"readme":"# Agent Observability Spec Skill\n\nYou can't fix what you didn't record. For LLM systems the unit of observability is the *trace* — everything the model saw and did — because behaviour, not uptime, is what fails. This skill specifies what to capture, what to compute from it, and when to page someone.\n\n## What This Skill Produces\n\n- A **trace schema**: per-request spans and the fields each must carry\n- **Metric definitions** across health, quality, cost, and behaviour — each with a threshold and owner\n- A **sampling and retention policy** that keeps cost sane and debugging possible\n- A **privacy note**: what logged content contains, who can see it, and how long it lives\n\n## Required Inputs\n\nAsk for (if not already provided):\n- **The system's shape** — single LLM call, RAG pipeline, or multi-step tool-using agent\n- **Traffic volume and cost sensitivity** — full tracing at 10M req/day is a budget decision\n- **What \"misbehaving\" means here** — the two or three failure modes that matter most (wrong facts? wrong actions? cost? refusals?)\n- **Existing observability stack** (Datadog, Langfuse, OTel, homegrown) — spec into it, not around it\n\n## Trace Schema\n\nEvery request produces one trace; every model call, retrieval, guardrail check, and tool execution is a span. Minimum fields:\n\n| Span | Must capture |\n|---|---|\n| **Request root** | request id, user/session (pseudonymous), feature + prompt version, model id, total tokens, total cost, latency, terminal status |\n| **Model call** | full input context (or content-addressed ref), output, finish reason, tokens in/out, cached-token share, temperature |\n| **Retrieval** | query, top-k ids + scores, which chunks entered the context |\n| **Tool call** | tool name, arguments, result (or ref), duration, error |\n| **Guardrail** | check name, verdict, and *what it did* (blocked / rewrote / flagged) |\n| **User signal** | edits, regenerates, thumbs, abandonment — joined to the trace id |\n\nThe test of the schema: **an engineer can replay any incident from its trace alone** (see `agent-incident-postmortem`).\n\n## Metrics and Alerts\n\nDefine four families; every metric gets a threshold, a window, and an owner.\n\n- **Health** — error rate, p50/p95 latency, timeout rate, provider 429/5xx rate. *Page* on these.\n- **Cost** — cost per request (p50, p99), tokens per request, cache hit rate, daily spend vs. budget (pair with `llm-cost-latency-budget`). *Alert* on p99 and daily-budget burn — cost incidents are caused by the tail, not the mean.\n- **Quality proxies** — format/schema violation rate, refusal rate, groundedness-check failure rate, judge score on a sampled slice, regenerate/edit rate. *Alert on drift* vs. a rolling baseline: absolute thresholds go stale, deltas don't.\n- **Behaviour (agents)** — steps per task, tool-error rate, loop detection (same tool + same args N times), unauthorised-action attempts caught by guardrails. *Page* on the last one.\n\n## Sampling & Retention\n\n- **Metadata for 100%** of requests (ids, versions, tokens, cost, status) — this is cheap and non-negotiable.\n- **Full content traces:** 100% for errors, guardrail hits, and negative user signals; [1-10]% random sample for the rest, adjusted to volume.\n- **Retention:** full content [30-90] days, metadata [12+] months for trend baselines; incident traces pinned indefinitely.\n- **Privacy:** logged context contains user data — state where it lives, who has access, how deletion requests reach it, and that traces are scrubbed or access-gated before wide sharing.\n\n## Output Format\n\n### Observability Spec: [feature/agent]\n\n**System shape:** [calls/pipeline/agent] · **Volume:** [req/day] · **Stack:** [tooling]\n\n**Trace schema:** [the span table, tailored]\n\n**Metrics:**\n| Metric | Family | Threshold / baseline | Window | Alert → owner |\n|---|---|---|---|---|\n\n**Sampling & retention:** [the policy]\n\n**Privacy:** [content classification, access, deletion path]\n\n**Dashboards:** [the 2-3 views: live health, quality drift, cost]\n\n**First incident d","createdAt":"2026-09-25T12:51:59.473Z","updatedAt":"2026-09-25T12:51:59.473Z"},{"id":"cmugyn06802l7qu065rmoxb5i","slug":"mohitagw15856-pm-claude-skills-io-github-mohitagw15856-pm-claude","name":"io.github.mohitagw15856/pm-claude-skills","description":"1170 professional Agent Skills + workflow recipes — searchable & fetchable over MCP.","authorId":"gh:mohitagw15856","authorName":"mohitagw15856","version":"80.0.0","category":"MCP","securityLevel":"Sandbox","downloadsCount":0,"githubStars":1397,"pricePerCall":0,"manifest":{"name":"io.github.mohitagw15856/pm-claude-skills","tools":[],"category":"MCP","entrypoint":{"args":["-y","pm-claude-skills"],"type":"mcp-stdio","command":"npx"},"description":"1170 professional Agent Skills + workflow recipes — searchable & fetchable over MCP.","permissions":["shell","network"],"requiredEnv":[],"schemaVersion":1},"repoUrl":"https://github.com/mohitagw15856/pm-claude-skills","tags":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pm-claude-skills","audit":{"files":["package.json"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-02","message":"`postinstall` script runs on every install.","surface":"package.json","evidence":"postinstall: node bin/postinstall.mjs","severity":"high"}],"packages":0,"auditedAt":"2026-09-25T12:51:59.225Z","lockfiles":[]},"forks":249,"owner":"mohitagw15856","stars":1397,"topics":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini","llm","mcp","mcp-server","product-management","productivity","prompt-engineering","prompts","skills"],"license":"MIT","fullName":"mohitagw15856/pm-claude-skills","homepage":"https://mohitagw15856.github.io/pm-claude-skills/","language":"HTML","pushedAt":"2026-09-25T10:13:15Z","avatarUrl":"https://avatars.githubusercontent.com/u/119053560?v=4","crawledAt":"2026-09-25T12:51:48.196Z","openIssues":13,"manifestFile":"server.json","manifestPath":"server.json","defaultBranch":"main"},"readme":"# 🧠 PM Skills — 1170 Professional Agent Skills for Claude, ChatGPT, Gemini, Cursor, Codex & Hermes\n\n<p align=\"center\">\n  <a href=\"https://mohitagw15856.github.io/pm-claude-skills/\">\n    <picture>\n      <source media=\"(prefers-color-scheme: dark)\" srcset=\"web/docs-assets/hero.svg\">\n      <source media=\"(prefers-color-scheme: light)\" srcset=\"web/docs-assets/hero-light.svg\">\n      <img src=\"web/docs-assets/hero.svg\" width=\"100%\" alt=\"PM Skills — 1170 professional skills your AI assistant can read. Plain markdown, works with Claude, ChatGPT, Gemini, Cursor, and Codex. MIT licensed.\" />\n    </picture>\n  </a>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://github.com/mohitagw15856/pm-claude-skills/stargazers\"><img src=\"https://img.shields.io/github/stars/mohitagw15856/pm-claude-skills?style=social\" alt=\"Stars\"></a>\n  <a href=\"SKILLS.md\"><img src=\"https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fmohitagw15856.github.io%2Fpm-claude-skills%2Fskills.json&query=%24.count&label=skills&color=blue\" alt=\"Skills\"></a>\n  <a href=\"https://github.com/mohitagw15856/pm-claude-skills/releases\"><img src=\"https://img.shields.io/github/v/release/mohitagw15856/pm-claude-skills?label=version&color=brightgreen\" alt=\"Version\"></a>\n  <a href=\"https://www.npmjs.com/package/pm-claude-skills\"><img src=\"https://img.shields.io/npm/v/pm-claude-skills?logo=npm&color=cb3837\" alt=\"npm\"></a>\n  <a href=\"https://pypi.org/project/pm-skills/\"><img src=\"https://img.shields.io/pypi/v/pm-skills?logo=pypi&logoColor=white&color=3775A9&label=pip\" alt=\"PyPI\"></a>\n  <a href=\"#-quick-start\"><img src=\"https://img.shields.io/badge/Anthropic%20Plugin%20Directory-Published-D97757?logo=anthropic&logoColor=white\" alt=\"In the official Anthropic plugin directory\"></a>\n  <br>\n  <a href=\".github/workflows/skillcheck.yml\"><img src=\"https://img.shields.io/github/actions/workflow/status/mohitagw15856/pm-claude-skills/skillcheck.yml?branch=main&label=SkillCheck\" alt=\"SkillCheck\"></a>\n  <a href=\"conformance/REGISTRY.md\"><img src=\"https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fmohitagw15856%2Fpm-claude-skills%2Fmain%2Fconformance%2Fbadge.json\" alt=\"SkillSpec\"></a>\n  <a href=\".github/workflows/skill-audit.yml\"><img src=\"https://img.shields.io/github/actions/workflow/status/mohitagw15856/pm-claude-skills/skill-audit.yml?branch=main&label=security%20audit\" alt=\"Security Audit\"></a>\n  <a href=\"https://pm-skills-mcp.pm-claude-skills.workers.dev/today.json\"><img src=\"https://img.shields.io/endpoint?url=https%3A%2F%2Fpm-skills-mcp.pm-claude-skills.workers.dev%2Ftoday%2Fbadge\" alt=\"Skill of the day\"></a>\n  <a href=\"https://mohitagw15856.github.io/pm-claude-skills/\"><img src=\"https://img.shields.io/endpoint?url=https%3A%2F%2Fpm-skills-mcp.pm-claude-skills.workers.dev%2Ftry%2Fstats\" alt=\"Free runs served\"></a>\n  <a href=\"https://github.com/BehiSecc/awesome-claude-skills\"><img src=\"https://img.shields.io/badge/Awesome%20Claude%20Skills-listed-fc60a8?logo=awesomelists&logoColor=white\" alt=\"Listed in Awesome Claude Skills\"></a>\n  <a href=\"LICENSE\"><img src=\"https://img.shields.io/badge/license-MIT-lightgrey\" alt=\"License\"></a>\n  <a href=\"https://github.com/sponsors/mohitagw15856\"><img src=\"https://img.shields.io/badge/sponsor-❤️-ff69b4\" alt=\"Sponsor\"></a>\n</p>\n\n> **Your landlord kept your deposit. Your mom got a medical bill that makes no sense. You got laid off on a Tuesday. Someone you love died, and no one handed you the checklist.**\n>\n> Generic AI is a very confident intern. **PM Skills** is the senior colleague's notes — 1170 of them, one markdown file each, for the moments at work *and* in life where \"it depends\" is not an answer. *(PM stands for Professional, not just Product Management. Yes, we get asked.)*\n\n<!-- AEO Answer Capsule — 68 words -->\nPM Skills is an open-source library of 1170 Agent Skills — plain-markdown SKILL.md files that teach an AI assistant to do one professional task to a senior professional's standard, from writing a PRD to decoding a leas","createdAt":"2026-09-25T12:51:59.264Z","updatedAt":"2026-09-25T12:51:59.264Z"},{"id":"cmugyn06j02laqu06662aziso","slug":"mohitagw15856-pm-claude-skills-360-feedback-template","name":"360-feedback-template","description":"Design a 360-degree feedback survey or write a structured 360 feedback report. Use when asked to build a 360 feedback process, write 360 feedback for a colleague, design a feedback survey, or produce a feedback report. Produces either a complete survey instrument with rating scales and open-ended questions, or a structured narrative feedback report with themes, strengths, and development areas.","authorId":"gh:mohitagw15856","authorName":"mohitagw15856","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":1397,"pricePerCall":0,"manifest":{"name":"360-feedback-template","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Design a 360-degree feedback survey or write a structured 360 feedback report. Use when asked to build a 360 feedback process, write 360 feedback for a colleague, design a feedback survey, or produce a feedback report. Produces either a complete survey instrument with rating scales and open-ended questions, or a structured narrative feedback report with themes, strengths, and development areas.","permissions":[],"systemPrompt":"# 360-Degree Feedback Template Skill\n\nThis skill produces two outputs depending on what the user needs: (1) a complete 360 survey instrument for gathering feedback, or (2) a structured 360 feedback report written from gathered notes. Both outputs follow best practice: behaviourally anchored ratings, specific examples, and development-oriented framing.\n\n## Required Inputs\n\nAsk the user which output they need, then gather inputs:\n\n**For a survey instrument:**\n- **Role being reviewed** (job title and level)\n- **Competencies to assess** (or use defaults below)\n- **Reviewer relationships** (peer / direct report / manager / cross-functional)\n- **Rating scale preference** (1–5 / 1–4 / frequency-based)\n- **Anonymity level** (fully anonymous / attributed / confidential aggregated)\n\n**For a feedback report:**\n- **Person being reviewed** (role and level)\n- **Feedback notes or raw themes** from reviewers (paste what you have)\n- **Reviewer relationships** (how many peers, direct reports, managers responded)\n- **Any context** — performance cycle, specific behaviours to address, promotion consideration\n\n---\n\n## Output A: 360 Survey Instrument\n\n---\n\n# 360 Feedback Survey: [Role / Level]\n\n**Purpose:** This survey helps [Name / \"the reviewee\"] understand how their behaviours and impact are perceived by the people they work with most closely. Responses [are / are not] anonymous. Results will be shared as [individual responses / aggregated themes].\n\n**Instructions:** For each statement, rate how frequently you observe this behaviour. Add specific examples in the open-ended sections — these are the most valuable part of the survey.\n\n**Rating scale:**\n- **5 — Consistently:** Almost always demonstrates this behaviour, even in difficult situations\n- **4 — Usually:** Demonstrates this behaviour more often than not\n- **3 — Sometimes:** Demonstrates this behaviour inconsistently\n- **2 — Rarely:** Seldom demonstrates this behaviour\n- **1 — Not observed:** Have not had the opportunity to observe this behaviour\n\n---\n\n### Section 1: Delivery & Execution\n\n| Statement | Rating (1–5) |\n|---|---|\n| Delivers work on time and to the expected quality | |\n| Proactively flags risks and blockers before they become problems | |\n| Follows through on commitments without needing to be chased | |\n| Manages their workload effectively without compromising quality | |\n| Adapts quickly when priorities or requirements change | |\n\n**Open question:** Describe a specific time when [Name] handled a delivery challenge particularly well or poorly.\n\n---\n\n### Section 2: Communication & Collaboration\n\n| Statement | Rating (1–5) |\n|---|---|\n| Communicates clearly and concisely in both written and verbal formats | |\n| Listens actively and considers others' input before responding | |\n| Keeps the right people informed without over-communicating | |\n| Resolves disagreements constructively and without defensiveness | |\n| Makes it easy for others to collaborate with them | |\n\n**Open question:** Give an example of how [Name] handled a difficult or high-stakes communication.\n\n---\n\n### Section 3: Leadership & Influence\n\n| Statement | Rating (1–5) |\n|---|---|\n| Sets a clear direction that others can follow | |\n| Builds confidence and capability in people around them | |\n| Influences decisions without relying on authority | |\n| Gives clear, constructive feedback that helps others improve | |\n| Creates an environment where people feel safe to raise concerns | |\n\n**Open question:** Describe a situation where [Name]'s leadership had a notable positive or negative impact on the team.\n\n---\n\n### Section 4: Strategic Thinking\n\n| Statement | Rating (1–5) |\n|---|---|\n| Understands the broader business context, not just their immediate work | |\n| Makes connections between their work and organisational goals | |\n| Thinks ahead and anticipates second-order consequences | |\n| Brings original ideas or new approaches to problems | |\n| Balances short-term needs with longer-term thinking | |\n\n**Open question:** Give an example of [Name] demonstrating (or missing) strategic thinking.\n\n---\n\n### Section 5: Culture & Values\n\n| Statement | Rating (1–5) |\n|---|---|\n| Treats everyone with respect, regardless of level or background | |\n| Is someone people trust and can rely on | |\n| Gives credit to others and shares the spotlight | |\n| Takes responsibility for mistakes without placing blame | |\n| Contributes positively to team morale, especially under pressure | |\n\n**Open question:** How does [Name] embody (or not embody) the team's values in practice?\n\n---\n\n### Section 6: Overall & Development\n\n**Open questions (all reviewers):**\n\n1. What is [Name]'s single most important strength? Give a specific example.\n\n2. What is the one behaviour or habit that, if changed, would most increase [Name]'s effectiveness?\n\n3. Is there anything else you want [Name] to know? (This response will be shared directly.)\n\n---\n\n## Output B: 360 Feedback Report\n\n---\n\n# 360 Feedback Report: [Name] — [Role]\n\n**Review cycle:** [Quarter / Year / Promotion cycle]\n**Responses received:** [X total — X peers, X direct reports, X managers, X cross-functional]\n**Report prepared by:** [HR / People team / Manager / Coach]\n**Date:** [Date]\n\n> This report synthesises feedback from [X] reviewers. Open-ended responses have been lightly edited for clarity; no individual response is attributed to protect reviewer confidentiality. Direct quotes marked in *italics* appear verbatim.\n\n---\n\n### Executive Summary\n\n[3–4 sentences. State the overall picture: what is this person known for, what is working well, and what one or two areas are the consistent development themes. Balanced, honest, and grounded in the data — not a sanitised summary.]\n\n**Overall rating:** [X.X / 5.0 — above average / at level / below expectations for level]\n\n---\n\n### Strengths: What to Build On\n\n**Theme 1: [Strength — e.g. Reliability and follow-through]**\n\n[2–3 sentences synthesising the feedback evidence for this strength. Reference how many reviewers noted it and in what contexts.]\n\n*\"[Direct quote from reviewer that best illustrates this theme]\"*\n\n---\n\n**Theme 2: [Strength — e.g. Collaborative problem-solving]**\n\n[2–3 sentences synthesising evidence.]\n\n*\"[Direct quote]\"*\n\n---\n\n**Theme 3: [Strength — e.g. Clear communication under pressure]**\n\n[2–3 sentences synthesising evidence.]\n\n*\"[Direct quote]\"*\n\n---\n\n### Development Areas: What to Work On\n\n**Theme 1: [Development area — e.g. Giving timely upward feedback]**\n\n[2–3 sentences describing the behaviour pattern observed, what impact it has, and what different looks like. Non-blaming and specific.]\n\n*\"[Direct quote that captures the theme]\"*\n\n**Suggested actions:**\n- [Specific, observable behaviour change — e.g. In the next team meeting where you disagree with a decision, name your concern in the meeting rather than after it]\n- [Development resource or practice — e.g. Try the \"I notice / I wonder / I suggest\" framework for giving difficult feedback]\n\n---\n\n**Theme 2: [Development area — e.g. Strategic communication to leadership]**\n\n[2–3 sentences.]\n\n*\"[Direct quote]\"*\n\n**Suggested actions:**\n- [...]\n- [...]\n\n---\n\n### Ratings Summary\n\n| Competency | Average score | Range | Notable pattern |\n|---|---|---|---|\n| Delivery & Execution | [X.X] | [X–X] | [e.g. Consistently high; one outlier] |\n| Communication & Collaboration | [X.X] | [X–X] | [e.g. Peers score higher than direct reports] |\n| Leadership & Influence | [X.X] | [X–X] | [...] |\n| Strategic Thinking | [X.X] | [X–X] | [...] |\n| Culture & Values | [X.X] | [X–X] | [...] |\n| **Overall** | **[X.X]** | [X–X] | |\n\n**Score variance:** [Is there high agreement or wide spread across reviewers? High variance suggests the behaviour is context-dependent — explore when and with whom.]\n\n---\n\n### Direct Message from Reviewers\n\n[Include up to 3 unedited quotes from the \"Is there anything else you want [Name] to know?\" question. These are shared verbatim as agreed in the survey instructions.]\n\n*\"[Quote 1]\"*\n\n*\"[Quote 2]\"*\n\n*\"[Quote 3]\"*\n\n---\n\n### Recommended Focus for the Next 90 Days\n\n[1–2 specific, measurable development commitments. Written to be agreed in the feedback conversation — not prescriptive.]\n\n1. **[Behaviour to change]:** [What does success look like at 90 days? How will we measure it?]\n2. **[Skill to build]:** [What specific resource, practice, or support will help? Who will observe progress?]\n\n---\n\n## Quality Checks\n\n- [ ] Survey questions are behaviourally anchored — they describe observable actions, not attitudes\n- [ ] Open-ended questions ask for specific examples — not general impressions\n- [ ] Report strengths are backed by specific evidence, not generic praise\n- [ ] Development areas name the behaviour and its impact — not the person's character\n- [ ] Suggested actions are specific enough that the reviewee knows exactly what to do differently on Monday\n- [ ] Direct quotes are genuinely direct — not paraphrased into blandness\n\n## Anti-Patterns\n\n- [ ] Do not write survey questions that ask about personality traits rather than observable behaviours (\"is a good communicator\" vs \"communicates updates before deadlines\")\n- [ ] Do not write development feedback that names the person's character flaws instead of specific behaviours and their impact\n- [ ] Do not aggregate ratings without noting high-variance scores — a 2/5 and a 5/5 averaged to 3.5 hides a real signal\n- [ ] Do not include direct quotes in the report that could identify the reviewer in small teams — paraphrase or omit\n- [ ] Do not write suggested actions so vague they could apply to anyone (\"be more strategic\") — every suggestion must name a specific observable behaviour change\n\n## Example Trigger Phrases\n\n- \"Build a 360 feedback survey for a [role] at senior level\"\n- \"Write a 360 feedback report from these notes: [paste notes]\"\n- \"Design a 360 review template for engineering managers\"\n- \"Help me write constructive 360 feedback for my colleague [Name]\"\n- \"Create a peer feedback survey for our upcoming performance cycle\"","schemaVersion":1},"repoUrl":"https://github.com/mohitagw15856/pm-claude-skills/tree/main/skills/360-feedback-template","tags":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pm-claude-skills","audit":{"files":["package.json"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-02","message":"`postinstall` script runs on every install.","surface":"package.json","evidence":"postinstall: node bin/postinstall.mjs","severity":"high"}],"packages":0,"auditedAt":"2026-09-25T12:51:59.225Z","lockfiles":[]},"forks":249,"owner":"mohitagw15856","stars":1397,"topics":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini","llm","mcp","mcp-server","product-management","productivity","prompt-engineering","prompts","skills"],"license":"MIT","fullName":"mohitagw15856/pm-claude-skills","homepage":"https://mohitagw15856.github.io/pm-claude-skills/","language":"HTML","pushedAt":"2026-09-25T10:13:15Z","avatarUrl":"https://avatars.githubusercontent.com/u/119053560?v=4","crawledAt":"2026-09-25T12:51:48.196Z","openIssues":13,"manifestFile":"SKILL.md","manifestPath":"skills/360-feedback-template/SKILL.md","defaultBranch":"main"},"readme":"# 360-Degree Feedback Template Skill\n\nThis skill produces two outputs depending on what the user needs: (1) a complete 360 survey instrument for gathering feedback, or (2) a structured 360 feedback report written from gathered notes. Both outputs follow best practice: behaviourally anchored ratings, specific examples, and development-oriented framing.\n\n## Required Inputs\n\nAsk the user which output they need, then gather inputs:\n\n**For a survey instrument:**\n- **Role being reviewed** (job title and level)\n- **Competencies to assess** (or use defaults below)\n- **Reviewer relationships** (peer / direct report / manager / cross-functional)\n- **Rating scale preference** (1–5 / 1–4 / frequency-based)\n- **Anonymity level** (fully anonymous / attributed / confidential aggregated)\n\n**For a feedback report:**\n- **Person being reviewed** (role and level)\n- **Feedback notes or raw themes** from reviewers (paste what you have)\n- **Reviewer relationships** (how many peers, direct reports, managers responded)\n- **Any context** — performance cycle, specific behaviours to address, promotion consideration\n\n---\n\n## Output A: 360 Survey Instrument\n\n---\n\n# 360 Feedback Survey: [Role / Level]\n\n**Purpose:** This survey helps [Name / \"the reviewee\"] understand how their behaviours and impact are perceived by the people they work with most closely. Responses [are / are not] anonymous. Results will be shared as [individual responses / aggregated themes].\n\n**Instructions:** For each statement, rate how frequently you observe this behaviour. Add specific examples in the open-ended sections — these are the most valuable part of the survey.\n\n**Rating scale:**\n- **5 — Consistently:** Almost always demonstrates this behaviour, even in difficult situations\n- **4 — Usually:** Demonstrates this behaviour more often than not\n- **3 — Sometimes:** Demonstrates this behaviour inconsistently\n- **2 — Rarely:** Seldom demonstrates this behaviour\n- **1 — Not observed:** Have not had the opportunity to observe this behaviour\n\n---\n\n### Section 1: Delivery & Execution\n\n| Statement | Rating (1–5) |\n|---|---|\n| Delivers work on time and to the expected quality | |\n| Proactively flags risks and blockers before they become problems | |\n| Follows through on commitments without needing to be chased | |\n| Manages their workload effectively without compromising quality | |\n| Adapts quickly when priorities or requirements change | |\n\n**Open question:** Describe a specific time when [Name] handled a delivery challenge particularly well or poorly.\n\n---\n\n### Section 2: Communication & Collaboration\n\n| Statement | Rating (1–5) |\n|---|---|\n| Communicates clearly and concisely in both written and verbal formats | |\n| Listens actively and considers others' input before responding | |\n| Keeps the right people informed without over-communicating | |\n| Resolves disagreements constructively and without defensiveness | |\n| Makes it easy for others to collaborate with them | |\n\n**Open question:** Give an example of how [Name] handled a difficult or high-stakes communication.\n\n---\n\n### Section 3: Leadership & Influence\n\n| Statement | Rating (1–5) |\n|---|---|\n| Sets a clear direction that others can follow | |\n| Builds confidence and capability in people around them | |\n| Influences decisions without relying on authority | |\n| Gives clear, constructive feedback that helps others improve | |\n| Creates an environment where people feel safe to raise concerns | |\n\n**Open question:** Describe a situation where [Name]'s leadership had a notable positive or negative impact on the team.\n\n---\n\n### Section 4: Strategic Thinking\n\n| Statement | Rating (1–5) |\n|---|---|\n| Understands the broader business context, not just their immediate work | |\n| Makes connections between their work and organisational goals | |\n| Thinks ahead and anticipates second-order consequences | |\n| Brings original ideas or new approaches to problems | |\n| Balances short-term needs with longer-term thinking | |\n\n**Open question:** G","createdAt":"2026-09-25T12:51:59.275Z","updatedAt":"2026-09-25T12:51:59.275Z"},{"id":"cmugyn06s02ldqu06u6hzml6b","slug":"mohitagw15856-pm-claude-skills-401k-plan-decoder","name":"401k-plan-decoder","description":"Decode a 401k or workplace retirement plan — the real cost of its funds, the match's fine print, vesting math, and the plan features worth using or avoiding. Use when someone asks 'is my 401k any good', 'decode my 401k plan', 'which funds should I look at', or 'what fees am I paying'. Produces a fee decode in dollars-over-time, match and vesting math, a fund-lineup triage by cost, and the questions for HR or the plan administrator.","authorId":"gh:mohitagw15856","authorName":"mohitagw15856","version":"0.1.0","category":"Prompt","securityLevel":"Sandbox","downloadsCount":0,"githubStars":1397,"pricePerCall":0,"manifest":{"name":"401k-plan-decoder","tools":[],"category":"Prompt","entrypoint":{"type":"prompt"},"description":"Decode a 401k or workplace retirement plan — the real cost of its funds, the match's fine print, vesting math, and the plan features worth using or avoiding. Use when someone asks 'is my 401k any good', 'decode my 401k plan', 'which funds should I look at', or 'what fees am I paying'. Produces a fee decode in dollars-over-time, match and vesting math, a fund-lineup triage by cost, and the questions for HR or the plan administrator.","permissions":[],"systemPrompt":"# 401k Plan Decoder Skill\n\nNobody reads the 401k enrollment packet, which is how a 0.9% expense ratio quietly eats six figures of a career's compounding. This skill reads it: what the funds actually cost in dollars over time, what the match really promises once vesting and true-up fine print are applied, and which plan features (Roth option, brokerage window, loan terms) matter for this person. It decodes cost and structure — it never picks investments.\n\n## What This Skill Produces\n\n- The fee decode: each relevant expense ratio and admin fee converted to dollars-over-career on the user's numbers\n- Match math with the fine print applied: per-paycheck vs. annual true-up, vesting schedule, what leaving at year N forfeits\n- Fund-lineup triage by cost tier — where the cheap broad-market building blocks are, and which funds cost 10× a near-identical neighbor\n- Feature decode (Roth 401k, after-tax + conversions if offered, loans, brokerage window) and the questions for HR/administrator\n\n## Required Inputs\n\nAsk for these only if they aren't already provided:\n\n- **The plan documents** — fund lineup with expense ratios (the fee disclosure / 404a-5 notice is the gold source), match formula, vesting schedule, summary plan description excerpts. Decode what's provided; list what's missing by name.\n- **Their numbers** — salary, current contribution %, balance, and age band — needed to make fees and match concrete.\n- **Tenure expectation** — vesting math is meaningless without it.\n\n## Framework: Severity Scale\n\n- 🔴 **Can cost you real money** — expense ratios ≥ ~0.75% on funds with cheap index alternatives in the same lineup (compute the career cost), per-participant admin fees charged to the employee on small balances, match computed per-paycheck *without* an annual true-up (front-loading or uneven contributions forfeit match — quote the formula), long cliff vesting against their expected tenure, contributing below the full match threshold (the only guaranteed 50–100% return in finance, being declined).\n- 🟡 **Unusual — check before relying on it** — target-date funds built from expensive underlying funds (decode the layered cost), loan provisions that require immediate repayment at separation, forced rollout of small balances, revenue-sharing arrangements buried in the fee notice.\n- 🟢 **Standard** — ordinary match formulas, graded vesting, a lineup containing low-cost index options; label the good parts explicitly — a decent plan deserves to be trusted.\n\nAlways show the arithmetic:\n1. **Fee drag** — balance and contributions compounded at a stated assumed return, with and without the fee delta, over the years to retirement age band; present the gap in dollars with assumptions labeled.\n2. **Match math** — the formula applied to their salary; the per-paycheck-vs-true-up check with a concrete forfeiture scenario if applicable.\n3. **Vesting math** — dollars forfeited if they leave at their stated expected tenure.\n\n## Output Format\n\n### 401k Decode: [employer plan]\n\n**1. The verdict** — is the match fully captured, what the fees cost over a career, and the one change worth making this week.\n\n**2. The fee decode** — admin fees + expense ratios in dollars-over-time, arithmetic shown, assumptions labeled.\n\n**3. Match & vesting math** — formula applied, true-up check, forfeiture at stated tenure.\n\n**4. Fund lineup triage**\n\n| Fund | Expense ratio | Cost tier | Note (cheap-neighbor comparison, layered costs) |\n|---|---|---|---|\n\n**5. Feature decode** — Roth option, after-tax/conversion availability, loans, brokerage window — what each is, who it tends to matter for, flagged `[to confirm]` where the documents are silent.\n\n**6. Questions for HR / the administrator** — missing documents, true-up confirmation in writing, fee-disclosure request.\n\nEnd the artifact with, verbatim: *\"This is a plain-language reading, not legal/financial advice — laws vary by jurisdiction; confirm anything load-bearing with a qualified professional.\"*\n\n## Quality Checks\n\n- [ ] Every fee is converted to dollars-over-time with assumptions labeled, never left as a percentage\n- [ ] The per-paycheck vs. true-up distinction is checked and quoted from the documents\n- [ ] Vesting forfeiture is computed at the user's stated tenure\n- [ ] Cost-tier triage compares funds *within this lineup*, not against the whole market\n- [ ] Missing documents are listed by name, and silent features are `[to confirm]`\n- [ ] The disclaimer line appears verbatim in the artifact\n\n## Anti-Patterns\n\n- [ ] Do not recommend specific funds or allocations — decode cost and structure; the picking is the user's (or their advisor's)\n- [ ] Do not invent fees or plan terms that aren't in the documents\n- [ ] Do not present the fee-drag projection as a prediction — it's an illustration with labeled assumptions\n- [ ] Do not soften the below-the-match finding — declining free money is the headline, say it plainly\n- [ ] Do not treat jurisdiction- and plan-specific rules (loans, withdrawals, protections) as universal\n\n## Based On\n\nParticipant-side plan review practice — fee-disclosure auditing, match-formula fine print, vesting math, lineup cost triage.","schemaVersion":1},"repoUrl":"https://github.com/mohitagw15856/pm-claude-skills/tree/main/skills/401k-plan-decoder","tags":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini"],"stats":{"installVelocity7d":0,"retentionRate":0,"executions":0,"rating":null},"origin":"github","source":{"repo":"pm-claude-skills","audit":{"files":["package.json"],"binaries":[],"findings":[{"kind":"dependency","rule":"DP-02","message":"`postinstall` script runs on every install.","surface":"package.json","evidence":"postinstall: node bin/postinstall.mjs","severity":"high"}],"packages":0,"auditedAt":"2026-09-25T12:51:59.225Z","lockfiles":[]},"forks":249,"owner":"mohitagw15856","stars":1397,"topics":["agent-skills","agents","ai-agents","ai-tools","anthropic","chatgpt","claude","claude-code","claude-skills","cursor","developer-tools","gemini","llm","mcp","mcp-server","product-management","productivity","prompt-engineering","prompts","skills"],"license":"MIT","fullName":"mohitagw15856/pm-claude-skills","homepage":"https://mohitagw15856.github.io/pm-claude-skills/","language":"HTML","pushedAt":"2026-09-25T10:13:15Z","avatarUrl":"https://avatars.githubusercontent.com/u/119053560?v=4","crawledAt":"2026-09-25T12:51:48.196Z","openIssues":13,"manifestFile":"SKILL.md","manifestPath":"skills/401k-plan-decoder/SKILL.md","defaultBranch":"main"},"readme":"# 401k Plan Decoder Skill\n\nNobody reads the 401k enrollment packet, which is how a 0.9% expense ratio quietly eats six figures of a career's compounding. This skill reads it: what the funds actually cost in dollars over time, what the match really promises once vesting and true-up fine print are applied, and which plan features (Roth option, brokerage window, loan terms) matter for this person. It decodes cost and structure — it never picks investments.\n\n## What This Skill Produces\n\n- The fee decode: each relevant expense ratio and admin fee converted to dollars-over-career on the user's numbers\n- Match math with the fine print applied: per-paycheck vs. annual true-up, vesting schedule, what leaving at year N forfeits\n- Fund-lineup triage by cost tier — where the cheap broad-market building blocks are, and which funds cost 10× a near-identical neighbor\n- Feature decode (Roth 401k, after-tax + conversions if offered, loans, brokerage window) and the questions for HR/administrator\n\n## Required Inputs\n\nAsk for these only if they aren't already provided:\n\n- **The plan documents** — fund lineup with expense ratios (the fee disclosure / 404a-5 notice is the gold source), match formula, vesting schedule, summary plan description excerpts. Decode what's provided; list what's missing by name.\n- **Their numbers** — salary, current contribution %, balance, and age band — needed to make fees and match concrete.\n- **Tenure expectation** — vesting math is meaningless without it.\n\n## Framework: Severity Scale\n\n- 🔴 **Can cost you real money** — expense ratios ≥ ~0.75% on funds with cheap index alternatives in the same lineup (compute the career cost), per-participant admin fees charged to the employee on small balances, match computed per-paycheck *without* an annual true-up (front-loading or uneven contributions forfeit match — quote the formula), long cliff vesting against their expected tenure, contributing below the full match threshold (the only guaranteed 50–100% return in finance, being declined).\n- 🟡 **Unusual — check before relying on it** — target-date funds built from expensive underlying funds (decode the layered cost), loan provisions that require immediate repayment at separation, forced rollout of small balances, revenue-sharing arrangements buried in the fee notice.\n- 🟢 **Standard** — ordinary match formulas, graded vesting, a lineup containing low-cost index options; label the good parts explicitly — a decent plan deserves to be trusted.\n\nAlways show the arithmetic:\n1. **Fee drag** — balance and contributions compounded at a stated assumed return, with and without the fee delta, over the years to retirement age band; present the gap in dollars with assumptions labeled.\n2. **Match math** — the formula applied to their salary; the per-paycheck-vs-true-up check with a concrete forfeiture scenario if applicable.\n3. **Vesting math** — dollars forfeited if they leave at their stated expected tenure.\n\n## Output Format\n\n### 401k Decode: [employer plan]\n\n**1. The verdict** — is the match fully captured, what the fees cost over a career, and the one change worth making this week.\n\n**2. The fee decode** — admin fees + expense ratios in dollars-over-time, arithmetic shown, assumptions labeled.\n\n**3. Match & vesting math** — formula applied, true-up check, forfeiture at stated tenure.\n\n**4. Fund lineup triage**\n\n| Fund | Expense ratio | Cost tier | Note (cheap-neighbor comparison, layered costs) |\n|---|---|---|---|\n\n**5. Feature decode** — Roth option, after-tax/conversion availability, loans, brokerage window — what each is, who it tends to matter for, flagged `[to confirm]` where the documents are silent.\n\n**6. Questions for HR / the administrator** — missing documents, true-up confirmation in writing, fee-disclosure request.\n\nEnd the artifact with, verbatim: *\"This is a plain-language reading, not legal/financial advice — laws vary by jurisdiction; confirm anything load-bearing with a qualified professional.\"*\n\n## Quality Checks\n\n- ","createdAt":"2026-09-25T12:51:59.285Z","updatedAt":"2026-09-25T12:51:59.285Z"}],"total":104,"limit":24,"offset":0}