@opendirectory.dev/skills 0.1.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 (212) hide show
  1. package/.claude/skills/claude-md-generator/.env.example +7 -0
  2. package/.claude/skills/claude-md-generator/README.md +78 -0
  3. package/.claude/skills/claude-md-generator/SKILL.md +248 -0
  4. package/.claude/skills/claude-md-generator/evals/evals.json +35 -0
  5. package/.claude/skills/claude-md-generator/references/section-guide.md +175 -0
  6. package/dist/e2e.test.d.ts +1 -0
  7. package/dist/e2e.test.js +62 -0
  8. package/dist/fs-adapters.d.ts +4 -0
  9. package/dist/fs-adapters.js +101 -0
  10. package/dist/fs-adapters.test.d.ts +1 -0
  11. package/dist/fs-adapters.test.js +108 -0
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.js +211 -0
  14. package/dist/transformers.d.ts +6 -0
  15. package/dist/transformers.js +2 -0
  16. package/package.json +25 -0
  17. package/registry.json +226 -0
  18. package/skills/blog-cover-image-cli/.github/workflows/publish.yml +19 -0
  19. package/skills/blog-cover-image-cli/LICENSE +15 -0
  20. package/skills/blog-cover-image-cli/README.md +126 -0
  21. package/skills/blog-cover-image-cli/SKILL.md +7 -0
  22. package/skills/blog-cover-image-cli/agent-skill/blog-cover-generator/README.md +30 -0
  23. package/skills/blog-cover-image-cli/agent-skill/blog-cover-generator/SKILL.md +72 -0
  24. package/skills/blog-cover-image-cli/bin/cli.js +226 -0
  25. package/skills/blog-cover-image-cli/examples/100x_UX_Research_AI_Agent.png +0 -0
  26. package/skills/blog-cover-image-cli/examples/Firecrawl-supabase-bolt.png +0 -0
  27. package/skills/blog-cover-image-cli/examples/Git-City_Case_study_Cover_Image.jpg +0 -0
  28. package/skills/blog-cover-image-cli/examples/THE DISTRIBUTION LAYER (2).png +0 -0
  29. package/skills/blog-cover-image-cli/examples/canva-perplexity-duolingo-cover-image.png +0 -0
  30. package/skills/blog-cover-image-cli/examples/gamma-mistral-veed.png +0 -0
  31. package/skills/blog-cover-image-cli/examples/server-survival-case-study-cover-image(1).png +0 -0
  32. package/skills/blog-cover-image-cli/examples/viral-meme-automation.png +0 -0
  33. package/skills/blog-cover-image-cli/index.js +2 -0
  34. package/skills/blog-cover-image-cli/package-lock.json +2238 -0
  35. package/skills/blog-cover-image-cli/package.json +37 -0
  36. package/skills/blog-cover-image-cli/src/geminiGenerator.js +126 -0
  37. package/skills/blog-cover-image-cli/src/imageValidator.js +54 -0
  38. package/skills/blog-cover-image-cli/src/logoFetcher.js +86 -0
  39. package/skills/claude-md-generator/.env.example +7 -0
  40. package/skills/claude-md-generator/README.md +78 -0
  41. package/skills/claude-md-generator/SKILL.md +254 -0
  42. package/skills/claude-md-generator/evals/evals.json +35 -0
  43. package/skills/claude-md-generator/references/section-guide.md +175 -0
  44. package/skills/cook-the-blog/README.md +86 -0
  45. package/skills/cook-the-blog/SKILL.md +130 -0
  46. package/skills/dependency-update-bot/.env.example +13 -0
  47. package/skills/dependency-update-bot/README.md +101 -0
  48. package/skills/dependency-update-bot/SKILL.md +376 -0
  49. package/skills/dependency-update-bot/evals/evals.json +45 -0
  50. package/skills/dependency-update-bot/references/changelog-patterns.md +201 -0
  51. package/skills/docs-from-code/.env.example +13 -0
  52. package/skills/docs-from-code/README.md +97 -0
  53. package/skills/docs-from-code/SKILL.md +160 -0
  54. package/skills/docs-from-code/evals/evals.json +29 -0
  55. package/skills/docs-from-code/references/extraction-guide.md +174 -0
  56. package/skills/docs-from-code/references/output-template.md +135 -0
  57. package/skills/docs-from-code/scripts/extract_py.py +238 -0
  58. package/skills/docs-from-code/scripts/extract_ts.ts +284 -0
  59. package/skills/docs-from-code/scripts/package.json +18 -0
  60. package/skills/explain-this-pr/README.md +74 -0
  61. package/skills/explain-this-pr/SKILL.md +130 -0
  62. package/skills/explain-this-pr/evals/evals.json +35 -0
  63. package/skills/google-trends-api-skills/README.md +78 -0
  64. package/skills/google-trends-api-skills/SKILL.md +7 -0
  65. package/skills/google-trends-api-skills/google-trends-api/SKILL.md +163 -0
  66. package/skills/google-trends-api-skills/google-trends-api/references/api-responses.md +188 -0
  67. package/skills/google-trends-api-skills/google-trends-api/scripts/discover_keywords.py +344 -0
  68. package/skills/google-trends-api-skills/seo-keyword-research/SKILL.md +205 -0
  69. package/skills/google-trends-api-skills/seo-keyword-research/references/keyword-placement-guide.md +89 -0
  70. package/skills/google-trends-api-skills/seo-keyword-research/references/tech-blog-examples.md +207 -0
  71. package/skills/google-trends-api-skills/seo-keyword-research/scripts/blog_seo_research.py +373 -0
  72. package/skills/hackernews-intel/.env.example +33 -0
  73. package/skills/hackernews-intel/README.md +161 -0
  74. package/skills/hackernews-intel/SKILL.md +156 -0
  75. package/skills/hackernews-intel/evals/evals.json +35 -0
  76. package/skills/hackernews-intel/package.json +15 -0
  77. package/skills/hackernews-intel/scripts/monitor-hn.js +258 -0
  78. package/skills/kill-the-standup/.env.example +22 -0
  79. package/skills/kill-the-standup/README.md +84 -0
  80. package/skills/kill-the-standup/SKILL.md +169 -0
  81. package/skills/kill-the-standup/evals/evals.json +35 -0
  82. package/skills/kill-the-standup/references/standup-format.md +102 -0
  83. package/skills/linkedin-post-generator/.env.example +14 -0
  84. package/skills/linkedin-post-generator/README.md +107 -0
  85. package/skills/linkedin-post-generator/SKILL.md +228 -0
  86. package/skills/linkedin-post-generator/evals/evals.json +35 -0
  87. package/skills/linkedin-post-generator/references/linkedin-format.md +216 -0
  88. package/skills/linkedin-post-generator/references/output-template.md +154 -0
  89. package/skills/llms-txt-generator/.env.example +18 -0
  90. package/skills/llms-txt-generator/README.md +142 -0
  91. package/skills/llms-txt-generator/SKILL.md +176 -0
  92. package/skills/llms-txt-generator/evals/evals.json +35 -0
  93. package/skills/llms-txt-generator/references/llms-txt-spec.md +88 -0
  94. package/skills/llms-txt-generator/references/output-template.md +76 -0
  95. package/skills/llms-txt-generator/test-output/genzcareer.in/llms.txt +31 -0
  96. package/skills/luma-attendees-scraper/README.md +170 -0
  97. package/skills/luma-attendees-scraper/SKILL.md +7 -0
  98. package/skills/luma-attendees-scraper/luma_attendees_export.js +223 -0
  99. package/skills/meeting-brief-generator/.env.example +21 -0
  100. package/skills/meeting-brief-generator/README.md +90 -0
  101. package/skills/meeting-brief-generator/SKILL.md +275 -0
  102. package/skills/meeting-brief-generator/evals/evals.json +35 -0
  103. package/skills/meeting-brief-generator/references/brief-format.md +114 -0
  104. package/skills/meeting-brief-generator/references/output-template.md +150 -0
  105. package/skills/meta-ads-skill/README.md +100 -0
  106. package/skills/meta-ads-skill/SKILL.md +7 -0
  107. package/skills/meta-ads-skill/meta-ads-skill/SKILL.md +41 -0
  108. package/skills/meta-ads-skill/meta-ads-skill/references/report_templates.md +47 -0
  109. package/skills/meta-ads-skill/meta-ads-skill/references/workflows.md +51 -0
  110. package/skills/meta-ads-skill/meta-ads-skill/scripts/auth_check.py +22 -0
  111. package/skills/meta-ads-skill/meta-ads-skill/scripts/formatters.py +46 -0
  112. package/skills/newsletter-digest/.env.example +20 -0
  113. package/skills/newsletter-digest/README.md +147 -0
  114. package/skills/newsletter-digest/SKILL.md +221 -0
  115. package/skills/newsletter-digest/evals/evals.json +35 -0
  116. package/skills/newsletter-digest/feeds.json +7 -0
  117. package/skills/newsletter-digest/package.json +15 -0
  118. package/skills/newsletter-digest/references/digest-format.md +123 -0
  119. package/skills/newsletter-digest/references/output-template.md +136 -0
  120. package/skills/newsletter-digest/scripts/fetch-feeds.js +141 -0
  121. package/skills/newsletter-digest/scripts/ghost-publish.js +147 -0
  122. package/skills/noise2blog/.env.example +16 -0
  123. package/skills/noise2blog/README.md +107 -0
  124. package/skills/noise2blog/SKILL.md +229 -0
  125. package/skills/noise2blog/evals/evals.json +35 -0
  126. package/skills/noise2blog/references/blog-format.md +188 -0
  127. package/skills/noise2blog/references/output-template.md +184 -0
  128. package/skills/outreach-sequence-builder/.env.example +12 -0
  129. package/skills/outreach-sequence-builder/README.md +108 -0
  130. package/skills/outreach-sequence-builder/SKILL.md +248 -0
  131. package/skills/outreach-sequence-builder/evals/evals.json +36 -0
  132. package/skills/outreach-sequence-builder/references/output-template.md +171 -0
  133. package/skills/outreach-sequence-builder/references/sequence-format.md +167 -0
  134. package/skills/outreach-sequence-builder/references/signal-playbook.md +117 -0
  135. package/skills/position-me/README.md +71 -0
  136. package/skills/position-me/SKILL.md +7 -0
  137. package/skills/position-me/position-me/SKILL.md +50 -0
  138. package/skills/position-me/position-me/references/EVALUATION_SOP.md +40 -0
  139. package/skills/position-me/position-me/references/REPORT_TEMPLATE.md +58 -0
  140. package/skills/position-me/position-me/scripts/extract_links.py +49 -0
  141. package/skills/pr-description-writer/README.md +81 -0
  142. package/skills/pr-description-writer/SKILL.md +141 -0
  143. package/skills/pr-description-writer/evals/evals.json +35 -0
  144. package/skills/pr-description-writer/references/pr-format-guide.md +145 -0
  145. package/skills/producthunt-launch-kit/.env.example +7 -0
  146. package/skills/producthunt-launch-kit/README.md +95 -0
  147. package/skills/producthunt-launch-kit/SKILL.md +380 -0
  148. package/skills/producthunt-launch-kit/evals/evals.json +35 -0
  149. package/skills/producthunt-launch-kit/references/copy-rules.md +124 -0
  150. package/skills/reddit-icp-monitor/.env.example +16 -0
  151. package/skills/reddit-icp-monitor/README.md +117 -0
  152. package/skills/reddit-icp-monitor/SKILL.md +271 -0
  153. package/skills/reddit-icp-monitor/evals/evals.json +40 -0
  154. package/skills/reddit-icp-monitor/references/icp-format.md +131 -0
  155. package/skills/reddit-icp-monitor/references/reply-rules.md +110 -0
  156. package/skills/reddit-post-engine/.env.example +13 -0
  157. package/skills/reddit-post-engine/README.md +103 -0
  158. package/skills/reddit-post-engine/SKILL.md +303 -0
  159. package/skills/reddit-post-engine/evals/evals.json +35 -0
  160. package/skills/reddit-post-engine/references/subreddit-playbook.md +156 -0
  161. package/skills/schema-markup-generator/.env.example +19 -0
  162. package/skills/schema-markup-generator/README.md +114 -0
  163. package/skills/schema-markup-generator/SKILL.md +192 -0
  164. package/skills/schema-markup-generator/evals/evals.json +35 -0
  165. package/skills/schema-markup-generator/references/json-ld-spec.md +263 -0
  166. package/skills/schema-markup-generator/references/output-template.md +556 -0
  167. package/skills/show-hn-writer/.env.example +14 -0
  168. package/skills/show-hn-writer/README.md +88 -0
  169. package/skills/show-hn-writer/SKILL.md +303 -0
  170. package/skills/show-hn-writer/evals/evals.json +35 -0
  171. package/skills/show-hn-writer/references/hn-rules.md +74 -0
  172. package/skills/show-hn-writer/references/title-formulas.md +93 -0
  173. package/skills/stargazer/README.md +79 -0
  174. package/skills/stargazer/SKILL.md +7 -0
  175. package/skills/stargazer/stargazer-skill/SKILL.md +58 -0
  176. package/skills/stargazer/stargazer-skill/assets/.env.example +18 -0
  177. package/skills/stargazer/stargazer-skill/scripts/convert_to_csv.py +63 -0
  178. package/skills/stargazer/stargazer-skill/scripts/count_emails.py +52 -0
  179. package/skills/stargazer/stargazer-skill/scripts/stargazer_deep_extractor.py +450 -0
  180. package/skills/tweet-thread-from-blog/.env.example +14 -0
  181. package/skills/tweet-thread-from-blog/README.md +109 -0
  182. package/skills/tweet-thread-from-blog/SKILL.md +177 -0
  183. package/skills/tweet-thread-from-blog/evals/evals.json +35 -0
  184. package/skills/tweet-thread-from-blog/references/output-template.md +193 -0
  185. package/skills/tweet-thread-from-blog/references/thread-format.md +107 -0
  186. package/skills/twitter-GTM-find-skill/README.md +43 -0
  187. package/skills/twitter-GTM-find-skill/SKILL.md +7 -0
  188. package/skills/twitter-GTM-find-skill/twitter-GTM-find/SKILL.md +37 -0
  189. package/skills/twitter-GTM-find-skill/twitter-GTM-find/references/icp-checklist.md +35 -0
  190. package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/package.json +23 -0
  191. package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/run_pipeline.sh +8 -0
  192. package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/src/debug.ts +23 -0
  193. package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/src/extractor.ts +79 -0
  194. package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/src/icp-filter.ts +87 -0
  195. package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/src/index.ts +94 -0
  196. package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/src/scraper.ts +41 -0
  197. package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/tsconfig.json +13 -0
  198. package/skills/yc-intent-radar-skill/README.md +39 -0
  199. package/skills/yc-intent-radar-skill/SKILL.md +7 -0
  200. package/skills/yc-intent-radar-skill/yc-jobs-scraper/SKILL.md +59 -0
  201. package/skills/yc-intent-radar-skill/yc-jobs-scraper/scripts/auth.js +29 -0
  202. package/skills/yc-intent-radar-skill/yc-jobs-scraper/scripts/db.js +62 -0
  203. package/skills/yc-intent-radar-skill/yc-jobs-scraper/scripts/export_radar_candidates.js +40 -0
  204. package/skills/yc-intent-radar-skill/yc-jobs-scraper/scripts/package-lock.json +1525 -0
  205. package/skills/yc-intent-radar-skill/yc-jobs-scraper/scripts/package.json +12 -0
  206. package/skills/yc-intent-radar-skill/yc-jobs-scraper/scripts/scraper.js +217 -0
  207. package/src/e2e.test.ts +35 -0
  208. package/src/fs-adapters.test.ts +91 -0
  209. package/src/fs-adapters.ts +65 -0
  210. package/src/index.ts +182 -0
  211. package/src/transformers.ts +6 -0
  212. package/tsconfig.json +8 -0
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "blog-cover-image-cli",
3
+ "version": "1.0.17",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "blog-cover-cli": "bin/cli.js"
8
+ },
9
+ "directories": {
10
+ "example": "examples"
11
+ },
12
+ "scripts": {
13
+ "test": "echo \"Error: no test specified\" && exit 1"
14
+ },
15
+ "keywords": [],
16
+ "author": "",
17
+ "license": "ISC",
18
+ "type": "module",
19
+ "files": [
20
+ "bin",
21
+ "src",
22
+ "examples",
23
+ "agent-skill",
24
+ "index.js"
25
+ ],
26
+ "dependencies": {
27
+ "@google/genai": "^1.44.0",
28
+ "@inquirer/prompts": "^8.3.0",
29
+ "chalk": "^5.6.2",
30
+ "commander": "^14.0.3",
31
+ "conf": "^15.1.0",
32
+ "dotenv": "^17.3.1",
33
+ "figlet": "^1.11.0",
34
+ "gradient-string": "^3.0.0",
35
+ "sharp": "^0.34.5"
36
+ }
37
+ }
@@ -0,0 +1,126 @@
1
+ import { GoogleGenAI } from '@google/genai';
2
+ import { readFile, readdir } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+
9
+ async function getExampleImages() {
10
+ const examplesDir = path.join(__dirname, '..', 'examples');
11
+ const imageParts = [];
12
+ try {
13
+ const files = await readdir(examplesDir);
14
+ for (const file of files) {
15
+ if (file.match(/\.(png|jpe?g)$/i)) {
16
+ const filePath = path.join(examplesDir, file);
17
+ const buffer = await readFile(filePath);
18
+ const ext = path.extname(file).toLowerCase();
19
+ const mimeType = ext === '.png' ? 'image/png' : 'image/jpeg';
20
+ imageParts.push({
21
+ inlineData: {
22
+ data: buffer.toString('base64'),
23
+ mimeType
24
+ }
25
+ });
26
+ }
27
+ }
28
+ } catch (err) {
29
+ console.warn('Warning: Could not load example images from ./examples directory.', err.message);
30
+ }
31
+ return imageParts;
32
+ }
33
+
34
+ /**
35
+ * Generates a blog cover image using Gemini 3.1 Flash Image Preview.
36
+ *
37
+ * @param {string} title - The title text to include in the image.
38
+ * @param {Object|null} logoData - Optional logo data { data: base64String, mimeType: 'image/png' }.
39
+ * @param {string} [apiKey] - Optional API key.
40
+ * @param {string} [criticalFeedback] - Optional feedback from a previous failed attempt.
41
+ * @returns {Promise<{ base64Image: string, textOutput: string }>} - The base64 encoded image data and any text output.
42
+ */
43
+ export async function generateCoverImage(title, logoData, apiKey, criticalFeedback) {
44
+ const ai = new GoogleGenAI({ apiKey: apiKey || process.env.GEMINI_API_KEY });
45
+ const exampleImages = await getExampleImages();
46
+
47
+ let textPrompt = `
48
+ You are an expert technical marketing designer creating a high-converting, minimalist 16:9 blog cover image. Strictly match the visual aesthetic of the provided example images.
49
+
50
+ CANVAS & TYPOGRAPHY:
51
+ - Use a pure solid white background.
52
+ - Render the text in a heavy, bold, black sans-serif font.
53
+ - Perfectly center-align the text block in the middle of the canvas, leaving generous negative space (padding) around the edges.
54
+ - Break the text naturally into 1 to 3 balanced lines (ABSOLUTE MAXIMUM 3 LINES).
55
+
56
+ THE EXACT TEXT TO RENDER:
57
+ "${title}"
58
+
59
+ LOGO INTEGRATION RULES:
60
+ Carefully analyze the provided reference logo(s) and integrate them into the text flow using these exact rules:
61
+ 1. IF the logo is a 'Wordmark' (it contains the brand's name text): Use it inline to completely replace that specific word in the text string.
62
+ 2. IF the logo is a 'Logomark' (a standalone icon or character): Place it immediately adjacent to the typed brand name in the text.
63
+ 3. TYPOGRAPHIC REPLACEMENT: If an icon is geometrically similar to a letter in the brand name (like the letter 'O'), creatively substitute the letter with the icon.
64
+
65
+ AESTHETIC TOUCHES:
66
+ Keep the composition radically uncluttered. DO NOT add random, unrelated third-party logos or generic floating UI icons unless explicitly requested in the title. The composition MUST be incredibly clean. If you add a UI element, it must make perfect contextual sense. The primary focus must remain on the bold text and the specific requested logo.
67
+ `;
68
+
69
+ if (criticalFeedback) {
70
+ textPrompt += `\nCRITICAL FEEDBACK FROM PREVIOUS ATTEMPT: ${criticalFeedback}. You MUST fix these errors in this new generation or you will be penalized.\n`;
71
+ }
72
+
73
+ const parts = [];
74
+
75
+ // 1. Examples
76
+ if (exampleImages.length > 0) {
77
+ parts.push({ text: 'Here are some reference examples for the desired style and layout:' });
78
+ parts.push(...exampleImages);
79
+ }
80
+
81
+ // 2. Instructions + Title
82
+ parts.push({ text: textPrompt });
83
+
84
+ // 3. Logo
85
+ if (logoData) {
86
+ parts.push({ text: 'Here is the reference logo to include in the image:' });
87
+ parts.push({
88
+ inlineData: {
89
+ data: logoData.data,
90
+ mimeType: logoData.mimeType
91
+ }
92
+ });
93
+ }
94
+
95
+ const contents = [{ role: 'user', parts }];
96
+
97
+ const response = await ai.models.generateContent({
98
+ model: 'gemini-3.1-flash-image-preview',
99
+ contents,
100
+ config: {
101
+ responseModalities: ['TEXT', 'IMAGE'],
102
+ imageConfig: {
103
+ aspectRatio: '16:9',
104
+ numberOfImages: 1
105
+ },
106
+ tools: [{ googleSearch: {} }]
107
+ }
108
+ });
109
+
110
+ let base64Image = null;
111
+ let textOutput = '';
112
+
113
+ for (const part of response.candidates[0].content.parts) {
114
+ if (part.text) {
115
+ textOutput += part.text + '\n';
116
+ } else if (part.inlineData) {
117
+ base64Image = part.inlineData.data;
118
+ }
119
+ }
120
+
121
+ if (!base64Image) {
122
+ throw new Error('No image was generated in the response. Text returned: ' + textOutput);
123
+ }
124
+
125
+ return { base64Image, textOutput };
126
+ }
@@ -0,0 +1,54 @@
1
+ import { GoogleGenAI } from '@google/genai';
2
+
3
+ export async function validateImage(base64Image, title, hasLogo, apiKey) {
4
+ const ai = new GoogleGenAI({ apiKey });
5
+
6
+ const prompt = `
7
+ Analyze this blog cover image and verify if it meets the following CRITICAL requirements:
8
+ 1. TEXT ACCURACY: Does the image contain the exact text: "${title}"? It must be legible and spelled correctly.
9
+ 2. LOGO PRESENCE: ${hasLogo ? 'The image MUST contain the requested company logo.' : 'No specific logo was required.'}
10
+ 3. IMAGE INTEGRITY: Is the image clear and not obviously corrupted or garbled?
11
+ 4. UNWANTED ELEMENTS: Are there any redundant, misplaced, or entirely irrelevant third-party icons or UI elements that don't fit the strict title context? (If yes, the image is INVALID).
12
+
13
+ RELAXED RULES (DO NOT FAIL FOR THESE):
14
+ - Colored text is ALLOWED and ENCOURAGED if it matches the brand.
15
+ - Brand-colored logos are ALLOWED.
16
+ - Minimalist, subtle UI elements are allowed ONLY if they perfectly match the specific requested context.
17
+ - The background does NOT have to be pure white; subtle gradients or brand colors are acceptable.
18
+
19
+ Return a JSON object with:
20
+ - "isValid": boolean (true only if CRITICAL requirements are met)
21
+ - "issues": string (empty if isValid is true, otherwise describe what is wrong)
22
+ `;
23
+
24
+ const contents = [
25
+ {
26
+ role: 'user',
27
+ parts: [
28
+ { text: prompt },
29
+ {
30
+ inlineData: {
31
+ data: base64Image,
32
+ mimeType: 'image/png',
33
+ },
34
+ },
35
+ ],
36
+ },
37
+ ];
38
+
39
+ const response = await ai.models.generateContent({
40
+ model: 'gemini-3.1-pro-preview',
41
+ contents,
42
+ config: {
43
+ responseMimeType: 'application/json',
44
+ },
45
+ });
46
+
47
+ const text = response.candidates[0].content.parts[0].text;
48
+
49
+ try {
50
+ return JSON.parse(text);
51
+ } catch (error) {
52
+ throw new Error(`Failed to parse validation response: ${text}`);
53
+ }
54
+ }
@@ -0,0 +1,86 @@
1
+ import sharp from 'sharp';
2
+
3
+ /**
4
+ * Fetches a logo from a domain or URL and converts it to PNG.
5
+ * @param {string} logoInput - Domain (e.g., 'google.com') or full URL.
6
+ * @param {string} [clientId] - Brandfetch Client ID.
7
+ * @returns {Promise<{ data: string, mimeType: string } | null>}
8
+ */
9
+ export async function fetchLogo(logoInput, clientId) {
10
+ let url;
11
+ const headers = {
12
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
13
+ 'Accept': 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8'
14
+ };
15
+
16
+ if (logoInput.startsWith('http://') || logoInput.startsWith('https://')) {
17
+ url = logoInput;
18
+ } else {
19
+ // Assume it's a domain, use Brandfetch API
20
+ url = `https://cdn.brandfetch.io/domain/${logoInput}/w/820/h/110/theme/dark/logo?c=${clientId}`;
21
+ }
22
+
23
+ try {
24
+ let response;
25
+ if (!logoInput.startsWith('http')) {
26
+ try {
27
+ response = await fetch(url, { headers });
28
+ } catch (e) {
29
+ response = { ok: false, headers: new Headers() };
30
+ }
31
+
32
+ let contentType = response.headers.get('content-type');
33
+ if (!response.ok || !contentType?.includes('image')) {
34
+ const hunterUrl = `https://logos.hunter.io/${logoInput}`;
35
+ try {
36
+ response = await fetch(hunterUrl, { headers });
37
+ } catch (e) {
38
+ response = { ok: false, headers: new Headers() };
39
+ }
40
+
41
+ contentType = response.headers.get('content-type');
42
+ if (!response.ok || !contentType?.includes('image')) {
43
+ const fallbackUrl = `https://icon.horse/icon/${logoInput}`;
44
+ try {
45
+ response = await fetch(fallbackUrl, { headers });
46
+ } catch (e) {
47
+ return null;
48
+ }
49
+
50
+ contentType = response.headers.get('content-type');
51
+ if (!response.ok || !contentType?.includes('image')) {
52
+ return null;
53
+ }
54
+
55
+ if (contentType === 'image/x-icon' || contentType === 'image/vnd.microsoft.icon') {
56
+ throw new Error('Unsupported ICO format');
57
+ }
58
+ }
59
+ }
60
+ } else {
61
+ response = await fetch(url, { headers });
62
+ const contentType = response.headers.get('content-type');
63
+ if (!response.ok || !contentType?.includes('image')) {
64
+ return null;
65
+ }
66
+ }
67
+
68
+ const arrayBuffer = await response.arrayBuffer();
69
+ const buffer = Buffer.from(arrayBuffer);
70
+
71
+ // Convert to PNG using sharp
72
+ const pngBuffer = await sharp(buffer)
73
+ .png()
74
+ .toBuffer();
75
+
76
+ const base64String = pngBuffer.toString('base64');
77
+
78
+ return {
79
+ data: base64String,
80
+ mimeType: 'image/png'
81
+ };
82
+ } catch (error) {
83
+ console.error(`Error fetching logo:`, error.message);
84
+ return null;
85
+ }
86
+ }
@@ -0,0 +1,7 @@
1
+ # claude-md-generator — Environment Variables
2
+ # =============================================
3
+ # Gemini is required for generating the CLAUDE.md content from analysis.
4
+
5
+ # Required: Google Gemini API key for CLAUDE.md generation
6
+ # Get it: aistudio.google.com, Get API key
7
+ GEMINI_API_KEY=your_gemini_api_key_here
@@ -0,0 +1,78 @@
1
+ # claude-md-generator
2
+
3
+ <img width="1280" height="640" alt="claude-md-generator" src="https://github.com/user-attachments/assets/0e295271-2216-47f7-828f-845c98ef0298" />
4
+
5
+
6
+ Reads your codebase and writes a CLAUDE.md that gives Claude Code the context it needs: build commands, code conventions, architecture notes, and gotchas. Stays under 200 lines.
7
+
8
+ ## What It Does
9
+
10
+ - Scans project files: package.json, tsconfig.json, linter configs, Makefile, directory structure
11
+ - Extracts all build, test, lint, and dev commands
12
+ - Identifies code style conventions that differ from defaults (path aliases, export patterns, naming)
13
+ - Maps non-obvious architecture decisions
14
+ - Finds gotchas: auto-generated files, required env var setup, test dependencies
15
+ - Generates CLAUDE.md using Gemini, then verifies it stays under 200 lines
16
+ - If CLAUDE.md already exists, improves it without discarding custom content
17
+
18
+ ## Requirements
19
+
20
+ | Requirement | Purpose | How to Set Up |
21
+ |------------|---------|--------------|
22
+ | Gemini API key | CLAUDE.md generation from codebase analysis | aistudio.google.com, Get API key |
23
+
24
+ ## Setup
25
+
26
+ ```bash
27
+ cp .env.example .env
28
+ # Add GEMINI_API_KEY
29
+ ```
30
+
31
+ ## How to Use
32
+
33
+ From the project root you want to document:
34
+ ```
35
+ "Generate a CLAUDE.md for this project"
36
+ "Create a CLAUDE.md"
37
+ "Write Claude configuration for this repo"
38
+ "Help Claude understand this codebase"
39
+ ```
40
+
41
+ To update an existing CLAUDE.md:
42
+ ```
43
+ "Update my CLAUDE.md: we added Vitest and changed the build system"
44
+ "Improve my existing CLAUDE.md"
45
+ ```
46
+
47
+ ## What Goes in CLAUDE.md
48
+
49
+ | Section | Include | Skip |
50
+ |---------|---------|------|
51
+ | Commands | Exact runnable commands, flags needed, env vars required | `npm install` and other obvious ones |
52
+ | Architecture | Non-obvious structure, auto-generated directories | "src contains source files" |
53
+ | Code Style | Path aliases, export conventions, non-default settings | Indent size (formatter handles it) |
54
+ | Testing | Required setup, how to run one test | "we use Jest" (visible from package.json) |
55
+ | Gotchas | Auto-generated files, env var order, known intentional issues | Things derivable from the code |
56
+
57
+ ## Why Under 200 Lines
58
+
59
+ Long CLAUDE.md files get ignored. Claude loads the full file into context every session: a bloated CLAUDE.md with obvious content trains Claude to skim it. A tight 100-150 line CLAUDE.md with only non-obvious facts gets read and used.
60
+
61
+ The skill cuts aggressively: if a section says only things Claude can infer from the code, it removes it.
62
+
63
+ ## Project Structure
64
+
65
+ ```
66
+ claude-md-generator/
67
+ ├── SKILL.md
68
+ ├── README.md
69
+ ├── .env.example
70
+ ├── evals/
71
+ │ └── evals.json
72
+ └── references/
73
+ └── section-guide.md
74
+ ```
75
+
76
+ ## License
77
+
78
+ MIT
@@ -0,0 +1,254 @@
1
+ ---
2
+ name: claude-md-generator
3
+ description: ''
4
+ compatibility: [claude-code, gemini-cli, github-copilot]
5
+ author: OpenDirectory
6
+ version: 1.0.0
7
+ ---
8
+
9
+ # CLAUDE.md Generator
10
+
11
+ Read the codebase. Write a CLAUDE.md that tells Claude exactly what it needs: no more, no less.
12
+
13
+ ---
14
+
15
+ **Critical rule:** A good CLAUDE.md is under 100 lines. It contains only information Claude cannot derive from reading the code itself. Do not auto-write the file: always show the draft and wait for user approval first.
16
+
17
+ **Code snippet rule:** Never include inline code examples in CLAUDE.md. Instead use `file.ts:42` references. Code in CLAUDE.md wastes tokens and goes stale.
18
+
19
+ ---
20
+
21
+ ## Step 1: Detect Mode
22
+
23
+ Determine which of three modes to run:
24
+
25
+ **create**: No CLAUDE.md exists. Write one from scratch.
26
+ **update**: A CLAUDE.md exists. Improve it without discarding custom content.
27
+ **audit**: Score all CLAUDE.md files in the project A-F and output a quality report. If the user says "audit", "check", "review", or "grade" my CLAUDE.md, run audit mode.
28
+
29
+ ```bash
30
+ # Discover ALL CLAUDE.md locations
31
+ find . -name "CLAUDE.md" -not -path "*/node_modules/*" -not -path "*/.git/*" 2>/dev/null
32
+ ls ~/.claude/CLAUDE.md 2>/dev/null && echo "Global CLAUDE.md found"
33
+ ls .claude.local.md 2>/dev/null && echo ".claude.local.md found"
34
+ ```
35
+
36
+ If multiple CLAUDE.md files are found: list them. Ask: "Found CLAUDE.md in [locations]. Should I update all of them or just [root]?"
37
+
38
+ ---
39
+
40
+ ## Step 2: Audit Mode (skip to Step 3 if create/update)
41
+
42
+ For each CLAUDE.md found, score it A-F using this rubric:
43
+
44
+ | Criterion | What to check |
45
+ |-----------|--------------|
46
+ | Commands | Build/test/lint commands present and runnable? |
47
+ | Architecture | Non-obvious structure explained? |
48
+ | Non-obvious patterns | Gotchas, generated files, env var order documented? |
49
+ | Conciseness | Under 100 lines? No obvious filler? |
50
+ | Currency | Commands still match current package.json/Makefile? |
51
+ | Actionability | Can a new contributor follow this without asking questions? |
52
+
53
+ Score: 90-100 = A, 70-89 = B, 50-69 = C, 30-49 = D, 0-29 = F
54
+
55
+ Present as a table:
56
+
57
+ ```
58
+ ## CLAUDE.md Audit Report
59
+
60
+ | File | Score | Grade | Top Issues |
61
+ |------|-------|-------|-----------|
62
+ | ./CLAUDE.md | 72 | B | Missing gotchas section, test command outdated |
63
+ | ./packages/api/CLAUDE.md | 45 | D | No commands, 340 lines (too long), stale arch notes |
64
+
65
+ **Overall: B (72/100)**
66
+
67
+ Issues found:
68
+ - ./packages/api/CLAUDE.md: 340 lines: well over the 100-line target
69
+ - ./packages/api/CLAUDE.md: Test command references `jest` but package.json uses `vitest`
70
+ - ./CLAUDE.md: No Gotchas section: most valuable section is missing
71
+ ```
72
+
73
+ After the report, ask: "Want me to fix any of these? (all / just root / specify)"
74
+
75
+ If user says yes, continue to Step 3 for each file they want fixed.
76
+
77
+ ---
78
+
79
+ ## Step 3: Scan Project Structure
80
+
81
+ ```bash
82
+ # Project type and package manager
83
+ ls package.json yarn.lock pnpm-lock.yaml bun.lockb requirements.txt pyproject.toml Cargo.toml go.mod 2>/dev/null
84
+
85
+ # Top-level directory structure
86
+ find . -maxdepth 2 -type d \
87
+ | grep -v node_modules | grep -v .git | grep -v __pycache__ \
88
+ | grep -v ".next" | grep -v dist | grep -v build | sort
89
+ ```
90
+
91
+ ---
92
+
93
+ ## Step 4: Extract Build and Test Commands
94
+
95
+ ```bash
96
+ # npm/yarn/pnpm/bun scripts
97
+ cat package.json 2>/dev/null \
98
+ | python3 -c "
99
+ import sys, json
100
+ d = json.load(sys.stdin)
101
+ for name, cmd in d.get('scripts', {}).items():
102
+ print(f'{name}: {cmd}')
103
+ "
104
+
105
+ # Python, Go, Rust Makefiles
106
+ cat Makefile 2>/dev/null | grep -E "^[a-z].*:" | head -20
107
+
108
+ # Go
109
+ cat go.mod 2>/dev/null | head -5
110
+
111
+ # Rust
112
+ cat Cargo.toml 2>/dev/null | grep -E "^\[" | head -10
113
+ ```
114
+
115
+ Identify the exact commands for: build, test (all), test (single file/name), dev server, lint/typecheck. Note any env vars required to run them.
116
+
117
+ ---
118
+
119
+ ## Step 5: Find Code Style and Gotchas
120
+
121
+ ```bash
122
+ # Import aliases (most commonly missed)
123
+ python3 -c "
124
+ import json, sys
125
+ try:
126
+ d = json.load(open('tsconfig.json'))
127
+ paths = d.get('compilerOptions', {}).get('paths', {})
128
+ if paths: print('Import aliases:', json.dumps(paths, indent=2))
129
+ except: pass
130
+ " 2>/dev/null
131
+
132
+ # Environment variables required
133
+ cat .env.example 2>/dev/null | grep -v "^#" | grep -v "^$" | head -20
134
+
135
+ # Auto-generated files (must not be edited)
136
+ find . -path "*/node_modules" -prune -o -name "*.ts" -print \
137
+ | xargs grep -l "DO NOT EDIT\|@generated\|Generated by" 2>/dev/null | head -5
138
+
139
+ # Test setup requirements
140
+ cat jest.config.js jest.config.ts vitest.config.ts 2>/dev/null | head -30
141
+
142
+ # Database/migration setup
143
+ ls migrations/ prisma/ drizzle/ db/ 2>/dev/null
144
+ ```
145
+
146
+ **What counts as a Gotcha** (include these, skip everything else):
147
+ - Files that are auto-generated (must not edit)
148
+ - Env vars required BEFORE tests run
149
+ - Non-default import alias mappings
150
+ - Test commands that require a running service
151
+ - Known intentional quirks (workarounds, not bugs)
152
+
153
+ ---
154
+
155
+ ## Step 6: Generate CLAUDE.md Draft with Gemini
156
+
157
+ Compile all findings and generate the draft:
158
+
159
+ ```bash
160
+ cat > /tmp/claude-md-request.json << 'ENDJSON'
161
+ {
162
+ "system_instruction": {
163
+ "parts": [{
164
+ "text": "Write a CLAUDE.md file for a software project. Rules: (1) Under 100 lines total. (2) Only include what Claude cannot derive from reading the code. (3) No inline code examples: use file.ts:42 references instead. (4) Sections: Commands, Code Style (only non-defaults), Testing (only if setup needed), Gotchas (required: what trips people up). Skip any section that has nothing non-obvious to say. (5) All commands in code blocks. (6) Preferred order: short Project Overview (1-2 sentences, only if non-obvious), Commands, Architecture (only non-obvious structure), Code Style, Testing, Gotchas. (7) Do not use em dashes. (8) Output only the CLAUDE.md content, no commentary."
165
+ }]
166
+ },
167
+ "contents": [{
168
+ "parts": [{
169
+ "text": "PROJECT_ANALYSIS_HERE"
170
+ }]
171
+ }],
172
+ "generationConfig": {
173
+ "temperature": 0.3,
174
+ "maxOutputTokens": 2048
175
+ }
176
+ }
177
+ ENDJSON
178
+
179
+ curl -s -X POST \
180
+ "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=$GEMINI_API_KEY" \
181
+ -H "Content-Type: application/json" \
182
+ -d @/tmp/claude-md-request.json \
183
+ | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['candidates'][0]['content']['parts'][0]['text'])"
184
+ ```
185
+
186
+ Replace `PROJECT_ANALYSIS_HERE` with findings from Steps 3-5.
187
+
188
+ **For large projects (50+ files):** Add a `@path` pointer at the bottom of CLAUDE.md instead of inline detail:
189
+
190
+ ```markdown
191
+ ## Extended Reference
192
+ See @docs/ai-context/architecture.md for full module map.
193
+ See @docs/ai-context/testing.md for integration test setup details.
194
+ ```
195
+
196
+ Write the referenced files to `docs/ai-context/` with the detail that would not fit in 100 lines.
197
+
198
+ ---
199
+
200
+ ## Step 7: Self-QA
201
+
202
+ Before presenting the draft, check:
203
+
204
+ - [ ] Under 100 lines (count: `echo "$CONTENT" | wc -l`)
205
+ - [ ] No inline code examples (only `file.ts:42` references or shell commands)
206
+ - [ ] All commands in code blocks and runnable as-is
207
+ - [ ] Gotchas section present with at least one real entry
208
+ - [ ] No section that says only things obvious from the files
209
+ - [ ] No em dashes
210
+ - [ ] No marketing words or filler phrases ("This project uses React to...")
211
+ - [ ] Import aliases documented if they exist
212
+ - [ ] Auto-generated files marked "do not edit" if they exist
213
+
214
+ If any check fails, revise before presenting.
215
+
216
+ ---
217
+
218
+ ## Step 8: Present Draft and Wait for Approval
219
+
220
+ **Never write the file without user approval.**
221
+
222
+ Present the draft in a code block:
223
+
224
+ ```
225
+ ## Draft CLAUDE.md ([N] lines)
226
+
227
+ [full draft content here]
228
+
229
+ ---
230
+ Write this to CLAUDE.md? (yes / edit first / cancel)
231
+ ```
232
+
233
+ If user says **yes**: write the file, then confirm:
234
+ "CLAUDE.md written ([N] lines). Sections: [list of ## headers]."
235
+
236
+ If user says **edit first**: apply their edits, re-show the draft.
237
+
238
+ If user says **cancel**: stop.
239
+
240
+ ---
241
+
242
+ ## What NOT to Include
243
+
244
+ - Language/framework version ("This is a TypeScript project")
245
+ - How the framework works (Claude already knows React, FastAPI, etc.)
246
+ - List of all dependencies
247
+ - Style rules the linter already enforces (indent size, quote style)
248
+ - Content that duplicates README.md
249
+ - Inline code examples or multi-line snippets
250
+ - Anything that would be identical for any project using the same stack
251
+
252
+
253
+
254
+
@@ -0,0 +1,35 @@
1
+ {
2
+ "skill_name": "claude-md-generator",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "Generate a CLAUDE.md for this project.",
7
+ "expected_output": "Agent runs all scan commands from Steps 1-5: directory structure, package.json scripts, tsconfig.json, ESLint config, test setup, .env.example. Calls Gemini with analysis to generate CLAUDE.md. Output is under 200 lines. Contains: Commands section with exact runnable commands, Code Style section noting any non-default aliases or export conventions, Testing section with any required setup, Gotchas section with at least one entry (auto-generated files, required env vars, etc.). Does not include obvious facts derivable from the files (e.g., 'This project uses TypeScript').",
8
+ "files": ["package.json", "tsconfig.json", ".eslintrc.json", ".env.example"]
9
+ },
10
+ {
11
+ "id": 2,
12
+ "prompt": "Create a CLAUDE.md. The project already has one.",
13
+ "expected_output": "Agent detects existing CLAUDE.md at project root. Reads it before generating. Preserves any sections the user has manually added. Improves sections that are outdated or missing. Shows a diff summary: 'Kept: [sections]. Updated: [sections]. Added: [sections].' Final file is still under 200 lines. Does not wholesale replace the existing file without showing what changed.",
14
+ "files": ["CLAUDE.md", "package.json"]
15
+ },
16
+ {
17
+ "id": 3,
18
+ "prompt": "Write a CLAUDE.md for this Python project.",
19
+ "expected_output": "Agent detects Python project from requirements.txt or pyproject.toml. Reads Makefile or pyproject.toml for commands. Identifies test runner (pytest, unittest). Notes any virtual environment setup required. Checks for generated files (migrations, protobuf stubs). Commands section shows exact Python commands (pytest, python -m, etc.). Gotchas section notes any required env vars and any generated files that should not be edited.",
20
+ "files": ["requirements.txt", "pyproject.toml", "Makefile"]
21
+ },
22
+ {
23
+ "id": 4,
24
+ "prompt": "Generate CLAUDE.md for this monorepo.",
25
+ "expected_output": "Agent detects monorepo from presence of packages/ or apps/ directory with multiple package.json files. Notes workspace structure in Architecture section. Documents root-level commands vs package-level commands. Notes any shared packages and how they are linked. Keeps the output under 200 lines by focusing on the most important commands and conventions. Does not try to document every package: focuses on the top-level patterns and the most commonly developed packages.",
26
+ "files": ["package.json", "packages/"]
27
+ },
28
+ {
29
+ "id": 5,
30
+ "prompt": "Create a CLAUDE.md. There are no config files: it's a small Go project with just main.go and a Makefile.",
31
+ "expected_output": "Agent finds main.go and Makefile. Reads Makefile for build/test/run targets. Notes that there is no package manager. Commands section shows make targets. Architecture section notes entry point (main.go). Gotchas section notes any env vars referenced in main.go. Output is short (under 50 lines) because there is not much to document: the agent does not pad with filler content. Does not invent sections for things that do not exist in this project.",
32
+ "files": ["main.go", "Makefile"]
33
+ }
34
+ ]
35
+ }