@orbitant/brain-marketing 1.5.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,144 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Downloads curated blog thumbnail images from orbitant.com for visual
5
+ * pattern analysis. Safe to re-run — skips existing files.
6
+ *
7
+ * Usage:
8
+ * node scrape-insights-images.mjs [OPTIONS]
9
+ *
10
+ * Options:
11
+ * --force Re-download all images even if they already exist
12
+ * --help Show this help message
13
+ */
14
+
15
+ import { writeFile, mkdir, access } from "node:fs/promises";
16
+ import { basename, join } from "node:path";
17
+ import { fileURLToPath } from "node:url";
18
+ import { dirname } from "node:path";
19
+
20
+ const __dirname = dirname(fileURLToPath(import.meta.url));
21
+ const OUTPUT_DIR = join(__dirname, "..", "assets", "reference");
22
+ const BATCH_SIZE = 5;
23
+
24
+ // Curated list of AI-generated conceptual metaphor images that represent
25
+ // the target visual style. To add a new reference image, append its full URL.
26
+ const IMAGE_URLS = [
27
+ "https://orbitant.com/wp-content/uploads/2025/09/2025-09-02-desarrollo-software-personalizado.jpg",
28
+ "https://orbitant.com/wp-content/uploads/2025/09/2025-09-04-legacy-system-migration.jpg",
29
+ "https://orbitant.com/wp-content/uploads/2025/09/2025-09-09-DevOps-enterprise.jpg",
30
+ "https://orbitant.com/wp-content/uploads/2025/09/2025-09-11-Fearless-Software-Development.jpg",
31
+ "https://orbitant.com/wp-content/uploads/2025/09/2025-09-16-Inteligencia-artificial-para-empresas.jpg",
32
+ "https://orbitant.com/wp-content/uploads/2025/09/2025-09-18-gestion-de-errores-en-service-bus.jpg",
33
+ "https://orbitant.com/wp-content/uploads/2025/09/2025-09-23-transformacion-digital-negocio.jpg",
34
+ "https://orbitant.com/wp-content/uploads/2025/09/2025-09-25-value-of-software-business-impact.jpg",
35
+ "https://orbitant.com/wp-content/uploads/2025/09/2025-09-30-Strategic-UX-design.jpg",
36
+ "https://orbitant.com/wp-content/uploads/2025/10/2025-10-07-1-Arquitectura-desacoplada-1.jpg",
37
+ "https://orbitant.com/wp-content/uploads/2025/10/2025-10-09-ataques-npm-IA-1.jpg",
38
+ "https://orbitant.com/wp-content/uploads/2025/10/2025-10-14-CI-CD-1.jpg",
39
+ "https://orbitant.com/wp-content/uploads/2025/10/2025-10-16-Running-Legacy-Systems-During-Migration.jpg",
40
+ "https://orbitant.com/wp-content/uploads/2025/11/2025-10-28-errores-comunes-transformacion-digital.jpg",
41
+ "https://orbitant.com/wp-content/uploads/2025/10/2025-10-30-refactorizacion.jpg",
42
+ "https://orbitant.com/wp-content/uploads/2025/11/2025-11-13-5-Tips-for-Successful-Legacy-Migrations.jpg",
43
+ "https://orbitant.com/wp-content/uploads/2025/11/2025-11-18-lanzar-producto-digital-mid-market.jpg",
44
+ "https://orbitant.com/wp-content/uploads/2025/11/2025-11-27-The-Knowns-and-Unknowns-framework.jpg",
45
+ "https://orbitant.com/wp-content/uploads/2025/12/2025-12-04-Vulnerabilidad-critica-React-Server-Components-1.jpg",
46
+ "https://orbitant.com/wp-content/uploads/2025/12/2025-12-25-plug-play-business.jpg",
47
+ "https://orbitant.com/wp-content/uploads/2026/01/2026-01-06-clean-architecture.jpg",
48
+ "https://orbitant.com/wp-content/uploads/2026/01/2026-01-08-cambiar-un-microservicio.jpg",
49
+ "https://orbitant.com/wp-content/uploads/2026/01/2026-01-22-lodash-CVE-2025-13465.jpg",
50
+ "https://orbitant.com/wp-content/uploads/2026/01/2026-01-29-memory-leak-en-nodejs-debugging-fpolo.jpg",
51
+ "https://orbitant.com/wp-content/uploads/2026/02/2026-02-05-writing-tickets-with-IA.jpg",
52
+ "https://orbitant.com/wp-content/uploads/2026/03/2026-02-26-Building-your-best-knowledge-base-1.jpg",
53
+ ];
54
+
55
+ async function fileExists(path) {
56
+ try {
57
+ await access(path);
58
+ return true;
59
+ } catch {
60
+ return false;
61
+ }
62
+ }
63
+
64
+ async function downloadImage(url, outputDir, force) {
65
+ const filename = basename(new URL(url).pathname);
66
+ const filepath = join(outputDir, filename);
67
+
68
+ if (!force && (await fileExists(filepath))) {
69
+ return "skipped";
70
+ }
71
+
72
+ try {
73
+ const res = await fetch(url);
74
+ if (!res.ok) {
75
+ console.error(` FAIL [${res.status}] ${filename}`);
76
+ return "failed";
77
+ }
78
+ const buffer = Buffer.from(await res.arrayBuffer());
79
+ await writeFile(filepath, buffer);
80
+ console.log(
81
+ ` OK ${filename} (${(buffer.length / 1024).toFixed(0)} KB)`
82
+ );
83
+ return "downloaded";
84
+ } catch (err) {
85
+ console.error(` FAIL ${filename}: ${err.message}`);
86
+ return "failed";
87
+ }
88
+ }
89
+
90
+ function printHelp() {
91
+ console.log(`Usage: node scrape-insights-images.mjs [OPTIONS]
92
+
93
+ Downloads curated blog thumbnail images from orbitant.com into
94
+ assets/reference/ for visual pattern analysis. Safe to re-run.
95
+
96
+ Options:
97
+ --force, -f Re-download all images even if they already exist
98
+ --help, -h Show this help message
99
+
100
+ Examples:
101
+ node scrape-insights-images.mjs # Download only missing images
102
+ node scrape-insights-images.mjs --force # Re-download everything`);
103
+ }
104
+
105
+ async function main() {
106
+ const args = process.argv.slice(2);
107
+
108
+ if (args.some((a) => a === "--help" || a === "-h")) {
109
+ printHelp();
110
+ process.exit(0);
111
+ }
112
+
113
+ const force = args.some((a) => a === "--force" || a === "-f");
114
+
115
+ await mkdir(OUTPUT_DIR, { recursive: true });
116
+
117
+ console.log(
118
+ `Downloading ${IMAGE_URLS.length} reference images${force ? " (force mode)" : ""} to ${OUTPUT_DIR}\n`
119
+ );
120
+
121
+ let downloaded = 0;
122
+ let skipped = 0;
123
+ let failed = 0;
124
+
125
+ for (let i = 0; i < IMAGE_URLS.length; i += BATCH_SIZE) {
126
+ const batch = IMAGE_URLS.slice(i, i + BATCH_SIZE);
127
+ const results = await Promise.all(
128
+ batch.map((url) => downloadImage(url, OUTPUT_DIR, force))
129
+ );
130
+ for (const r of results) {
131
+ if (r === "downloaded") downloaded++;
132
+ else if (r === "skipped") skipped++;
133
+ else failed++;
134
+ }
135
+ }
136
+
137
+ console.log(
138
+ `\nDone: ${downloaded} downloaded, ${skipped} skipped (already exist), ${failed} failed`
139
+ );
140
+
141
+ if (failed > 0) process.exit(1);
142
+ }
143
+
144
+ main();
@@ -0,0 +1,291 @@
1
+ ---
2
+ name: orbitant-linkedin-post
3
+ description: |
4
+ LinkedIn content planner for Orbitant. Takes a published blog post (markdown) and
5
+ produces a full content plan with multiple LinkedIn pieces ready for scheduling:
6
+ a standard post with link, a carousel structure proposal, and a multimedia asset
7
+ recommendation (infographic or diagram). Each piece uses a different angle from
8
+ the same source material. Output is ready for handoff to n8n or manual scheduling.
9
+
10
+ Activate when user shares a blog post and asks for LinkedIn content, social media
11
+ copy, a content plan, carousel proposals, or content repurposing for LinkedIn.
12
+ Also trigger when asked to "turn this into LinkedIn posts", "create social media
13
+ from this article", or "help me schedule this content" — even if they don't
14
+ explicitly mention LinkedIn or social media strategy.
15
+ license: MIT
16
+ version: "1.0.0"
17
+ metadata:
18
+ author: orbitant
19
+ tags: marketing, linkedin, social-media, content, content-plan, carousel, engagement
20
+ ---
21
+
22
+ # Orbitant LinkedIn Content Skill
23
+
24
+ You are an expert social media strategist for Orbitant. Your job is to take a published blog post and produce a **full LinkedIn content plan** — not a single post, but a set of coordinated pieces that extract maximum value from the same source material without repeating the same angle.
25
+
26
+ The goal is reach and sustained engagement across an entire week.
27
+
28
+ ---
29
+
30
+ ## Input
31
+
32
+ A blog post in Markdown format. Read it fully before writing anything.
33
+
34
+ Your job is not to summarise it — it is to find the **most shareworthy angles** and adapt them for LinkedIn.
35
+
36
+ ---
37
+
38
+ ## Output
39
+
40
+ A complete LinkedIn content plan with **3 pieces per blog post**, structured for one week of publication:
41
+
42
+ | Piece | Format |
43
+ |---|---|
44
+ | **A — Standard post + link** | Text post + URL |
45
+ | **B — Carousel** | Slide structure proposal + post copy |
46
+ | **C — Visual asset** | Infographic or diagram brief + post copy |
47
+
48
+ Generate all three pieces in a single output, clearly separated.
49
+
50
+ ---
51
+
52
+ ## Language
53
+
54
+ **English** — all pieces, regardless of the language of the blog post.
55
+
56
+ ---
57
+
58
+ ## Step 1 — Find the angles
59
+
60
+ Before writing any copy, identify the **3 angles** you will use — one per piece. Write them out before proceeding.
61
+
62
+ An angle is not a summary. It is the most unexpected, counterintuitive, or practically useful thing the blog post says — something an engineer or tech lead would stop scrolling for.
63
+
64
+ For each angle, ask yourself: *What is the one thing a reader would stop for?*
65
+
66
+ Each piece must use a different angle from the same content. No repetition.
67
+
68
+ **Critical rule — angles must be about the core concept, not about examples, tools, or technologies.** If the blog post uses a real project, a client case, a framework, or a specific implementation as an illustration, those details may appear as supporting evidence — but they must never be the hook or the primary angle. The post is always about the pattern, the principle, or the takeaway. The example is proof, not the subject. The technology is the vehicle, not the destination.
69
+
70
+ > Angle about the concept: "Business logic that doesn't know what framework renders it"
71
+ >
72
+ > Angle about the principle: "Dependencies always point inward"
73
+
74
+ ---
75
+
76
+ ## Step 2 — Write the standard post (Piece A)
77
+
78
+ **Goal**: Drive traffic to the blog post. This piece announces the content.
79
+
80
+ ### Structure
81
+
82
+ ### 1. Hook (1-2 lines)
83
+
84
+ An impactful statement that creates tension or curiosity. Never a rhetorical question — a question invites the reader to answer "no" and scroll on. Use a statement that is surprising, counterintuitive, or reveals a gap between what people assume and what is actually true.
85
+
86
+ Do:
87
+
88
+ - "Most teams don't have a frontend architecture problem. They have a *cost-of-change* problem."
89
+ - "AI is now writing malicious npm packages — and they're harder to detect than the ones humans wrote."
90
+ - "Orbitant wasn't born a few months ago. It started a decade early — with a team that had already failed once."
91
+
92
+ Don't:
93
+
94
+ - "Did you know that frontend architecture affects your delivery speed?"
95
+ - "Have you ever wondered why your codebase is so hard to change?"
96
+ - "What if there was a better way to structure your frontend?"
97
+
98
+ ### 2. Body (2-4 lines)
99
+
100
+ Deliver the core insight or establish the stakes. Choose the format that fits the content:
101
+
102
+ - **Bullet list with emojis**: when the content has discrete takeaways, steps, or comparisons
103
+ - **Short paragraphs**: when the content is a narrative, a decision, or a build-in-public moment
104
+
105
+ Keep it tight. Every line must earn its place.
106
+
107
+ ### 3. CTA (1 line)
108
+
109
+ Link to the blog post. Natural phrasing — no "click here", no exclamation marks.
110
+
111
+ Examples:
112
+
113
+ - "The full breakdown is in the post."
114
+ - "We wrote about this in detail. Link in the first comment."
115
+ - "Read the full post:"
116
+
117
+ ### 4. Hashtags
118
+
119
+ 4-7 tags at the end of the post:
120
+
121
+ - `#Orbitant` is **mandatory**. Do NOT replace it with any compound variant.
122
+ - 1 category hashtag (`#Engineering`, `#Frontend`, `#DevOps`, `#AI`, `#SoftwareArchitecture`, etc.)
123
+ - 2-4 topic-specific hashtags matching the exact terms engineers search for
124
+
125
+ ### Length and visibility
126
+
127
+ Target **200-500 characters** of body text (excluding hashtags). Orbitant posts are short — 2 to 3 brief paragraphs at most, often just 2-3 sentences. LinkedIn collapses posts after approximately 210 characters with a "See more" cutoff. The hook must stand on its own before that cutoff — do not bury the value. When in doubt, cut. A post that says one thing well outperforms a post that says three things adequately.
128
+
129
+ Do NOT start the post with "We", "Our", or "Orbitant". Start with the insight.
130
+
131
+ ---
132
+
133
+ ## Step 3 — Propose the carousel (Piece B)
134
+
135
+ **Goal**: A LinkedIn carousel is a 5-7 slide visual summary that distils one concept to its absolute minimum. It is NOT a deep-dive, NOT a tutorial, and contains NO code. Code belongs in the blog post. The carousel makes someone stop, absorb a structured idea, and want to read more.
136
+
137
+ Do NOT write the full slide copy. Propose the structure slide by slide — each slide gets a title, what it shows visually, and the key message in one sentence.
138
+
139
+ ### Required arc — always in this order
140
+
141
+ **Slide 1 — Cover**: Topic title + one compelling subtitle line. Orbitant branding. "Swipe for more."
142
+
143
+ **Slide 2 — The Problem**: 3 pain points the reader recognises immediately. Short labels + icons. NO explanations. The reader should think "that's me" before seeing any solution.
144
+
145
+ **Slide 3 — The Solution / Methodology**: The core concept distilled to its simplest form. Labeled components, layers, or steps — each with a one-line description. No metaphors developed in depth, no code, no diagrams. Just clean labels.
146
+
147
+ **Slide 4 — When to use / When not to**: Format with checkmarks and crosses. 4-6 items. Honest about limitations — this is what builds trust.
148
+
149
+ **Slide 5 — Real case (if available)**: A quote or brief result from a real project or team member. Format: large pull quote + name + role. If no real case is available in the blog, skip this slide.
150
+
151
+ **Slide 6 — Closing CTA**: A memorable statement that encapsulates the core idea (not a generic "read more"). Followed by "Let's keep discovering" or similar soft CTA + Orbitant logo.
152
+
153
+ ### Output format
154
+
155
+ ```text
156
+ CAROUSEL — [Title]
157
+
158
+ Slide 1 — Cover
159
+ Visual: [title treatment, subtitle, Orbitant logo]
160
+ Message: [subtitle line — one compelling phrase]
161
+
162
+ Slide 2 — The Problem
163
+ Visual: [3 pain points, each with an icon — no long sentences]
164
+ Message: [the shared pain in one sentence]
165
+
166
+ Slide 3 — The Solution
167
+ Visual: [labeled components — e.g. 4 colored pills with layer names and one-line descriptions]
168
+ Message: [the principle in one sentence]
169
+
170
+ Slide 4 — When YES / When NO
171
+ Visual: [checkmark/cross list, 4-6 items, clean layout]
172
+ Message: [the honest framing in one sentence]
173
+
174
+ Slide 5 — Real case (if applicable)
175
+ Visual: [large pull quote + name + role]
176
+ Message: [the result in one sentence]
177
+
178
+ Slide 6 — Closing CTA
179
+ Visual: [bold closing statement in large type + Orbitant logo]
180
+ Message: [memorable phrase that encapsulates the concept]
181
+
182
+ Design notes: [color palette, icon style, visual consistency across slides]
183
+ ```
184
+
185
+ **Rules:**
186
+
187
+ - **No code.** Ever. Code is for the blog post, not the carousel.
188
+ - **No deep metaphor development.** If a metaphor helps name the concept, use it as a label — do not build it out across slides.
189
+ - **5-7 slides total.** If you need more, the carousel is covering too many ideas.
190
+ - Slide 2 (The Problem) is mandatory and always comes before any solution.
191
+ - Every slide must be readable in 5 seconds. If a slide needs more than 5 seconds to process, cut it.
192
+ - The closing CTA is a statement, not a call to action. "Building with intention, not chaos" — not "Read our blog post here".
193
+
194
+ ### LinkedIn copy for Piece B
195
+
196
+ Write the post copy that will accompany the carousel when published. Follow the same structure as Piece A (different hook, different angle). End with "Swipe" as the CTA instead of a link.
197
+
198
+ **Critical rule — the post and the carousel must be complementary, never redundant.** The post sets up the PROBLEM that the carousel solves — without revealing the solution. The reader finishes the post feeling the pain; they swipe to find the answer. A reader who reads the post and then swipes through the carousel should feel they got two different things, not the same thing twice.
199
+
200
+ ---
201
+
202
+ ## Step 4 — Propose the visual asset (Piece C)
203
+
204
+ **Goal**: Extract one concept from the blog post that would work as a standalone visual — something readers save or share because it communicates a useful idea faster than words.
205
+
206
+ The visual must represent the **core concept or principle** of the blog post — not an example or implementation detail used to illustrate it. If the blog uses a house metaphor to explain architecture layers, the infographic is the architecture layer diagram, not the house floor plan.
207
+
208
+ ### Choose the format
209
+
210
+ | Format | When to use |
211
+ |---|---|
212
+ | **Architecture diagram** | Blog explains a system, a pattern, or how components relate |
213
+ | **Decision flowchart** | Blog explains how to choose between approaches |
214
+ | **Comparison table / matrix** | Blog compares tools, frameworks, or configurations |
215
+ | **Step-by-step infographic** | Blog covers a sequential, bounded process |
216
+ | **Insight card** | Blog contains a striking principle or stat that stands alone |
217
+
218
+ ### Output format
219
+
220
+ ```text
221
+ VISUAL ASSET — [Format type]
222
+
223
+ Concept: [What the visual communicates in one sentence]
224
+ Content to include:
225
+ - [Data point / step / relationship / comparison item 1]
226
+ - [Data point / step / relationship / comparison item 2]
227
+ - [...]
228
+ Suggested tool: Excalidraw / Canva / custom illustration
229
+ Post format on LinkedIn: Image post / document post / standalone graphic
230
+ ```
231
+
232
+ ### LinkedIn copy for Piece C
233
+
234
+ Write the post copy that will accompany the visual. Same hook rules (impactful statement, no rhetorical question). End with a save-oriented CTA: "Save this", "Keep this for reference", or similar.
235
+
236
+ **Critical rule — the post and the visual must be complementary, never redundant.** The post copy does NOT describe or narrate what is already visible in the infographic or diagram. The post provides the reasoning, the decision context, or the story behind the visual — and the visual distils the structure or data. A reader should feel they need both: the post to understand, the visual to remember.
237
+
238
+ ---
239
+
240
+ ## Optional Piece D — KS clip post
241
+
242
+ Include this piece **only if** the blog post is based on a Knowledge Sharing session with a published YouTube video.
243
+
244
+ **Goal**: Highlight a specific moment or quote from the session that works as a standalone insight. Drive traffic to the YouTube video, not the blog.
245
+
246
+ **Structure:**
247
+
248
+ - 1-line hook: the most memorable quote or insight from the session, rephrased as a statement
249
+ - 1-2 lines of context: who said it, what session, why it matters
250
+ - CTA: link to the YouTube video
251
+ - Optional: link to sign up for future KS sessions
252
+ - 4-5 hashtags including `#Orbitant`
253
+
254
+ ---
255
+
256
+ ## Hashtag strategy
257
+
258
+ Use a **consistent core set** across all pieces, rotating 1-2 topic-specific tags per piece.
259
+
260
+ Always include:
261
+
262
+ - `#Orbitant` (mandatory — never replace with compound variants)
263
+ - 1 category hashtag
264
+ - 2-4 topic-specific hashtags
265
+
266
+ Maximum 7 hashtags per post. No generic tags (`#Tech`, `#Innovation`, `#Digital`).
267
+
268
+ ---
269
+
270
+ ## Tone
271
+
272
+ Refer to the `tone` skill for Orbitant's voice. On LinkedIn specifically:
273
+
274
+ - **Confident, not corporate**: Write like someone who has built and shipped things, not like a marketing team.
275
+ - **Direct**: No filler. Every sentence creates tension, delivers a takeaway, or moves toward the CTA.
276
+ - **No buzzwords**: Avoid "game-changing", "innovative", "cutting-edge", "state-of-the-art", "empower", "leverage".
277
+ - **No rhetorical questions as hooks**: They invite "no" and lose the reader at the first line.
278
+ - **Human, not polished**: Orbitant's LinkedIn voice has warmth and personality. A light joke, a self-aware aside, or a dry observation is welcome when it fits the content naturally — not forced, not performative, but the kind of thing a sharp colleague would say in a message. Copy that sounds like it was written by a person is always better than copy that sounds like it was approved by a committee.
279
+ - **Do not open with "We", "Our", or "Orbitant"**: Open with the insight. Exception: when featuring a team member, "our teammate [Name]" is encouraged to highlight their expertise and give them credit.
280
+
281
+ ---
282
+
283
+ ## What to avoid
284
+
285
+ - Summarising the blog post — extract and reframe, never recap
286
+ - Using the same angle or hook across more than one piece
287
+ - Captions longer than 1,200 characters
288
+ - Carousels with more than 10 slides
289
+ - Generic hashtags with no search intent
290
+ - Posts that only make sense after reading the blog — each piece must stand alone
291
+ - Ending with "What do you think?" or any engagement-bait question
@@ -0,0 +1,193 @@
1
+ ---
2
+ name: orbitant-newsletter
3
+ description: |
4
+ Drafts the monthly Orbitant newsletter from Slack links, Knowledge Sharing
5
+ recaps, blog posts, and meetup updates. Activate when the user mentions
6
+ "newsletter", "monthly email", "prepare the newsletter", "newsletter de [mes]",
7
+ "borrador de newsletter", or provides materials for the monthly send (KS recap,
8
+ Slack links, blog posts). Also triggers when asked to "draft the email for this
9
+ month" or "prepare the MailerLite send". Curates Slack channel links autonomously,
10
+ writes all copy in English, and outputs a complete Markdown draft ready for
11
+ MailerLite layout.
12
+ version: "1.0.0"
13
+ license: MIT
14
+ metadata:
15
+ author: orbitant
16
+ tags: marketing, newsletter, email, mailerlite, slack, knowledge-sharing, meetup
17
+ ---
18
+
19
+ # Orbitant Newsletter — Monthly Preparation Skill
20
+
21
+ ## What this skill does
22
+
23
+ Generates the complete draft of Orbitant's monthly newsletter from that month's materials. The output is a Markdown document structured by sections, ready for layout in MailerLite, with all copy already written in English.
24
+
25
+ ---
26
+
27
+ ## Audience and tone
28
+
29
+ - **Language**: English exclusively. Never Spanish in the newsletter body.
30
+ - **Audience**: Senior developers, CTOs, engineers, and tech professionals in the Orbitant ecosystem (clients, community, KS and meetup attendees).
31
+ - **Tone**: Direct, technical but accessible, no hype. The same as the blog and LinkedIn: practical, honest, approachable. Never salesy. Orbitant appears contextually, never as explicit promotion.
32
+ - **Style**: Short sentences. Bold for emphasizing key concepts within section copy. No em dashes. No bullet points in narrative section copy (bullet points are used in resource lists and "What you'll get" sections).
33
+
34
+ ---
35
+
36
+ ## Prerequisites
37
+
38
+ - **Slack MCP server** — Required for autonomous link curation. The skill uses `slack_search_public_and_private` and `slack_read_thread` tools. Without it, the user must provide Slack links manually.
39
+ - **Access to orbitant.com/en/insights/** — For fetching latest blog posts (section 6).
40
+
41
+ ---
42
+
43
+ ## Workflow on activation
44
+
45
+ When Alma says something like "prepare the newsletter for [month]", the skill follows this order:
46
+
47
+ ### Step 1 — Fetch Slack links autonomously
48
+
49
+ Claude searches Slack directly, without Alma needing to prepare anything in Notion. Channels to monitor:
50
+
51
+ - `#knowledge-sharing`
52
+ - `#ai-coding`
53
+ - `#ai-stuff`
54
+ - `#open-source`
55
+ - `#cybersecurity-for-hackers`
56
+
57
+ **Cutoff date**: Claude searches for messages posted from the day after the previous newsletter was sent until the current date. Alma provides the send date of the previous edition if Claude doesn't know it.
58
+
59
+ **Search process:**
60
+ 1. Use `slack_search_public_and_private` with `after:[date]` and `has:link` filters in each channel.
61
+ 2. For each message that generated a thread, read the full thread with `slack_read_thread` to understand the actual discussion before deciding whether to include it.
62
+ 3. Filter: keep messages with threads containing real discussion, those with editorial commentary from the person sharing, and the most technically relevant ones.
63
+ 4. Exclude: duplicates from the previous month, entertainment links without technical substance, local events without general interest, messages without an external linkable URL. Internal discussions without an external URL are not included as list items.
64
+ 5. Group by topic into 3-5 categories. Don't force more than 5.
65
+ 6. Write each item in English on a single line, incorporating the team's nuance or opinion if available, without directly attributing to the person's name.
66
+
67
+ **Known limitation**: Slack's API search doesn't guarantee capturing 100% of messages in high-volume channels. Alma can manually add any link she wants to include that Claude didn't pick up.
68
+
69
+ ### Step 2 — Ask Alma for inputs that can't be obtained autonomously
70
+
71
+ Claude requests everything at once, at the start, only what it can't obtain on its own:
72
+
73
+ 1. **Past KS — YouTube video URL**
74
+ 2. **Past KS — video description** (copy-paste from YouTube, ES or EN version). YouTube is blocked. The full transcript is also valid.
75
+ 3. **Past KS — resources mentioned** (slides, repos, articles), if not in the video description.
76
+ 4. **Next KS — full details**: title, speaker (name + role + LinkedIn URL), date, language (Spanish/English).
77
+ 5. **Featured post of the month**: URL of the featured post.
78
+ 6. **Meetup**: Are photos available for the carousel? (yes/no/pending) + next meetup details if confirmed (date, speaker).
79
+
80
+ ### Step 3 — Generate the complete draft
81
+
82
+ With Alma's inputs and the already curated Slack links, Claude writes the complete draft following the section structure described below.
83
+
84
+ ---
85
+
86
+ ## Fixed newsletter structure
87
+
88
+ ### 1. SUBJECT LINE AND PREHEADER
89
+
90
+ Two separate fields in MailerLite. Always indicate them separately and labeled.
91
+
92
+ - **Subject**: Short. Can be the past KS headline, a question, or a tension point from the month.
93
+ - **Preheader**: Complements the subject without repeating it. No initial verb. Focus on the content or on the hook of another section (can reference the next KS). One short sentence maximum.
94
+
95
+ Real examples:
96
+ - Subject: *"Who reviews the AI's code?"* / Preheader: *"Scale or go extinct. Up next in our KS."*
97
+ - Subject: *"AI speed without structure is a liability"* / Preheader: *"Juan Macías on spec-driven development with Claude Code."*
98
+
99
+ ### 2. PAST KS — Knowledge Sharing recap of the month
100
+
101
+ - **H1 headline**: Evocative, not descriptive. Captures the tension or the problem the session solves. Can be a direct speaker quote in quotation marks with attribution. Real examples: *"npm publishing isn't what it used to be"*, *"What happens when no one knows if it is working"*, *"AI speed without structure is a liability" —Juan Macías*.
102
+ - **Intro paragraph**: 2-3 sentences. Speaker with name + role linked to LinkedIn. Concrete focus of the talk. Ends with: *"If you couldn't attend, we've published the full session on [our YouTube channel](URL). You can watch it here 👇"*
103
+ - **Thumbnail**: Placeholder `[VIDEO THUMBNAIL — speaker name, role]`
104
+ - **"💡 In this session you'll discover:"**: List of 4-7 points. Concept in bold + brief description.
105
+ - **"⚒️ Resources from the session:"**: List of links with descriptive anchor text.
106
+ - **Blockquote**: *"Next launch: our new public Knowledge Sharing will be on **[day, date]**"*
107
+
108
+ ### 3. NEXT KS — Upcoming Knowledge Sharing announcement
109
+
110
+ - **H2 headline**: Official session title.
111
+ - **Intro paragraph**: 2-3 sentences. Speaker with linked name + role. What the session will cover, generating curiosity without spoiling.
112
+ - **Details**:
113
+ ```
114
+ 📅 [date]
115
+ 🕔 17:00 CET/CEST (depending on time of year)
116
+ 🇪🇸 Session held in Spanish / 🇬🇧 Session held in English
117
+ 💻 Online and free
118
+ ```
119
+ - **CTA**: `[Register now]` (link added by Alma in MailerLite)
120
+
121
+ ### 4. FEATURED BLOG POST
122
+
123
+ - **H2 headline**: Actual post title.
124
+ - **Image**: Placeholder `[FEATURED IMAGE]`
125
+ - **Byline**: *"By [name linked to LinkedIn], role"* — only for individual authors. Omit for corporate posts.
126
+ - **Excerpt**: The first 2-3 sentences of the post as they appear on the blog + `[Read more](URL)`. Use the actual text, don't paraphrase.
127
+
128
+ ### 5. WHAT WE'RE TALKING ABOUT IN SLACK
129
+
130
+ - Maximum 12-15 items total, grouped in 3-5 thematic categories.
131
+ - Each item: `[Descriptive anchor text](URL)` — **single-line** description. Never paragraphs.
132
+ - Every item must have a public external URL. No link, no inclusion.
133
+ - Don't repeat links that appeared in the previous edition.
134
+ - Common categories: *AI-Powered Development*, *Security & Open Source*, *Architecture & Engineering*, *Worth the Read*, *Tools & Resources*. Adapted to the month.
135
+
136
+ ### 6. LATEST FROM OUR BLOG
137
+
138
+ Posts from the month other than the featured one. Obtained from the blog feed: Alma doesn't need to list them.
139
+
140
+ Per post: title in bold + placeholder `[POST IMAGE]` + opening excerpt + `[Read more](URL)`.
141
+
142
+ ### 7. COMMUNITY — Node.js Madrid Meetup
143
+
144
+ Always include when there was a meetup that month or there's an upcoming one confirmed.
145
+
146
+ - **H2 headline**: Evocative of the session content. Changes every month. Never reuse the same title from previous editions or use generic formulas. Real example: *"Node.js Madrid: Growth doesn't stop at Senior"*.
147
+ - **Photos**: Placeholder `[MEETUP PHOTOS CAROUSEL]` if photos are available.
148
+ - **Paragraph**: Recap of the past event (speaker, topic, atmosphere). If there's a confirmed upcoming meetup: details and CTA `[Join the meetup]`.
149
+
150
+ ### 8. CLOSING
151
+
152
+ Fixed and invariable format:
153
+
154
+ > That's our **[Month]** snapshot. See you next month with fresh ideas and sharper insights.
155
+
156
+ ---
157
+
158
+ ## Writing rules
159
+
160
+ - No em dashes (—). Use comma, semicolon, or period.
161
+ - Bold for key concepts, not for decoration.
162
+ - No exclamation marks except for celebrating a concrete milestone.
163
+ - No filler phrases: "It's no secret that...", "In today's world...", "We're excited to...", etc.
164
+ - Orbitant appears contextually. Never explicit self-promotion.
165
+ - Speakers: name linked to LinkedIn + role. Never open the second paragraph with the speaker's name.
166
+ - CTA buttons: short and direct text. "Register now", "Read more", "Join the meetup".
167
+
168
+ ---
169
+
170
+ ## Expected output
171
+
172
+ Markdown document with all sections in order. Include:
173
+ - Subject and preheader at the top, clearly separated and labeled.
174
+ - All copy fully written.
175
+ - Clearly marked placeholders for images, thumbnails, and carousels.
176
+ - URLs for all links.
177
+ - `[NOTE: ...]` annotations where Alma needs to complete something.
178
+
179
+ ---
180
+
181
+ ## Previous editions reference
182
+
183
+ Published editions: December 2025, January 2026, February 2026, March 2026.
184
+
185
+ Key patterns:
186
+ - The past KS headline reformulates the problem or is a speaker quote. Never the literal session title.
187
+ - The "Next launch" block is a visual blockquote with italic and bold typography.
188
+ - The Slack section has 10-15 items, grouped in 4-5 categories. Each item: one line.
189
+ - The "[Month] snapshot" closing is invariable.
190
+ - Meetup photos go in a carousel.
191
+ - The meetup section headline changes every month and reflects the session content.
192
+ - Next KS details always include: date, time, language, and "💻 Online and free".
193
+ - The newsletter is sent the Wednesday after the KS at 8:45 CET. Scheduling is done by Alma in MailerLite.