@rfxlamia/skillkit 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. package/agents/agents/creative-copywriter.md +212 -0
  2. package/agents/agents/dario-amodei.md +135 -0
  3. package/agents/agents/doc-simplifier.md +63 -0
  4. package/agents/agents/kotlin-pro.md +433 -0
  5. package/agents/agents/red-team.md +136 -0
  6. package/agents/agents/sam-altman.md +121 -0
  7. package/agents/agents/seo-manager.md +184 -0
  8. package/package.json +1 -1
  9. package/skills/skillkit-help/SKILL.md +81 -0
  10. package/skills/skillkit-help/knowledge/application/09-case-studies.md +257 -0
  11. package/skills/skillkit-help/knowledge/application/12-testing-and-validation.md +276 -0
  12. package/skills/skillkit-help/knowledge/foundation/01-why-skills-exist.md +246 -0
  13. package/skills/skillkit-help/knowledge/foundation/02-skills-vs-subagents-comparison.md +312 -0
  14. package/skills/skillkit-help/knowledge/foundation/03-skills-vs-subagents-decision-tree.md +346 -0
  15. package/skills/skillkit-help/knowledge/foundation/06-platform-constraints.md +237 -0
  16. package/skills/skillkit-help/knowledge/foundation/08-when-not-to-use-skills.md +270 -0
  17. package/skills/skillkit-help/template/SKILL.md +52 -0
  18. package/skills/skills/adversarial-review/SKILL.md +219 -0
  19. package/skills/skills/baby-education/SKILL.md +260 -0
  20. package/skills/skills/baby-education/references/advanced-techniques.md +323 -0
  21. package/skills/skills/baby-education/references/transformations.md +345 -0
  22. package/skills/skills/been-there-done-that/SKILL.md +455 -0
  23. package/skills/skills/been-there-done-that/references/analysis-patterns.md +162 -0
  24. package/skills/skills/been-there-done-that/references/git-commands.md +132 -0
  25. package/skills/skills/been-there-done-that/references/tree-insertion-logic.md +145 -0
  26. package/skills/skills/coolhunter/SKILL.md +270 -0
  27. package/skills/skills/coolhunter/assets/elicitation-methods.csv +51 -0
  28. package/skills/skills/coolhunter/knowledge/elicitation-methods.md +312 -0
  29. package/skills/skills/coolhunter/references/workflow-execution.md +238 -0
  30. package/skills/skills/coolhunter/workflow-plan-coolhunter.md +232 -0
  31. package/skills/skills/creative-copywriting/SKILL.md +324 -0
  32. package/skills/skills/creative-copywriting/databases/README.md +60 -0
  33. package/skills/skills/creative-copywriting/databases/carousel-structures.csv +16 -0
  34. package/skills/skills/creative-copywriting/databases/emotional-arcs.csv +11 -0
  35. package/skills/skills/creative-copywriting/databases/hook-formulas.csv +51 -0
  36. package/skills/skills/creative-copywriting/databases/power-words.csv +201 -0
  37. package/skills/skills/creative-copywriting/databases/psychological-triggers.csv +21 -0
  38. package/skills/skills/creative-copywriting/databases/read-more-patterns.csv +26 -0
  39. package/skills/skills/creative-copywriting/databases/swipe-triggers.csv +31 -0
  40. package/skills/skills/creative-copywriting/references/carousel-psychology.md +223 -0
  41. package/skills/skills/creative-copywriting/references/hook-anatomy.md +169 -0
  42. package/skills/skills/creative-copywriting/references/power-word-science.md +134 -0
  43. package/skills/skills/creative-copywriting/references/storytelling-frameworks.md +157 -0
  44. package/skills/skills/diverse-content-gen/SKILL.md +201 -0
  45. package/skills/skills/diverse-content-gen/references/advanced-techniques.md +320 -0
  46. package/skills/skills/diverse-content-gen/references/research-findings.md +379 -0
  47. package/skills/skills/diverse-content-gen/references/task-workflows.md +241 -0
  48. package/skills/skills/diverse-content-gen/references/tool-integration.md +419 -0
  49. package/skills/skills/diverse-content-gen/references/troubleshooting.md +426 -0
  50. package/skills/skills/diverse-content-gen/references/vs-core-technique.md +240 -0
  51. package/skills/skills/framework-critical-thinking/SKILL.md +220 -0
  52. package/skills/skills/framework-critical-thinking/references/bias_detector.md +375 -0
  53. package/skills/skills/framework-critical-thinking/references/fallback_handler.md +239 -0
  54. package/skills/skills/framework-critical-thinking/references/memory_curator.md +161 -0
  55. package/skills/skills/framework-critical-thinking/references/metacognitive_monitor.md +297 -0
  56. package/skills/skills/framework-critical-thinking/references/producer_critic_orchestrator.md +333 -0
  57. package/skills/skills/framework-critical-thinking/references/reasoning_router.md +235 -0
  58. package/skills/skills/framework-critical-thinking/references/reasoning_validator.md +97 -0
  59. package/skills/skills/framework-critical-thinking/references/reflection_trigger.md +78 -0
  60. package/skills/skills/framework-critical-thinking/references/self_verification.md +388 -0
  61. package/skills/skills/framework-critical-thinking/references/uncertainty_quantifier.md +207 -0
  62. package/skills/skills/framework-initiative/SKILL.md +231 -0
  63. package/skills/skills/framework-initiative/references/examples.md +150 -0
  64. package/skills/skills/framework-initiative/references/impact-analysis.md +157 -0
  65. package/skills/skills/framework-initiative/references/intent-patterns.md +145 -0
  66. package/skills/skills/framework-initiative/references/star-framework.md +165 -0
  67. package/skills/skills/humanize-docs/SKILL.md +203 -0
  68. package/skills/skills/humanize-docs/references/advanced-techniques.md +13 -0
  69. package/skills/skills/humanize-docs/references/core-transformations.md +368 -0
  70. package/skills/skills/humanize-docs/references/detection-patterns.md +400 -0
  71. package/skills/skills/humanize-docs/references/examples-gallery.md +374 -0
  72. package/skills/skills/imagine/SKILL.md +190 -0
  73. package/skills/skills/imagine/references/artstyle-corporate-memphis.md +625 -0
  74. package/skills/skills/imagine/references/artstyle-crewdson-hyperrealism.md +295 -0
  75. package/skills/skills/imagine/references/artstyle-iphone-social-media.md +426 -0
  76. package/skills/skills/imagine/references/artstyle-sciencesaru.md +276 -0
  77. package/skills/skills/pre-deploy-checklist/README.md +26 -0
  78. package/skills/skills/pre-deploy-checklist/SKILL.md +153 -0
  79. package/skills/skills/pre-deploy-checklist/references/checklist-categories.md +174 -0
  80. package/skills/skills/pre-deploy-checklist/references/domain-prompts.md +216 -0
  81. package/skills/skills/prompt-engineering/SKILL.md +209 -0
  82. package/skills/skills/prompt-engineering/references/advanced-combinations.md +444 -0
  83. package/skills/skills/prompt-engineering/references/chain-of-thought.md +140 -0
  84. package/skills/skills/prompt-engineering/references/decision_matrix.md +220 -0
  85. package/skills/skills/prompt-engineering/references/few-shot.md +346 -0
  86. package/skills/skills/prompt-engineering/references/json-format.md +270 -0
  87. package/skills/skills/prompt-engineering/references/natural-language.md +420 -0
  88. package/skills/skills/prompt-engineering/references/pitfalls.md +365 -0
  89. package/skills/skills/prompt-engineering/references/prompt-chaining.md +498 -0
  90. package/skills/skills/prompt-engineering/references/react.md +108 -0
  91. package/skills/skills/prompt-engineering/references/self-consistency.md +322 -0
  92. package/skills/skills/prompt-engineering/references/tree-of-thoughts.md +386 -0
  93. package/skills/skills/prompt-engineering/references/xml-format.md +220 -0
  94. package/skills/skills/prompt-engineering/references/yaml-format.md +488 -0
  95. package/skills/skills/prompt-engineering/references/zero-shot.md +74 -0
  96. package/skills/skills/quick-spec/SKILL.md +280 -0
  97. package/skills/skills/quick-spec/assets/tech-spec-template.md +74 -0
  98. package/skills/skills/quick-spec/references/step-01-understand.md +189 -0
  99. package/skills/skills/quick-spec/references/step-02-investigate.md +144 -0
  100. package/skills/skills/quick-spec/references/step-03-generate.md +128 -0
  101. package/skills/skills/quick-spec/references/step-04-review.md +173 -0
  102. package/skills/skills/quick-spec/tests/__pycache__/test_skill.cpython-314-pytest-9.0.2.pyc +0 -0
  103. package/skills/skills/quick-spec/tests/test_scenarios.md +83 -0
  104. package/skills/skills/quick-spec/tests/test_skill.py +136 -0
  105. package/skills/skills/readme-expert/SKILL.md +538 -0
  106. package/skills/skills/readme-expert/knowledge/INDEX.md +192 -0
  107. package/skills/skills/readme-expert/knowledge/application/quality-standards.md +470 -0
  108. package/skills/skills/readme-expert/knowledge/application/script-executor.md +604 -0
  109. package/skills/skills/readme-expert/knowledge/application/template-library.md +822 -0
  110. package/skills/skills/readme-expert/knowledge/foundation/codebase-scanner.md +361 -0
  111. package/skills/skills/readme-expert/knowledge/foundation/validation-checklist.md +481 -0
  112. package/skills/skills/red-teaming/SKILL.md +321 -0
  113. package/skills/skills/red-teaming/references/ai-llm-redteam.md +517 -0
  114. package/skills/skills/red-teaming/references/attack-techniques.md +410 -0
  115. package/skills/skills/red-teaming/references/cybersecurity-redteam.md +383 -0
  116. package/skills/skills/red-teaming/references/tools-frameworks.md +446 -0
  117. package/skills/skills/releasing/.skillkit-mode +1 -0
  118. package/skills/skills/releasing/SKILL.md +225 -0
  119. package/skills/skills/releasing/references/version-detection.md +108 -0
  120. package/skills/skills/screenwriter/SKILL.md +273 -0
  121. package/skills/skills/screenwriter/references/advanced-techniques.md +216 -0
  122. package/skills/skills/screenwriter/references/pipeline-integration.md +266 -0
  123. package/skills/skills/skillkit/.claude/settings.local.json +7 -0
  124. package/skills/skills/skillkit/.claude-plugin/plugin.json +27 -0
  125. package/skills/skills/skillkit/CHANGELOG.md +484 -0
  126. package/skills/skills/skillkit/SKILL.md +511 -0
  127. package/skills/skills/skillkit/commands/skillkit.md +6 -0
  128. package/skills/skills/skillkit/commands/validate-plan.md +6 -0
  129. package/skills/skills/skillkit/commands/verify.md +6 -0
  130. package/skills/skills/skillkit/knowledge/INDEX.md +352 -0
  131. package/skills/skills/skillkit/knowledge/application/09-case-studies.md +257 -0
  132. package/skills/skills/skillkit/knowledge/application/10-technical-architecture.md +324 -0
  133. package/skills/skills/skillkit/knowledge/application/11-adoption-strategy.md +267 -0
  134. package/skills/skills/skillkit/knowledge/application/12-testing-and-validation.md +276 -0
  135. package/skills/skills/skillkit/knowledge/application/13-competitive-landscape.md +198 -0
  136. package/skills/skills/skillkit/knowledge/foundation/01-why-skills-exist.md +246 -0
  137. package/skills/skills/skillkit/knowledge/foundation/02-skills-vs-subagents-comparison.md +312 -0
  138. package/skills/skills/skillkit/knowledge/foundation/03-skills-vs-subagents-decision-tree.md +346 -0
  139. package/skills/skills/skillkit/knowledge/foundation/04-hybrid-patterns.md +308 -0
  140. package/skills/skills/skillkit/knowledge/foundation/05-token-economics.md +275 -0
  141. package/skills/skills/skillkit/knowledge/foundation/06-platform-constraints.md +237 -0
  142. package/skills/skills/skillkit/knowledge/foundation/07-security-concerns.md +322 -0
  143. package/skills/skills/skillkit/knowledge/foundation/08-when-not-to-use-skills.md +270 -0
  144. package/skills/skills/skillkit/knowledge/plugin-guide.md +614 -0
  145. package/skills/skills/skillkit/knowledge/tools/14-validation-tools-guide.md +150 -0
  146. package/skills/skills/skillkit/knowledge/tools/15-cost-tools-guide.md +157 -0
  147. package/skills/skills/skillkit/knowledge/tools/16-security-tools-guide.md +122 -0
  148. package/skills/skills/skillkit/knowledge/tools/17-pattern-tools-guide.md +161 -0
  149. package/skills/skills/skillkit/knowledge/tools/18-decision-helper-guide.md +243 -0
  150. package/skills/skills/skillkit/knowledge/tools/19-test-generator-guide.md +275 -0
  151. package/skills/skills/skillkit/knowledge/tools/20-split-skill-guide.md +149 -0
  152. package/skills/skills/skillkit/knowledge/tools/21-quality-scorer-guide.md +226 -0
  153. package/skills/skills/skillkit/knowledge/tools/22-migration-helper-guide.md +356 -0
  154. package/skills/skills/skillkit/knowledge/tools/23-subagent-creation-guide.md +448 -0
  155. package/skills/skills/skillkit/knowledge/tools/24-behavioral-testing-guide.md +122 -0
  156. package/skills/skills/skillkit/references/proposal-generation.md +982 -0
  157. package/skills/skills/skillkit/references/rationalization-catalog.md +75 -0
  158. package/skills/skills/skillkit/references/research-methodology.md +661 -0
  159. package/skills/skills/skillkit/references/section-2-full-creation-workflow.md +452 -0
  160. package/skills/skills/skillkit/references/section-3-validation-workflow-existing-skill.md +63 -0
  161. package/skills/skills/skillkit/references/section-4-decision-workflow-skills-vs-subagents.md +64 -0
  162. package/skills/skills/skillkit/references/section-5-migration-workflow-doc-to-skill.md +58 -0
  163. package/skills/skills/skillkit/references/section-6-subagent-creation-workflow.md +499 -0
  164. package/skills/skills/skillkit/references/section-7-knowledge-reference-map.md +72 -0
  165. package/skills/skills/skillkit/scripts/__pycache__/decision_helper.cpython-314.pyc +0 -0
  166. package/skills/skills/skillkit/scripts/__pycache__/quick_validate.cpython-312.pyc +0 -0
  167. package/skills/skills/skillkit/scripts/__pycache__/quick_validate.cpython-314.pyc +0 -0
  168. package/skills/skills/skillkit/scripts/__pycache__/test_generator.cpython-314-pytest-9.0.2.pyc +0 -0
  169. package/skills/skills/skillkit/scripts/decision_helper.py +799 -0
  170. package/skills/skills/skillkit/scripts/init_skill.py +400 -0
  171. package/skills/skills/skillkit/scripts/init_subagent.py +231 -0
  172. package/skills/skills/skillkit/scripts/migration_helper.py +669 -0
  173. package/skills/skills/skillkit/scripts/package_skill.py +211 -0
  174. package/skills/skills/skillkit/scripts/pattern_detector.py +381 -0
  175. package/skills/skills/skillkit/scripts/pattern_detector_new.py +382 -0
  176. package/skills/skills/skillkit/scripts/pressure_tester.py +157 -0
  177. package/skills/skills/skillkit/scripts/quality_scorer.py +999 -0
  178. package/skills/skills/skillkit/scripts/quick_validate.py +100 -0
  179. package/skills/skills/skillkit/scripts/security_scanner.py +474 -0
  180. package/skills/skills/skillkit/scripts/split_skill.py +540 -0
  181. package/skills/skills/skillkit/scripts/test_generator.py +695 -0
  182. package/skills/skills/skillkit/scripts/token_estimator.py +493 -0
  183. package/skills/skills/skillkit/scripts/utils/__init__.py +49 -0
  184. package/skills/skills/skillkit/scripts/utils/__pycache__/__init__.cpython-312.pyc +0 -0
  185. package/skills/skills/skillkit/scripts/utils/__pycache__/__init__.cpython-314.pyc +0 -0
  186. package/skills/skills/skillkit/scripts/utils/__pycache__/budget_tracker.cpython-312.pyc +0 -0
  187. package/skills/skills/skillkit/scripts/utils/__pycache__/budget_tracker.cpython-314.pyc +0 -0
  188. package/skills/skills/skillkit/scripts/utils/__pycache__/output_formatter.cpython-312.pyc +0 -0
  189. package/skills/skills/skillkit/scripts/utils/__pycache__/output_formatter.cpython-314.pyc +0 -0
  190. package/skills/skills/skillkit/scripts/utils/__pycache__/reference_validator.cpython-312.pyc +0 -0
  191. package/skills/skills/skillkit/scripts/utils/__pycache__/reference_validator.cpython-314.pyc +0 -0
  192. package/skills/skills/skillkit/scripts/utils/budget_tracker.py +388 -0
  193. package/skills/skills/skillkit/scripts/utils/output_formatter.py +263 -0
  194. package/skills/skills/skillkit/scripts/utils/reference_validator.py +401 -0
  195. package/skills/skills/skillkit/scripts/validate_skill.py +594 -0
  196. package/skills/skills/skillkit/tests/test_behavioral.py +39 -0
  197. package/skills/skills/skillkit/tests/test_scenarios.md +83 -0
  198. package/skills/skills/skillkit/tests/test_skill.py +136 -0
  199. package/skills/skills/skillkit-help/SKILL.md +81 -0
  200. package/skills/skills/skillkit-help/knowledge/application/09-case-studies.md +257 -0
  201. package/skills/skills/skillkit-help/knowledge/application/12-testing-and-validation.md +276 -0
  202. package/skills/skills/skillkit-help/knowledge/foundation/01-why-skills-exist.md +246 -0
  203. package/skills/skills/skillkit-help/knowledge/foundation/02-skills-vs-subagents-comparison.md +312 -0
  204. package/skills/skills/skillkit-help/knowledge/foundation/03-skills-vs-subagents-decision-tree.md +346 -0
  205. package/skills/skills/skillkit-help/knowledge/foundation/06-platform-constraints.md +237 -0
  206. package/skills/skills/skillkit-help/knowledge/foundation/08-when-not-to-use-skills.md +270 -0
  207. package/skills/skills/skillkit-help/template/SKILL.md +52 -0
  208. package/skills/skills/social-media-seo/SKILL.md +278 -0
  209. package/skills/skills/social-media-seo/databases/caption-styles.csv +31 -0
  210. package/skills/skills/social-media-seo/databases/engagement-tactics.csv +16 -0
  211. package/skills/skills/social-media-seo/databases/hashtag-strategies.csv +21 -0
  212. package/skills/skills/social-media-seo/databases/hook-formulas.csv +26 -0
  213. package/skills/skills/social-media-seo/databases/keyword-clusters.csv +11 -0
  214. package/skills/skills/social-media-seo/databases/thread-structures.csv +26 -0
  215. package/skills/skills/social-media-seo/databases/viral-patterns.csv +21 -0
  216. package/skills/skills/social-media-seo/references/analytics-guide.md +321 -0
  217. package/skills/skills/social-media-seo/references/instagram-seo.md +235 -0
  218. package/skills/skills/social-media-seo/references/threads-seo.md +305 -0
  219. package/skills/skills/social-media-seo/references/x-twitter-seo.md +337 -0
  220. package/skills/skills/social-media-seo/scripts/query_database.py +191 -0
  221. package/skills/skills/storyteller/SKILL.md +241 -0
  222. package/skills/skills/storyteller/references/transformation-methodology.md +293 -0
  223. package/skills/skills/storyteller/references/visual-vocabulary.md +177 -0
  224. package/skills/skills/thread-pro/SKILL.md +162 -0
  225. package/skills/skills/thread-pro/anti-ai-patterns.md +120 -0
  226. package/skills/skills/thread-pro/hook-formulas.md +138 -0
  227. package/skills/skills/thread-pro/references/anti-ai-patterns.md +120 -0
  228. package/skills/skills/thread-pro/references/hook-formulas.md +138 -0
  229. package/skills/skills/thread-pro/references/thread-structures.md +240 -0
  230. package/skills/skills/thread-pro/references/voice-injection.md +130 -0
  231. package/skills/skills/thread-pro/thread-structures.md +240 -0
  232. package/skills/skills/thread-pro/voice-injection.md +130 -0
  233. package/skills/skills/tinkering/SKILL.md +251 -0
  234. package/skills/skills/tinkering/references/graduation-checklist.md +100 -0
  235. package/skills/skills/validate-plan/.skillkit-mode +1 -0
  236. package/skills/skills/validate-plan/SKILL.md +406 -0
  237. package/skills/skills/validate-plan/references/dry-principles.md +251 -0
  238. package/skills/skills/validate-plan/references/gap-analysis-guide.md +320 -0
  239. package/skills/skills/validate-plan/references/tdd-patterns.md +413 -0
  240. package/skills/skills/validate-plan/references/yagni-checklist.md +330 -0
  241. package/skills/skills/verify-before-ship/.skillkit-mode +1 -0
  242. package/skills/skills/verify-before-ship/SKILL.md +116 -0
  243. package/skills/skills/verify-before-ship/references/anti-rationalization.md +212 -0
  244. package/skills/skills/verify-before-ship/references/verification-gates.md +305 -0
  245. package/skills-manifest.json +8 -2
  246. package/src/picker.js +11 -5
  247. package/src/picker.test.js +36 -1
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Quick validation script for skills - minimal version
4
+ """
5
+
6
+ import sys
7
+ import os
8
+ import re
9
+ import yaml
10
+ from pathlib import Path
11
+
12
+ def validate_skill(skill_path):
13
+ """Basic validation of a skill"""
14
+ skill_path = Path(skill_path)
15
+
16
+ # Check SKILL.md exists
17
+ skill_md = skill_path / 'SKILL.md'
18
+ if not skill_md.exists():
19
+ return False, "SKILL.md not found"
20
+
21
+ # Read and validate frontmatter
22
+ content = skill_md.read_text()
23
+ if not content.startswith('---'):
24
+ return False, "No YAML frontmatter found"
25
+
26
+ # Extract frontmatter
27
+ match = re.match(r'^---\n(.*?)\n---', content, re.DOTALL)
28
+ if not match:
29
+ return False, "Invalid frontmatter format"
30
+
31
+ frontmatter_text = match.group(1)
32
+
33
+ # Parse YAML frontmatter
34
+ try:
35
+ frontmatter = yaml.safe_load(frontmatter_text)
36
+ if not isinstance(frontmatter, dict):
37
+ return False, "Frontmatter must be a YAML dictionary"
38
+ except yaml.YAMLError as e:
39
+ return False, f"Invalid YAML in frontmatter: {e}"
40
+
41
+ # Define allowed properties
42
+ ALLOWED_PROPERTIES = {'name', 'description', 'license', 'allowed-tools', 'metadata'}
43
+
44
+ # Check for unexpected properties (excluding nested keys under metadata)
45
+ unexpected_keys = set(frontmatter.keys()) - ALLOWED_PROPERTIES
46
+ if unexpected_keys:
47
+ return False, (
48
+ f"Unexpected key(s) in SKILL.md frontmatter: {', '.join(sorted(unexpected_keys))}. "
49
+ f"Allowed properties are: {', '.join(sorted(ALLOWED_PROPERTIES))}"
50
+ )
51
+
52
+ # Check required fields
53
+ if 'name' not in frontmatter:
54
+ return False, "Missing 'name' in frontmatter"
55
+ if 'description' not in frontmatter:
56
+ return False, "Missing 'description' in frontmatter"
57
+
58
+ # Extract name for validation
59
+ name = frontmatter.get('name', '')
60
+ if not isinstance(name, str):
61
+ return False, f"Name must be a string, got {type(name).__name__}"
62
+ name = name.strip()
63
+ if name:
64
+ # Check naming convention (hyphen-case: lowercase with hyphens)
65
+ if not re.match(r'^[a-z0-9-]+$', name):
66
+ return False, f"Name '{name}' should be hyphen-case (lowercase letters, digits, and hyphens only)"
67
+ if name.startswith('-') or name.endswith('-') or '--' in name:
68
+ return False, f"Name '{name}' cannot start/end with hyphen or contain consecutive hyphens"
69
+ # Check name length (max 64 characters per spec)
70
+ if len(name) > 64:
71
+ return False, f"Name is too long ({len(name)} characters). Maximum is 64 characters."
72
+
73
+ # Extract and validate description
74
+ description = frontmatter.get('description', '')
75
+ if not isinstance(description, str):
76
+ return False, f"Description must be a string, got {type(description).__name__}"
77
+ description = description.strip()
78
+ if description:
79
+ # Check for angle brackets
80
+ if '<' in description or '>' in description:
81
+ return False, "Description cannot contain angle brackets (< or >)"
82
+ # Check description length (max 1024 characters per spec)
83
+ if len(description) > 1024:
84
+ return False, f"Description is too long ({len(description)} characters). Maximum is 1024 characters."
85
+
86
+ return True, "Skill is valid!"
87
+
88
+ if __name__ == "__main__":
89
+ import argparse
90
+
91
+ parser = argparse.ArgumentParser(
92
+ description='Quick validation script for skills - minimal version'
93
+ )
94
+ parser.add_argument('skill_path', help='Path to skill directory')
95
+
96
+ args = parser.parse_args()
97
+
98
+ valid, message = validate_skill(args.skill_path)
99
+ print(message)
100
+ sys.exit(0 if valid else 1)
@@ -0,0 +1,474 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Security vulnerability scanner for Claude skills.
4
+ Detects common security anti-patterns and provides remediation guidance.
5
+
6
+ Usage:
7
+ python security_scanner.py <skill_path> [--severity LEVEL] [--format FORMAT]
8
+
9
+ References:
10
+ - File 07: Security concerns and best practices
11
+ - File 16: Vulnerability patterns and prevention
12
+ """
13
+
14
+ import re
15
+ import sys
16
+ from pathlib import Path
17
+ from typing import Dict, List
18
+ from dataclasses import dataclass
19
+ from enum import Enum
20
+
21
+
22
+ class Severity(Enum):
23
+ """Security finding severity levels."""
24
+ CRITICAL = 0
25
+ HIGH = 1
26
+ MEDIUM = 2
27
+ LOW = 3
28
+ INFO = 4
29
+
30
+
31
+ @dataclass
32
+ class Finding:
33
+ """Single security finding."""
34
+ severity: Severity
35
+ finding_type: str
36
+ file: str
37
+ line: int
38
+ description: str
39
+ evidence: str
40
+ remediation: str
41
+
42
+
43
+ class SecurityScanner:
44
+ """Automated security vulnerability detection for skills."""
45
+
46
+ def __init__(self, skill_path: str):
47
+ """Initialize scanner with skill directory path."""
48
+ self.skill_path = Path(skill_path)
49
+ self.findings: List[Finding] = []
50
+
51
+ if not self.skill_path.exists():
52
+ raise FileNotFoundError(f"Skill path not found: {skill_path}")
53
+
54
+ # ========== SECRET DETECTION ==========
55
+
56
+ def scan_hardcoded_secrets(self) -> List[Finding]:
57
+ """
58
+ Scan for hardcoded secrets in all files.
59
+ Reference: File 07 (credential management)
60
+ """
61
+ findings = []
62
+
63
+ secret_patterns = [
64
+ (r'api[_-]?key\s*=\s*["\'][\w\-]+["\']', 'API key'),
65
+ (r'password\s*=\s*["\'][^"\']+["\']', 'Password'),
66
+ (r'token\s*=\s*["\'][\w\-]+["\']', 'Token'),
67
+ (r'secret\s*=\s*["\'][\w\-]+["\']', 'Secret'),
68
+ (r'Authorization:\s*Bearer\s+[\w\-\.]+', 'Bearer token'),
69
+ (r'sk-[a-zA-Z0-9]{32,}', 'API key pattern'),
70
+ ]
71
+
72
+ for file_path in self._get_scannable_files():
73
+ content = file_path.read_text(encoding='utf-8', errors='ignore')
74
+
75
+ for pattern, secret_type in secret_patterns:
76
+ for match in re.finditer(pattern, content, re.IGNORECASE):
77
+ line_num = content[:match.start()].count('\n') + 1
78
+ findings.append(Finding(
79
+ severity=Severity.CRITICAL,
80
+ finding_type='Hardcoded Secret',
81
+ file=str(file_path.relative_to(self.skill_path)),
82
+ line=line_num,
83
+ description=f'{secret_type} detected in code',
84
+ evidence=match.group(0)[:50] + '...',
85
+ remediation='Use environment variables or secret management (File 07)'
86
+ ))
87
+
88
+ return findings
89
+
90
+ # ========== COMMAND INJECTION ==========
91
+
92
+ def scan_command_injection(self) -> List[Finding]:
93
+ """
94
+ Scan for command injection vulnerabilities.
95
+ Reference: File 07 (injection risks)
96
+ """
97
+ findings = []
98
+
99
+ dangerous_patterns = [
100
+ (r'subprocess\.\w+\([^)]*shell\s*=\s*True', 'shell=True', Severity.CRITICAL),
101
+ (r'os\.system\s*\(', 'os.system()', Severity.CRITICAL),
102
+ (r'\beval\s*\(', 'eval()', Severity.CRITICAL),
103
+ (r'\bexec\s*\(', 'exec()', Severity.CRITICAL),
104
+ ]
105
+
106
+ for file_path in self._get_python_files():
107
+ content = file_path.read_text(encoding='utf-8', errors='ignore')
108
+
109
+ for pattern, name, severity in dangerous_patterns:
110
+ for match in re.finditer(pattern, content):
111
+ line_num = content[:match.start()].count('\n') + 1
112
+ findings.append(Finding(
113
+ severity=severity,
114
+ finding_type='Command Injection Risk',
115
+ file=str(file_path.relative_to(self.skill_path)),
116
+ line=line_num,
117
+ description=f'Dangerous function: {name}',
118
+ evidence=match.group(0),
119
+ remediation='Use parameterized commands, avoid shell=True/eval/exec'
120
+ ))
121
+
122
+ return findings
123
+
124
+ # ========== SQL INJECTION ==========
125
+
126
+ def scan_sql_injection(self) -> List[Finding]:
127
+ """
128
+ Scan for SQL injection patterns.
129
+ Reference: File 16 (SQL injection prevention)
130
+ """
131
+ findings = []
132
+
133
+ sql_patterns = [
134
+ (r'(SELECT|INSERT|UPDATE|DELETE).*\+.*', 'string concatenation'),
135
+ (r'(SELECT|INSERT|UPDATE|DELETE).*f["\'].*\{', 'f-string formatting'),
136
+ (r'(SELECT|INSERT|UPDATE|DELETE).*\.format\(', '.format() usage'),
137
+ ]
138
+
139
+ for file_path in self._get_python_files():
140
+ content = file_path.read_text(encoding='utf-8', errors='ignore')
141
+
142
+ for pattern, name in sql_patterns:
143
+ for match in re.finditer(pattern, content, re.IGNORECASE | re.MULTILINE):
144
+ line_num = content[:match.start()].count('\n') + 1
145
+ findings.append(Finding(
146
+ severity=Severity.HIGH,
147
+ finding_type='SQL Injection Risk',
148
+ file=str(file_path.relative_to(self.skill_path)),
149
+ line=line_num,
150
+ description=f'SQL query with {name}',
151
+ evidence=match.group(0)[:80],
152
+ remediation='Use parameterized queries with placeholders (?)'
153
+ ))
154
+
155
+ return findings
156
+
157
+ # ========== PATH TRAVERSAL ==========
158
+
159
+ def scan_path_traversal(self) -> List[Finding]:
160
+ """
161
+ Scan for path traversal vulnerabilities.
162
+ Reference: File 16 (path security)
163
+ """
164
+ findings = []
165
+
166
+ file_operations = [
167
+ 'open(', 'Path(', 'read_text(', 'write_text(',
168
+ 'os.path.join(', 'shutil.copy(', 'shutil.move('
169
+ ]
170
+
171
+ for file_path in self._get_python_files():
172
+ content = file_path.read_text(encoding='utf-8', errors='ignore')
173
+
174
+ # Heuristic: file operations + user input handling
175
+ has_file_ops = any(op in content for op in file_operations)
176
+ has_user_input = 'input(' in content or 'args.' in content or 'argv' in content
177
+
178
+ if has_file_ops and has_user_input:
179
+ findings.append(Finding(
180
+ severity=Severity.MEDIUM,
181
+ finding_type='Path Traversal Risk',
182
+ file=str(file_path.relative_to(self.skill_path)),
183
+ line=0,
184
+ description='File operations with potential user input',
185
+ evidence='File has both file operations and user input handling',
186
+ remediation='Validate paths, use Path.resolve(), check for .. patterns'
187
+ ))
188
+
189
+ return findings
190
+
191
+ # ========== DANGEROUS IMPORTS ==========
192
+
193
+ def scan_dangerous_imports(self) -> List[Finding]:
194
+ """
195
+ Scan for dangerous library imports.
196
+ Reference: File 16 (dangerous imports)
197
+ """
198
+ findings = []
199
+
200
+ dangerous_imports = [
201
+ ('import pickle', 'pickle', Severity.HIGH,
202
+ 'Arbitrary code execution via deserialization. Use json instead.'),
203
+ ('from pickle', 'pickle', Severity.HIGH,
204
+ 'Arbitrary code execution via deserialization. Use json instead.'),
205
+ ('yaml.load(', 'yaml.load()', Severity.HIGH,
206
+ 'Unsafe YAML loading. Use yaml.safe_load() instead.'),
207
+ ]
208
+
209
+ for file_path in self._get_python_files():
210
+ content = file_path.read_text(encoding='utf-8', errors='ignore')
211
+
212
+ for pattern, name, severity, remediation in dangerous_imports:
213
+ if pattern in content:
214
+ line_num = content.split(pattern)[0].count('\n') + 1
215
+ findings.append(Finding(
216
+ severity=severity,
217
+ finding_type='Dangerous Import',
218
+ file=str(file_path.relative_to(self.skill_path)),
219
+ line=line_num,
220
+ description=f'Risky library: {name}',
221
+ evidence=pattern,
222
+ remediation=remediation
223
+ ))
224
+
225
+ return findings
226
+
227
+ # ========== NETWORK CONNECTIONS ==========
228
+
229
+ def scan_network_connections(self) -> List[Finding]:
230
+ """
231
+ Scan for external network connections.
232
+ Reference: File 16 (network security)
233
+ """
234
+ findings = []
235
+
236
+ network_patterns = [
237
+ (r'https?://(?!localhost|127\.0\.0\.1)[^\s\'"]+', 'External URL'),
238
+ (r'requests\.get\(', 'HTTP GET request'),
239
+ (r'requests\.post\(', 'HTTP POST request'),
240
+ (r'socket\.connect\(', 'Socket connection'),
241
+ (r'urllib\.request\.urlopen\(', 'URL open'),
242
+ ]
243
+
244
+ for file_path in self._get_scannable_files():
245
+ content = file_path.read_text(encoding='utf-8', errors='ignore')
246
+
247
+ for pattern, name in network_patterns:
248
+ for match in re.finditer(pattern, content, re.IGNORECASE):
249
+ line_num = content[:match.start()].count('\n') + 1
250
+ findings.append(Finding(
251
+ severity=Severity.MEDIUM,
252
+ finding_type='External Network Connection',
253
+ file=str(file_path.relative_to(self.skill_path)),
254
+ line=line_num,
255
+ description=f'{name} detected',
256
+ evidence=match.group(0)[:60],
257
+ remediation='Validate necessity, use HTTPS, verify certificates'
258
+ ))
259
+
260
+ return findings
261
+
262
+ # ========== PROMPT INJECTION ==========
263
+
264
+ def scan_prompt_injection(self) -> List[Finding]:
265
+ """
266
+ Scan for prompt injection vulnerabilities in SKILL.md.
267
+ Reference: File 07 (prompt injection prevention)
268
+ """
269
+ findings = []
270
+
271
+ skill_md = self.skill_path / 'SKILL.md'
272
+ if skill_md.exists():
273
+ content = skill_md.read_text(encoding='utf-8')
274
+
275
+ # Check for user input handling without validation mention
276
+ has_user_input = 'user input' in content.lower() or 'user data' in content.lower()
277
+ has_validation = 'validat' in content.lower() or 'sanitiz' in content.lower()
278
+
279
+ if has_user_input and not has_validation:
280
+ findings.append(Finding(
281
+ severity=Severity.MEDIUM,
282
+ finding_type='Prompt Injection Risk',
283
+ file='SKILL.md',
284
+ line=0,
285
+ description='User input mentioned without validation guidance',
286
+ evidence='Instructions reference user input without validation',
287
+ remediation='Add input validation/sanitization instructions (File 07)'
288
+ ))
289
+
290
+ return findings
291
+
292
+ # ========== UTILITY METHODS ==========
293
+
294
+ def _get_scannable_files(self) -> List[Path]:
295
+ """Get all files that should be scanned."""
296
+ extensions = ['.py', '.md', '.sh', '.yaml', '.yml']
297
+ files = []
298
+ for ext in extensions:
299
+ files.extend(self.skill_path.rglob(f'*{ext}'))
300
+ return files
301
+
302
+ def _get_python_files(self) -> List[Path]:
303
+ """Get all Python files in skill directory."""
304
+ return list(self.skill_path.rglob('*.py'))
305
+
306
+ # ========== SCAN EXECUTION ==========
307
+
308
+ def run_all_scans(self) -> List[Finding]:
309
+ """Run all security scans and return findings."""
310
+ self.findings = []
311
+
312
+ self.findings.extend(self.scan_hardcoded_secrets())
313
+ self.findings.extend(self.scan_command_injection())
314
+ self.findings.extend(self.scan_sql_injection())
315
+ self.findings.extend(self.scan_path_traversal())
316
+ self.findings.extend(self.scan_dangerous_imports())
317
+ self.findings.extend(self.scan_network_connections())
318
+ self.findings.extend(self.scan_prompt_injection())
319
+
320
+ return self.findings
321
+
322
+ # ========== REPORT GENERATION ==========
323
+
324
+ def generate_report(self, min_severity: Severity = Severity.LOW, format: str = 'text') -> str:
325
+ """Generate security scan report."""
326
+ if format == 'json':
327
+ return self._generate_json_report(min_severity)
328
+ return self._generate_text_report(min_severity)
329
+
330
+ def _generate_text_report(self, min_severity: Severity) -> str:
331
+ """Generate human-readable text report."""
332
+ # Filter by severity
333
+ filtered = [f for f in self.findings if f.severity.value <= min_severity.value]
334
+
335
+ # Categorize
336
+ critical = [f for f in filtered if f.severity == Severity.CRITICAL]
337
+ high = [f for f in filtered if f.severity == Severity.HIGH]
338
+ medium = [f for f in filtered if f.severity == Severity.MEDIUM]
339
+ low = [f for f in filtered if f.severity == Severity.LOW]
340
+
341
+ lines = []
342
+ lines.append(f"\n{'='*60}")
343
+ lines.append(f"Security Scan Report: {self.skill_path.name}")
344
+ lines.append('='*60 + '\n')
345
+
346
+ # Critical issues
347
+ if critical:
348
+ lines.append("🔴 CRITICAL ISSUES (must fix before deployment):\n")
349
+ for i, finding in enumerate(critical, 1):
350
+ lines.append(f"{i}. {finding.finding_type}")
351
+ lines.append(f" File: {finding.file}:{finding.line}")
352
+ lines.append(f" Issue: {finding.description}")
353
+ lines.append(f" Evidence: {finding.evidence}")
354
+ lines.append(f" Fix: {finding.remediation}\n")
355
+
356
+ # High severity
357
+ if high:
358
+ lines.append("🟠 HIGH SEVERITY (review and fix):\n")
359
+ for i, finding in enumerate(high, 1):
360
+ lines.append(f"{i}. {finding.finding_type}")
361
+ lines.append(f" File: {finding.file}:{finding.line}")
362
+ lines.append(f" Issue: {finding.description}")
363
+ lines.append(f" Fix: {finding.remediation}\n")
364
+
365
+ # Medium severity
366
+ if medium:
367
+ lines.append("🟡 MEDIUM SEVERITY (review required):\n")
368
+ for i, finding in enumerate(medium, 1):
369
+ lines.append(f"{i}. {finding.finding_type} in {finding.file}")
370
+ lines.append(f" {finding.description}\n")
371
+
372
+ # Summary
373
+ total_issues = len(filtered)
374
+ if total_issues == 0:
375
+ lines.append("🟢 No security issues found!\n")
376
+ else:
377
+ lines.append('-'*60)
378
+ lines.append(f"Security Score: {len(critical)} critical, "
379
+ f"{len(high)} high, {len(medium)} medium, {len(low)} low\n")
380
+
381
+ if critical:
382
+ lines.append("⚠️ CRITICAL ISSUES FOUND - Do NOT deploy until fixed!")
383
+ elif high:
384
+ lines.append("⚠️ HIGH SEVERITY ISSUES - Fix before production")
385
+
386
+ # Recommendations
387
+ lines.append("\nGeneral Security Best Practices:")
388
+ lines.append(" • Never hardcode credentials - use environment variables")
389
+ lines.append(" • Never use shell=True with user input")
390
+ lines.append(" • Always validate and sanitize inputs")
391
+ lines.append(" • Use parameterized queries for SQL")
392
+ lines.append(" • Test skills in isolated environment first")
393
+ lines.append("\nReferences: File 07 (security-concerns.md) for guidance\n")
394
+
395
+ return '\n'.join(lines)
396
+
397
+ def _generate_json_report(self, min_severity: Severity) -> str:
398
+ """Generate machine-readable JSON report."""
399
+ import json
400
+
401
+ filtered = [f for f in self.findings if f.severity.value <= min_severity.value]
402
+
403
+ report = {
404
+ 'skill_name': self.skill_path.name,
405
+ 'findings': [
406
+ {
407
+ 'severity': f.severity.name,
408
+ 'type': f.finding_type,
409
+ 'file': f.file,
410
+ 'line': f.line,
411
+ 'description': f.description,
412
+ 'evidence': f.evidence,
413
+ 'remediation': f.remediation
414
+ }
415
+ for f in filtered
416
+ ],
417
+ 'summary': {
418
+ 'total': len(filtered),
419
+ 'critical': len([f for f in filtered if f.severity == Severity.CRITICAL]),
420
+ 'high': len([f for f in filtered if f.severity == Severity.HIGH]),
421
+ 'medium': len([f for f in filtered if f.severity == Severity.MEDIUM]),
422
+ 'low': len([f for f in filtered if f.severity == Severity.LOW])
423
+ }
424
+ }
425
+ return json.dumps(report, indent=2)
426
+
427
+ def get_exit_code(self) -> int:
428
+ """Get appropriate exit code based on findings."""
429
+ if any(f.severity == Severity.CRITICAL for f in self.findings):
430
+ return 2 # Critical issues
431
+ if any(f.severity == Severity.HIGH for f in self.findings):
432
+ return 1 # High severity
433
+ return 0 # All clear
434
+
435
+
436
+ def main():
437
+ """CLI entry point."""
438
+ import argparse
439
+
440
+ parser = argparse.ArgumentParser(
441
+ description='Scan Claude skill for security vulnerabilities',
442
+ epilog='References: Files 07, 16 for security guidance'
443
+ )
444
+ parser.add_argument('skill_path', help='Path to skill directory')
445
+ parser.add_argument('--severity',
446
+ choices=['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'],
447
+ default='LOW',
448
+ help='Minimum severity to report (default: LOW)')
449
+ parser.add_argument('--format', choices=['text', 'json'], default='text',
450
+ help='Output format (default: text)')
451
+
452
+ args = parser.parse_args()
453
+
454
+ try:
455
+ scanner = SecurityScanner(args.skill_path)
456
+ scanner.run_all_scans()
457
+
458
+ min_sev = Severity[args.severity]
459
+ report = scanner.generate_report(min_severity=min_sev, format=args.format)
460
+
461
+ print(report)
462
+ sys.exit(scanner.get_exit_code())
463
+
464
+ except FileNotFoundError as e:
465
+ print(f"Error: {e}", file=sys.stderr)
466
+ sys.exit(2)
467
+
468
+ except Exception as e:
469
+ print(f"Error: {e}", file=sys.stderr)
470
+ sys.exit(2)
471
+
472
+
473
+ if __name__ == '__main__':
474
+ main()