forkfeed-mcp 1.0.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.
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Condensed skill guide for generating forkfeed content from GitHub commits.
3
+ * Returned by the forkfeed_guide tool. This is the single-read reference
4
+ * that teaches Claude how to generate a valid manifest.
5
+ */
6
+ export declare const GUIDE_CONTENT: string;
@@ -0,0 +1,233 @@
1
+ /**
2
+ * Condensed skill guide for generating forkfeed content from GitHub commits.
3
+ * Returned by the forkfeed_guide tool. This is the single-read reference
4
+ * that teaches Claude how to generate a valid manifest.
5
+ */
6
+ export const GUIDE_CONTENT = `
7
+ # Forkfeed Content Guide - "The Fuck I Pushed"
8
+
9
+ Turn GitHub commits into swipeable card content. One fork per repo, one feed per commit, 8 cards per feed (35-62 variants total).
10
+
11
+ ## Quick start
12
+
13
+ 1. Ask which repo and commits to process
14
+ 2. Fetch commit data via git or gh CLI
15
+ 3. Generate 8-card manifest JSON
16
+ 4. Call forkfeed_push with the manifest
17
+
18
+ ---
19
+
20
+ ## Phase 1: Resolve repo and commits
21
+
22
+ Use the **current working directory** as the repo. Do not ask which repo.
23
+
24
+ If the user didn't specify commits, use the latest commit. Otherwise respect what they asked (last N, specific SHA, since date).
25
+
26
+ Use **IT Scenes** images. Call **forkfeed_images** to get the full catalog (200 scene images + 30 backgrounds). Match images to content by tags and semantic similarity. Do not ask about image style.
27
+
28
+ ---
29
+
30
+ ## Phase 2: Fetch commit data
31
+
32
+ ### GitHub repos
33
+ \`\`\`bash
34
+ # Verify access
35
+ gh api repos/{owner}/{repo} --jq '.full_name'
36
+
37
+ # Metadata
38
+ gh api repos/{owner}/{repo}/commits/{sha} --jq '{sha: .sha, shortSha: (.sha[:7]), message: .commit.message, author: .commit.author.name, date: .commit.author.date, additions: .stats.additions, deletions: .stats.deletions, totalFiles: (.files | length)}'
39
+
40
+ # Full diff
41
+ gh api repos/{owner}/{repo}/commits/{sha} -H "Accept: application/vnd.github.v3.diff"
42
+
43
+ # README for fork title/description
44
+ gh api repos/{owner}/{repo} --jq '.description'
45
+ \`\`\`
46
+
47
+ ### Local repos
48
+ \`\`\`bash
49
+ git -C "{path}" log -1 --format='{"sha":"%H","shortSha":"%h","message":"%s","author":"%an","date":"%aI"}' {sha}
50
+ git -C "{path}" diff --stat {sha}^..{sha}
51
+ git -C "{path}" diff {sha}^..{sha}
52
+ \`\`\`
53
+
54
+ Skip merge commits (>1 parent) unless it's the only commit.
55
+
56
+ ---
57
+
58
+ ## Phase 3: Generate manifest
59
+
60
+ ### ID conventions
61
+ - Fork: \`tfip-{owner}-{repo}\` or \`tfip-local-{dirname}\`
62
+ - Feed: \`tfip-{owner}-{repo}-{7char-sha}\`
63
+ - Card: UUID v4 (generate upfront with \`node -e "for(let i=0;i<N;i++) process.stdout.write(require('crypto').randomUUID()+'\\n')"\`)
64
+
65
+ All IDs must match \`/^[a-z0-9-]+$/\` (except card UUIDs).
66
+
67
+ ### JSON structure
68
+ \`\`\`json
69
+ {
70
+ "forks": [{
71
+ "_id": "tfip-owner-repo",
72
+ "title": "Project Name (from README)",
73
+ "description": "What the project IS",
74
+ "imageSrc": "same as card 0 cover image",
75
+ "feedIds": ["tfip-owner-repo-abc1234"],
76
+ "actionLabel": "View on GitHub",
77
+ "actionUrl": "https://github.com/owner/repo"
78
+ }],
79
+ "feeds": [{
80
+ "_id": "tfip-owner-repo-abc1234",
81
+ "title": "Human-readable headline (max 60 chars)",
82
+ "description": "Mon DD: one-line impact summary",
83
+ "imageSrc": "same as card 0 cover image",
84
+ "mode": "sequential",
85
+ "scrollDirection": "vertical",
86
+ "engagement": true
87
+ }],
88
+ "cards": [
89
+ {
90
+ "_id": "uuid-v4",
91
+ "feedId": "tfip-owner-repo-abc1234",
92
+ "order": 0,
93
+ "variants": [
94
+ { "type": "FULL_IMAGE", "imageSrc": "url", "title": "Section name", "subtitle": "Hook text (max 200 chars)" },
95
+ { "type": "CONTENT", "backgroundSrc": "url", "blocks": [...] }
96
+ ]
97
+ }
98
+ ]
99
+ }
100
+ \`\`\`
101
+
102
+ ### The 8 cards (sections)
103
+
104
+ Each card: variant[0] = FULL_IMAGE cover, variant[1+] = CONTENT details.
105
+
106
+ | # | Section | Detail variants | Block pattern | Tone |
107
+ |---|---------|----------------|---------------|------|
108
+ | 0 | Explain like I'm 5 | 3-6 | IMAGE(wide) -> TITLE -> TEXT | Playful, zero jargon |
109
+ | 1 | The roast | 3-6 | IMAGE(wide) -> TITLE -> TEXT, optional SUBTEXT | Maximum cheekiness, swearing ok |
110
+ | 2 | Commit message, decoded | 2-4 | SOCIAL -> TITLE -> TEXT -> optional CODE | Escalating absurdity |
111
+ | 3 | The LinkedIn post | 2-4 | SOCIAL -> TITLE -> TEXT -> SUBTEXT | Peak LinkedIn parody |
112
+ | 4 | Statistics | 3-5 | IMAGE(wide) -> TITLE -> CODE | Deadpan data humor |
113
+ | 5 | Learning moment | 3-8 | IMAGE(wide) -> TITLE -> TEXT -> optional CODE -> BUTTON(last) | Teach with personality |
114
+ | 6 | Alternatives | 3-6 | IMAGE(wide) -> TITLE -> TEXT -> optional CODE | Constructive snark |
115
+ | 7 | Quiz | 10-15 | TITLE -> QUIZ (no IMAGE) | Quiz show energy |
116
+
117
+ ### Content block types
118
+
119
+ \`\`\`typescript
120
+ // CONTENT_IMAGE - inline image
121
+ { type: "CONTENT_IMAGE", imageSrc: "url", sizing: "wide" }
122
+
123
+ // CONTENT_TITLE - section heading (required in every detail variant, sentence case)
124
+ { type: "CONTENT_TITLE", title: "Feature detection pattern" }
125
+
126
+ // CONTENT_TEXT - paragraph (50-200 words, use \\n\\n for breaks)
127
+ { type: "CONTENT_TEXT", text: "..." }
128
+
129
+ // CONTENT_CODE - code snippet (real from diff, 5-20 lines, strip +/- prefixes)
130
+ { type: "CONTENT_CODE", code: "...", language: "typescript" }
131
+
132
+ // CONTENT_SOCIAL - persona post (Cards 2-3 only, replaces IMAGE)
133
+ { type: "CONTENT_SOCIAL", avatarSrc: "url", name: "Chad Gitpush", subtitle: "10x Engineer", source: "linkedin" }
134
+
135
+ // CONTENT_SUBTEXT - aside or protip
136
+ { type: "CONTENT_SUBTEXT", text: "..." }
137
+
138
+ // CONTENT_QUIZ - quiz question (Card 7 only, exactly 4 options, one correct)
139
+ { type: "CONTENT_QUIZ", question: "...", options: [{ label: "A", correct: false }, ...], explanation: "..." }
140
+
141
+ // CONTENT_BUTTON - action button (Card 5 only, MUST be last block)
142
+ { type: "CONTENT_BUTTON", label: "Google it", action: "url", target: "https://www.google.com/search?q=topic+here" }
143
+ \`\`\`
144
+
145
+ ### Card 2 personas (Decoded)
146
+ - "What you meant" (source: "x" or "threads")
147
+ - "Corporate speak" (source: "linkedin")
148
+ - Optional: "Shakespearean" (source: "x"), "Military briefing" (source: "x")
149
+
150
+ ### Card 3 personas (LinkedIn)
151
+ - Chad Gitpush: "10x Engineer | Building in Public | DMs Open"
152
+ - Alexandra Middleware: "VP of Forward Thinking at TechCorp"
153
+ - Dave 'Shipping' Johnson: "Just a humble engineer doing humble things"
154
+
155
+ ### Key rules
156
+ - All CONTENT variants in a card share the same backgroundSrc
157
+ - 8 unique backgroundSrc values across the 8 cards
158
+ - 8 unique FULL_IMAGE cover imageSrc values
159
+ - Cards 0-5: code must be REAL from the diff (never fabricated)
160
+ - Card 6: synthesized code IS allowed
161
+ - Card 7: no code blocks, no CONTENT_IMAGE
162
+ - Card 5: every detail variant MUST end with CONTENT_BUTTON
163
+ - CONTENT_QUIZ: exactly 4 options, exactly one correct: true, explanation required
164
+ - No em dashes, smart quotes, or non-ASCII characters
165
+ - Top-level key MUST be "forks" (plural array)
166
+
167
+ ### IT Scenes images
168
+
169
+ Call **forkfeed_images** to get the full catalog. 200 scene images (img1-img200) for covers and inline images, 30 backgrounds (bg1-bg30) for card backgrounds.
170
+
171
+ **Matching rules:**
172
+ 1. Identify commit tags from the diff: deploy, git, disaster, debug, hype, victory, beginner, language, lifestyle, workplace, sarcastic, general
173
+ 2. Filter images by tag overlap
174
+ 3. Rank by semantic similarity to card content (title, text, code topics)
175
+ 4. Assign best match, remove from pool (no duplicates)
176
+
177
+ **Uniqueness rules:**
178
+ - 8 unique scene images for FULL_IMAGE covers (one per card)
179
+ - Detail CONTENT_IMAGE must differ from the card's cover
180
+ - No two detail variants in the same card share a CONTENT_IMAGE
181
+ - 8 unique bg* images for backgroundSrc (one per card)
182
+ - Pick 16-25 unique images per feed
183
+
184
+ **BG preferences per section:**
185
+ - ELI5 (0): bg10, bg27 | Roast (1): bg11, bg1 | Decoded (2): bg20, bg11
186
+ - LinkedIn (3): bg25, bg24 | Statistics (4): bg9, bg3 | Learning (5): match tech
187
+ - Alternatives (6): bg25, bg30 | Quiz (7): bg18, bg5
188
+
189
+ **Fork/feed imageSrc** = Card 0's FULL_IMAGE imageSrc
190
+
191
+ ### Tone
192
+ Casual, cheeky, technically accurate. Like your funniest friend reviewing your code.
193
+ - Use "you" directly
194
+ - Short paragraphs
195
+ - Contractions
196
+ - Swear occasionally for emphasis
197
+ - Humor is the default
198
+
199
+ ### Incremental updates
200
+ If the user has pushed before (check with forkfeed_status), generate only NEW feeds/cards. Prepend new feed IDs to the fork's feedIds array. Never regenerate existing commits.
201
+
202
+ ---
203
+
204
+ ## Phase 4: Push
205
+
206
+ After generating the manifest JSON, call the **forkfeed_push** tool with it:
207
+ \`\`\`
208
+ forkfeed_push({ manifest: { forks: [...], feeds: [...], cards: [...] } })
209
+ \`\`\`
210
+
211
+ Content starts as **private**. The user can make it public from the forkfeed mobile app (requires admin approval).
212
+
213
+ ---
214
+
215
+ ## Validation checklist (verify before pushing)
216
+
217
+ - [ ] Fork/feed IDs match /^[a-z0-9-]+$/
218
+ - [ ] Card IDs are valid UUID v4
219
+ - [ ] Every card.feedId matches an actual feed._id
220
+ - [ ] Fork.feedIds match actual feed._id values
221
+ - [ ] Top-level key is "forks" (plural array)
222
+ - [ ] Card order values are sequential 0-7
223
+ - [ ] Each card has >= 2 variants
224
+ - [ ] variant[0] is FULL_IMAGE with imageSrc, title, subtitle
225
+ - [ ] variant[1+] are CONTENT with backgroundSrc and blocks
226
+ - [ ] FULL_IMAGE subtitle max 200 chars
227
+ - [ ] Feed title max 60 chars
228
+ - [ ] Feed mode: "sequential", scrollDirection: "vertical", engagement: true
229
+ - [ ] CONTENT_QUIZ: exactly 4 options, one correct, explanation required
230
+ - [ ] Card 5 detail variants end with CONTENT_BUTTON
231
+ - [ ] 8 unique cover images, 8 unique backgrounds
232
+ - [ ] No em dashes or smart quotes
233
+ `.trim();