@ericrisco/rsc 0.1.53 → 0.1.54
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.
- package/manifest.json +7 -7
- package/package.json +1 -1
- package/skills/lead-gen/SKILL.md +2 -6
- package/skills/lead-gen/evals/cases.yaml +2 -2
- package/skills/linkedin-carousels/SKILL.md +31 -42
- package/skills/llm-pipeline/SKILL.md +4 -9
- package/skills/modal/SKILL.md +31 -49
- package/skills/newsletter/SKILL.md +10 -20
- package/skills/newsletter/references/growth-loops.md +3 -3
- package/skills/prompt-engineering/SKILL.md +5 -16
- package/skills/prompt-engineering/evals/cases.yaml +1 -1
package/manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.1.
|
|
2
|
+
"version": "0.1.54",
|
|
3
3
|
"counts": {
|
|
4
4
|
"skills": 258
|
|
5
5
|
},
|
|
@@ -2549,7 +2549,7 @@
|
|
|
2549
2549
|
},
|
|
2550
2550
|
{
|
|
2551
2551
|
"id": "lead-gen",
|
|
2552
|
-
"description": "Use when
|
|
2552
|
+
"description": "Use when building and qualifying a prospect list before anyone reaches out — a falsifiable ICP, named accounts/contacts from Apollo/ZoomInfo/Clay, deduped against the CRM, tiered by fit+intent+engagement. NOT writing or sending the outreach (that is cold-outreach), NOT tracking the deal after first contact (that is sales-pipeline).",
|
|
2553
2553
|
"tags": [
|
|
2554
2554
|
"lead-generation",
|
|
2555
2555
|
"prospecting",
|
|
@@ -2609,7 +2609,7 @@
|
|
|
2609
2609
|
},
|
|
2610
2610
|
{
|
|
2611
2611
|
"id": "linkedin-carousels",
|
|
2612
|
-
"description": "Use when
|
|
2612
|
+
"description": "Use when building a LinkedIn carousel / document post — the swipeable multi-page PDF — slide by slide: cover hook, narrative arc, one idea per slide, CTA closer, PDF export spec. NOT the account/format plan (that is `linkedin-strategy`), NOT a text or single-image feed post (that is `linkedin-content`), NOT a 16:9 talk deck (that is `presentations`).",
|
|
2613
2613
|
"tags": [
|
|
2614
2614
|
"linkedin",
|
|
2615
2615
|
"carousel",
|
|
@@ -2694,7 +2694,7 @@
|
|
|
2694
2694
|
},
|
|
2695
2695
|
{
|
|
2696
2696
|
"id": "llm-pipeline",
|
|
2697
|
-
"description": "Use when wiring several LLM calls into
|
|
2697
|
+
"description": "Use when wiring several LLM calls into a production flow: typed contracts between steps, a router/gateway so 429s, timeouts and outages fail over instead of taking you down, and cost control via caching, model tiers and abort caps. NOT single-prompt wording (that is `prompt-engineering`), NOT a model-driven tool loop (that is `building-agents`).",
|
|
2698
2698
|
"tags": [
|
|
2699
2699
|
"llm-orchestration",
|
|
2700
2700
|
"llm-gateway",
|
|
@@ -2912,7 +2912,7 @@
|
|
|
2912
2912
|
},
|
|
2913
2913
|
{
|
|
2914
2914
|
"id": "modal",
|
|
2915
|
-
"description": "Use when running Python
|
|
2915
|
+
"description": "Use when running Python or GPU workloads serverlessly on Modal — modal.App, inline container Images, gpu= on @app.function, Volumes for weight caching, Cron schedules, ASGI endpoints, modal run vs serve vs deploy. NOT managed prediction APIs with no container of your own (that is replicate); NOT SSH-able GPU boxes rented by the hour (that is runpod).",
|
|
2916
2916
|
"tags": [
|
|
2917
2917
|
"modal",
|
|
2918
2918
|
"serverless",
|
|
@@ -3075,7 +3075,7 @@
|
|
|
3075
3075
|
},
|
|
3076
3076
|
{
|
|
3077
3077
|
"id": "newsletter",
|
|
3078
|
-
"description": "Use when running an email newsletter as a recurring publication —
|
|
3078
|
+
"description": "Use when running an email newsletter as a recurring publication — subject + preview pair, issues that turn opens into clicks, the welcome sequence, cadence and engagement tiering, growth loops, and a post-Apple-MPP click scorecard. NOT one-off launch or nurture sends (that is `marketing`), NOT SPF/DKIM/DMARC (that is `email-deliverability`).",
|
|
3079
3079
|
"tags": [
|
|
3080
3080
|
"newsletter",
|
|
3081
3081
|
"email",
|
|
@@ -3609,7 +3609,7 @@
|
|
|
3609
3609
|
},
|
|
3610
3610
|
{
|
|
3611
3611
|
"id": "prompt-engineering",
|
|
3612
|
-
"description": "Use when one prompt
|
|
3612
|
+
"description": "Use when one prompt must give the same right answer across reruns, models, and pasted-in hostile input: forcing a fixed schema, picking the few-shot set, ordering the prompt blocks, or the inline cases you run while tuning. NOT the agent loop, tools, or retrieval (that is `building-agents`), NOT a standing CI eval harness (that is `agent-eval`).",
|
|
3613
3613
|
"tags": [
|
|
3614
3614
|
"prompts",
|
|
3615
3615
|
"llm",
|
package/package.json
CHANGED
package/skills/lead-gen/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: lead-gen
|
|
3
|
-
description: "Use when
|
|
3
|
+
description: "Use when building and qualifying a prospect list before anyone reaches out — a falsifiable ICP, named accounts/contacts from Apollo/ZoomInfo/Clay, deduped against the CRM, tiered by fit+intent+engagement. NOT writing or sending the outreach (that is cold-outreach), NOT tracking the deal after first contact (that is sales-pipeline)."
|
|
4
4
|
tags: [lead-generation, prospecting, icp, lead-scoring, sales]
|
|
5
5
|
recommends: [cold-outreach, sales-pipeline, market-research, data-scraper, spreadsheet-ops, email-deliverability, gdpr-privacy]
|
|
6
6
|
origin: risco
|
|
@@ -8,9 +8,7 @@ origin: risco
|
|
|
8
8
|
|
|
9
9
|
# Lead Gen — The List and the Model That Ranks It
|
|
10
10
|
|
|
11
|
-
*You turn "we sell X to Y" into a deduplicated, scored, compliance-cleared roster of named accounts and people. You define the target, you build the list, you rank it — then you stop.
|
|
12
|
-
|
|
13
|
-
The identity of this skill is **the list and its scoring model**, not the messages sent to it and not the pipeline it becomes. Everything you produce is a *prioritized roster + the rationale that ranked it*. The hand-off is the finish line, not the campaign.
|
|
11
|
+
*You turn "we sell X to Y" into a deduplicated, scored, compliance-cleared roster of named accounts and people. You define the target, you build the list, you rank it — then you stop. What you produce is a prioritized roster plus the rationale that ranked it; the hand-off is the finish line, not the campaign.*
|
|
14
12
|
|
|
15
13
|
## The pipeline — three phases, two gates
|
|
16
14
|
|
|
@@ -151,5 +149,3 @@ This skill stops at a scored, compliance-cleared list. From there:
|
|
|
151
149
|
- The **A/B tiers + persona context** go to `../cold-outreach/SKILL.md` — that skill writes the message and the cadence; you do not.
|
|
152
150
|
- **Accepted leads** (worked and responsive) go to `../sales-pipeline/SKILL.md` — that skill tracks stages, forecasts, and manages the deal; you do not.
|
|
153
151
|
- If the request is really "how big is this market / which segment?" with no named list, that is `../market-research/SKILL.md`, not this skill.
|
|
154
|
-
|
|
155
|
-
When the deliverable would be a message, a pipeline stage, or a market sizing — route. Your job ended at the ranked roster.
|
|
@@ -10,9 +10,9 @@ should_trigger:
|
|
|
10
10
|
- prompt: "Is this cold prospect list legal to email under GDPR before we send?"
|
|
11
11
|
why: "The compliance gate (GDPR LIA, no scraped basis) is part of making a list ship-ready — non-obvious that lead-gen owns it, not a generic legal skill."
|
|
12
12
|
- prompt: "Necesito una lista de clientes potenciales para nuestro SaaS de logística."
|
|
13
|
-
why: "Spanish core
|
|
13
|
+
why: "Spanish-language phrasing of the core case — build a target list of prospects."
|
|
14
14
|
- prompt: "A qui de la nostra base truquem primer, tenim 300 comptes sense prioritzar?"
|
|
15
|
-
why: "Catalan
|
|
15
|
+
why: "Catalan-language phrasing — scoring/tiering an unprioritized account list."
|
|
16
16
|
|
|
17
17
|
should_not_trigger:
|
|
18
18
|
- prompt: "Write the cold email sequence for these prospects."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: linkedin-carousels
|
|
3
|
-
description: "Use when
|
|
3
|
+
description: "Use when building a LinkedIn carousel / document post — the swipeable multi-page PDF — slide by slide: cover hook, narrative arc, one idea per slide, CTA closer, PDF export spec. NOT the account/format plan (that is `linkedin-strategy`), NOT a text or single-image feed post (that is `linkedin-content`), NOT a 16:9 talk deck (that is `presentations`)."
|
|
4
4
|
tags: [linkedin, carousel, document-post, slide-design, visual-hierarchy, hook, b2b, social-content]
|
|
5
5
|
recommends: [linkedin-content, linkedin-strategy, brand-identity, brand-voice, presentations, social-publisher]
|
|
6
6
|
origin: risco
|
|
@@ -8,16 +8,10 @@ origin: risco
|
|
|
8
8
|
|
|
9
9
|
# LinkedIn carousels
|
|
10
10
|
|
|
11
|
-
Design **one swipeable LinkedIn document post
|
|
12
|
-
|
|
13
|
-
Canva/Figma/Slides
|
|
14
|
-
|
|
15
|
-
You do not own the account plan (which formats, cadence, niche — that is
|
|
16
|
-
[`../linkedin-strategy/SKILL.md`](../linkedin-strategy/SKILL.md)), the words of a text or
|
|
17
|
-
single-image feed post ([`../linkedin-content/SKILL.md`](../linkedin-content/SKILL.md)), the
|
|
18
|
-
programmatic upload ([`../linkedin-api/SKILL.md`](../linkedin-api/SKILL.md)), or a spoken-to
|
|
19
|
-
16:9 talk deck ([`../presentations/SKILL.md`](../presentations/SKILL.md)). Your artifact is the
|
|
20
|
-
*slides of a phone-read PDF* — sequence and visual hierarchy are the product.
|
|
11
|
+
Design **one swipeable LinkedIn document post**. Your artifact is the *slides of a phone-read
|
|
12
|
+
PDF* — sequence and visual hierarchy are the product — handed back as a slide-by-slide build
|
|
13
|
+
ready to assemble in Canva/Figma/Slides plus a one-page design+export checklist. Everything
|
|
14
|
+
adjacent (the account plan, the feed copy, the upload, a talk deck) routes out; see Handoffs.
|
|
21
15
|
|
|
22
16
|
## What you produce
|
|
23
17
|
|
|
@@ -27,34 +21,30 @@ programmatic upload ([`../linkedin-api/SKILL.md`](../linkedin-api/SKILL.md)), or
|
|
|
27
21
|
- **A design + export spec** — canvas, safe area, type floor, PDF checklist (one page).
|
|
28
22
|
- **A one-line caption starter** — the first feed line; full caption tuning routes out.
|
|
29
23
|
|
|
30
|
-
Precondition:
|
|
31
|
-
|
|
24
|
+
Precondition: a topic, an angle, or a source (post/article). If the ask is the account plan or
|
|
25
|
+
a block of feed copy, you are in the wrong skill — see the handoffs table.
|
|
32
26
|
|
|
33
27
|
## Ground first
|
|
34
28
|
|
|
35
|
-
A carousel inherits an identity; it does not invent one.
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
|
|
39
|
-
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
[`../linkedin-strategy/SKILL.md`](../linkedin-strategy/SKILL.md) or
|
|
43
|
-
[`../linkedin-content/SKILL.md`](../linkedin-content/SKILL.md). Reuse the hook, don't reopen it.
|
|
44
|
-
|
|
45
|
-
If none exist, name your assumptions on slide 0 of the spec and proceed — don't stall.
|
|
29
|
+
A carousel inherits an identity; it does not invent one. Read the brand kit (colors, type,
|
|
30
|
+
logo — owned by [`../brand-identity/SKILL.md`](../brand-identity/SKILL.md)) and the voice
|
|
31
|
+
([`../brand-voice/SKILL.md`](../brand-voice/SKILL.md)) from `02-DOCS/` if they exist; don't pick
|
|
32
|
+
arbitrary fonts. Pull the angle from any plan or post already produced by
|
|
33
|
+
[`../linkedin-strategy/SKILL.md`](../linkedin-strategy/SKILL.md) or
|
|
34
|
+
[`../linkedin-content/SKILL.md`](../linkedin-content/SKILL.md) — reuse the hook, don't reopen
|
|
35
|
+
it. If none exist, name your assumptions on slide 0 of the spec and proceed; don't stall.
|
|
46
36
|
|
|
47
37
|
## The swipe economics (why every rule below exists)
|
|
48
38
|
|
|
49
39
|
Document/carousel posts are the **highest-engagement native format on LinkedIn right now** —
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
40
|
+
roughly 6.6% average engagement, ahead of every other format, and top-performing pages post far
|
|
41
|
+
more of them than median pages. The reason is **dwell time**: a swipeable deck holds the thumb
|
|
42
|
+
on screen, and dwell — not likes — is the algorithm's main distribution signal.
|
|
53
43
|
|
|
54
44
|
So the whole bet is the **cover slide and the swipe-to-slide-2 bounce**. If the cover doesn't
|
|
55
|
-
earn the first swipe, your slide count, your arc, and your CTA never get seen
|
|
56
|
-
|
|
57
|
-
|
|
45
|
+
earn the first swipe, your slide count, your arc, and your CTA never get seen; every swipe after
|
|
46
|
+
that extends dwell and signals quality, which is why each slide must *pull to the next*. Design
|
|
47
|
+
backwards from that: stop the thumb, then keep it moving.
|
|
58
48
|
|
|
59
49
|
## The cover slide
|
|
60
50
|
|
|
@@ -150,11 +140,10 @@ Good — one idea, one dominant element, breathing room
|
|
|
150
140
|
## Slide count
|
|
151
141
|
|
|
152
142
|
Aim for the **6–12 band, ~8 as the sweet spot** (cover + ~6 content + CTA). Reported peaks
|
|
153
|
-
cluster around 7–8 slides; 8–12 is where the highest dwell/save/share rates show up. Fewer
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
resolves in 7 slides, ship 7 — don't pad to hit a number.
|
|
143
|
+
cluster around 7–8 slides; 8–12 is where the highest dwell/save/share rates show up. Fewer than
|
|
144
|
+
5 underdelivers (not worth the swipe); more than ~15 loses people before the payoff. Treat the
|
|
145
|
+
band as a guide, not a law: **length follows the arc, not a quota** — if the arc resolves in 7
|
|
146
|
+
slides, ship 7, don't pad to hit a number.
|
|
158
147
|
|
|
159
148
|
## The CTA closer
|
|
160
149
|
|
|
@@ -184,17 +173,17 @@ Gotchas: open the exported PDF and verify fonts — free Canva silently substi
|
|
|
184
173
|
```
|
|
185
174
|
|
|
186
175
|
Portrait 4:5 takes the most vertical space in a mobile feed, which raises dwell and the chance
|
|
187
|
-
of a scroll-stop
|
|
188
|
-
devices
|
|
176
|
+
of a scroll-stop; PDF is the only export that preserves fonts and layout reliably across
|
|
177
|
+
devices, since slides exported as images lose crispness and break selectable text. The full
|
|
189
178
|
checklist in prose is in [`references/carousel-patterns.md`](references/carousel-patterns.md).
|
|
190
179
|
|
|
191
180
|
## The feed caption handoff
|
|
192
181
|
|
|
193
182
|
A document post still has a **text caption above it**, and its first 1–2 lines (before the
|
|
194
183
|
"…more" fold) must restate the cover hook — that line is what people read before deciding to
|
|
195
|
-
expand and swipe. Give a one-line starter that echoes the cover
|
|
196
|
-
|
|
197
|
-
|
|
184
|
+
expand and swipe. Give a one-line starter that echoes the cover; you own the slides, and
|
|
185
|
+
[`../linkedin-content/SKILL.md`](../linkedin-content/SKILL.md) owns the caption's full
|
|
186
|
+
length/tone tuning.
|
|
198
187
|
|
|
199
188
|
## Handoffs
|
|
200
189
|
|
|
@@ -202,7 +191,7 @@ the slides; that sibling owns the caption.
|
|
|
202
191
|
|---|---|
|
|
203
192
|
| The account/format plan, cadence, niche, who to target | [`../linkedin-strategy/SKILL.md`](../linkedin-strategy/SKILL.md) |
|
|
204
193
|
| A text or single-image feed post (just the copy) | [`../linkedin-content/SKILL.md`](../linkedin-content/SKILL.md) |
|
|
205
|
-
| 1:1 DMs / connection-request outreach sequences | `linkedin-outreach
|
|
194
|
+
| 1:1 DMs / connection-request outreach sequences | [`../linkedin-outreach/SKILL.md`](../linkedin-outreach/SKILL.md) |
|
|
206
195
|
| To publish/schedule the deck via the LinkedIn API | [`../linkedin-api/SKILL.md`](../linkedin-api/SKILL.md) |
|
|
207
196
|
| A spoken-to 16:9 talk deck (speaker support) | [`../presentations/SKILL.md`](../presentations/SKILL.md) |
|
|
208
197
|
| The color / type / logo brand kit the deck is styled in | [`../brand-identity/SKILL.md`](../brand-identity/SKILL.md) |
|
|
@@ -236,4 +225,4 @@ scripts/verify.sh path/to/carousel-spec.md
|
|
|
236
225
|
It checks (read-only) for a labeled cover slide, a slide count in 5–15 (warns outside 6–12), a
|
|
237
226
|
CTA slide with an explicit ask, a portrait/square canvas, a ≥28 px type floor, "PDF" as the
|
|
238
227
|
export target, and warns on any crammed (3+ bullet) interior slide. An empty or clean target
|
|
239
|
-
passes.
|
|
228
|
+
passes.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: llm-pipeline
|
|
3
|
-
description: "Use when wiring several LLM calls into
|
|
3
|
+
description: "Use when wiring several LLM calls into a production flow: typed contracts between steps, a router/gateway so 429s, timeouts and outages fail over instead of taking you down, and cost control via caching, model tiers and abort caps. NOT single-prompt wording (that is `prompt-engineering`), NOT a model-driven tool loop (that is `building-agents`)."
|
|
4
4
|
tags: [llm-orchestration, llm-gateway, fallbacks, prompt-caching, cost-control, litellm, reliability]
|
|
5
5
|
recommends: [prompt-engineering, structured-extraction, building-agents, cost-tracking, agent-eval, rag, observability, parallel]
|
|
6
6
|
origin: risco
|
|
@@ -10,14 +10,7 @@ origin: risco
|
|
|
10
10
|
|
|
11
11
|
Wire multiple LLM calls into a reliable, controllable production pipeline. You chain steps where one call's validated output feeds the next, put a router in front of providers so an outage fails over instead of taking you down, and engineer the cross-cutting concerns: timeouts, bounded retries, fallbacks, caching, and cost caps.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Treat the LLM as an unreliable network dependency, not a local function call. Everything below follows from that.
|
|
16
|
-
|
|
17
|
-
- **Every call gets a hard timeout and bounded retries.** Providers have outages, rate limits, and latency tails; a naked call can hang your whole request behind one slow upstream.
|
|
18
|
-
- **Steps pass validated structured objects, not free text.** The output of step N is a contract you assert on before it becomes step N+1's input — a parse failure is caught at the seam, not three steps later.
|
|
19
|
-
- **A router sits in front of every provider.** One model's 429/500/timeout fails over to another; no single provider is a single point of failure.
|
|
20
|
-
- **Cache and tier before you tune prompts.** The cheapest, fastest, most reliable call is the one you never made. Prompt wording is the last lever, not the first.
|
|
13
|
+
Treat the LLM as an unreliable network dependency, not a local function call. Every rule below follows from that: providers have outages, rate limits, and latency tails, so no single provider is a single point of failure and no call is allowed to run unbounded.
|
|
21
14
|
|
|
22
15
|
## Do you even need a pipeline?
|
|
23
16
|
|
|
@@ -116,6 +109,8 @@ except Exception:
|
|
|
116
109
|
|
|
117
110
|
## Caching: two distinct layers
|
|
118
111
|
|
|
112
|
+
The cheapest, fastest, most reliable call is the one you never made — so cache and tier before you tune prompts. Wording is the last lever, not the first.
|
|
113
|
+
|
|
119
114
|
| Layer | What it matches | Safety | Enable when |
|
|
120
115
|
| --- | --- | --- | --- |
|
|
121
116
|
| Prefix / prompt cache (provider-native) | Exact prefix of the prompt | Always safe (same input → same cached compute) | Always; put the stable prefix first |
|
package/skills/modal/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: modal
|
|
3
|
-
description: "Use when running Python
|
|
3
|
+
description: "Use when running Python or GPU workloads serverlessly on Modal — modal.App, inline container Images, gpu= on @app.function, Volumes for weight caching, Cron schedules, ASGI endpoints, modal run vs serve vs deploy. NOT managed prediction APIs with no container of your own (that is replicate); NOT SSH-able GPU boxes rented by the hour (that is runpod)."
|
|
4
4
|
tags: [modal, serverless, gpu, python, ai-infra, deployment, cron, web-endpoint]
|
|
5
5
|
recommends: [replicate, runpod, fastapi, docker, python, llm-pipeline]
|
|
6
6
|
origin: risco
|
|
@@ -19,27 +19,19 @@ Pinned stack: **modal 1.4.3** (released 2026-05-18), Python **3.10–3.14** (`>=
|
|
|
19
19
|
Install with `pip install modal` then `modal setup` to authenticate. Everything below uses
|
|
20
20
|
the Modal 1.0+ API; several pre-1.0 forms were removed and are called out as Bad→Good.
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## Not this skill
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
- Building a container image inline (`Image.debian_slim().uv_pip_install(...)`) for a remote job.
|
|
27
|
-
- Persisting model weights or datasets across runs with a Modal `Volume`.
|
|
28
|
-
- Scheduled jobs (nightly report, periodic scrape) via `modal.Cron` / `modal.Period`.
|
|
29
|
-
- Exposing a function over HTTP (`fastapi_endpoint`, `asgi_app`, `wsgi_app`, `web_server`).
|
|
30
|
-
- Fan-out parallelism with `.map()` / `.starmap()` / `.spawn()`.
|
|
24
|
+
Modal owns the serverless-container-as-decorators surface and its CLI lifecycle; the *contents*
|
|
25
|
+
of your function belong elsewhere.
|
|
31
26
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
Modal owns the serverless-container-as-decorators surface and its CLI lifecycle; the
|
|
42
|
-
*contents* of your function (FastAPI app, RAG chain) belong to the siblings above.
|
|
27
|
+
| The job | Goes to |
|
|
28
|
+
|---|---|
|
|
29
|
+
| Calling a **managed prediction API** with no container of your own | [`replicate`](../replicate/SKILL.md) / [`together-fireworks`](../together-fireworks/SKILL.md) / [`fal`](../fal/SKILL.md) |
|
|
30
|
+
| Renting a **persistent, SSH-able GPU box** by the hour/week | [`runpod`](../runpod/SKILL.md) |
|
|
31
|
+
| **FastAPI design** (routing, Pydantic, deps) independent of host | [`fastapi`](../fastapi/SKILL.md) |
|
|
32
|
+
| Writing a **Dockerfile** for a registry / k8s / Compose | [`docker`](../docker/SKILL.md) |
|
|
33
|
+
| General **Python language/runtime** questions | [`python`](../python/SKILL.md) |
|
|
34
|
+
| **RAG / LLM pipeline** orchestration logic itself | [`llm-pipeline`](../llm-pipeline/SKILL.md) |
|
|
43
35
|
|
|
44
36
|
## Decision: which entrypoint?
|
|
45
37
|
|
|
@@ -109,8 +101,8 @@ image = (
|
|
|
109
101
|
)
|
|
110
102
|
```
|
|
111
103
|
|
|
112
|
-
|
|
113
|
-
download-once weight-cache pattern.
|
|
104
|
+
→ [`references/images-gpu-cookbook.md`](references/images-gpu-cookbook.md) for vLLM / torch+CUDA
|
|
105
|
+
/ diffusers recipes and the download-once weight-cache pattern.
|
|
114
106
|
|
|
115
107
|
## GPU — it's a string now
|
|
116
108
|
|
|
@@ -193,8 +185,7 @@ def pull():
|
|
|
193
185
|
```
|
|
194
186
|
|
|
195
187
|
Never bake a token into the image (`.run_commands("export TOKEN=...")`) — it's recorded in
|
|
196
|
-
layer history. Use a Secret.
|
|
197
|
-
HF/OpenAI secret patterns.
|
|
188
|
+
layer history. Use a Secret. The cookbook above also carries the HF/OpenAI secret patterns.
|
|
198
189
|
|
|
199
190
|
## Web endpoints
|
|
200
191
|
|
|
@@ -228,8 +219,8 @@ def web():
|
|
|
228
219
|
|
|
229
220
|
Develop with `modal serve app.py` (hot-reload); ship with `modal deploy app.py` (stable URL).
|
|
230
221
|
For custom domains, proxy-auth tokens, batching (`@modal.batched`), and concurrency tuning →
|
|
231
|
-
`references/web-and-scaling.md
|
|
232
|
-
that's
|
|
222
|
+
[`references/web-and-scaling.md`](references/web-and-scaling.md). For the FastAPI app's *own*
|
|
223
|
+
design (routes, Pydantic, deps), that's [`fastapi`](../fastapi/SKILL.md) — this skill only mounts it.
|
|
233
224
|
|
|
234
225
|
## Scheduled jobs
|
|
235
226
|
|
|
@@ -268,9 +259,9 @@ def main():
|
|
|
268
259
|
they complete (faster when latencies vary). Combine with `retries=` on the function so a
|
|
269
260
|
single bad input doesn't sink the batch.
|
|
270
261
|
|
|
271
|
-
## Anti-patterns
|
|
262
|
+
## Anti-patterns
|
|
272
263
|
|
|
273
|
-
|
|
|
264
|
+
| Anti-pattern | Do instead |
|
|
274
265
|
|---|---|
|
|
275
266
|
| "I'll use `gpu=modal.gpu.A100()` like the old docs" | Removed in 1.0. Use the string `gpu="A100-80GB"`. |
|
|
276
267
|
| "Attach a GPU, it might speed up this CPU job" | GPU is billed per second alive. CPU-only job → no `gpu=`. |
|
|
@@ -279,30 +270,21 @@ single bad input doesn't sink the batch.
|
|
|
279
270
|
| "`modal run` it, the endpoint/schedule will stay up" | `run` is ephemeral; it exits. Use `modal deploy` for anything persistent. |
|
|
280
271
|
| "Order the decorators however — Modal figures it out" | `@app.function` outermost, web decorator innermost. Wrong order errors. |
|
|
281
272
|
| "Bake the HF token into the image with `run_commands`" | Leaks into layer history. Use `modal.Secret.from_name(...)`. |
|
|
282
|
-
| "Just call the model via a managed API through Modal" | If you write no container, that's a managed-API job → `replicate
|
|
283
|
-
| "I need a box to SSH into for a week" | That's a persistent rental → `runpod
|
|
273
|
+
| "Just call the model via a managed API through Modal" | If you write no container, that's a managed-API job → [`replicate`](../replicate/SKILL.md). |
|
|
274
|
+
| "I need a box to SSH into for a week" | That's a persistent rental → [`runpod`](../runpod/SKILL.md), not Modal's scale-to-zero. |
|
|
284
275
|
| "Set `min_containers` high so it's always fast" | Idle warm containers cost money 24/7. Tune `scaledown_window` first. |
|
|
285
276
|
|
|
286
|
-
##
|
|
277
|
+
## Verify
|
|
287
278
|
|
|
288
|
-
`scripts/verify.sh [TARGET]` statically lints the nearest emitted Modal
|
|
289
|
-
`modal.App(`, **fails** if the removed `modal.gpu.` object form appears,
|
|
290
|
-
decorator sits under an `@app.function`, and that any `Volume` uses
|
|
279
|
+
[`scripts/verify.sh`](scripts/verify.sh) `[TARGET]` statically lints the nearest emitted Modal
|
|
280
|
+
`*.py`: it requires a `modal.App(`, **fails** if the removed `modal.gpu.` object form appears,
|
|
281
|
+
checks that any web decorator sits under an `@app.function`, and that any `Volume` uses
|
|
291
282
|
`from_name(..., create_if_missing=...)`. It runs `python -c "import modal"` only if modal is
|
|
292
|
-
installed (skip-pass otherwise)
|
|
293
|
-
exits 0.
|
|
294
|
-
|
|
295
|
-
## Project grounding (02-DOCS + CLAUDE.md)
|
|
296
|
-
|
|
297
|
-
In a project with a `02-DOCS/` layer (the [`harness`](../harness/SKILL.md) wiki), record this
|
|
298
|
-
app's real Modal choices — GPU types, image base, Volume names, schedule, endpoint shape — in
|
|
299
|
-
`02-DOCS/wiki/stack/modal.md` and index it in `02-DOCS/wiki/index.md` (the Knowledge map; root
|
|
300
|
-
`CLAUDE.md` keeps only a short pointer to it). Read it
|
|
301
|
-
first on every use; create/update it with the real decisions. No `02-DOCS/`? Skip silently.
|
|
283
|
+
installed (skip-pass otherwise), needs **no Modal credentials**, and exits 0 on an empty target.
|
|
302
284
|
|
|
303
|
-
##
|
|
285
|
+
## Project grounding (02-DOCS)
|
|
304
286
|
|
|
305
|
-
- [`
|
|
306
|
-
-
|
|
307
|
-
|
|
308
|
-
|
|
287
|
+
In a project with a `02-DOCS/` layer (the [`harness`](../harness/SKILL.md) wiki), read
|
|
288
|
+
`02-DOCS/wiki/stack/modal.md` first, then record this app's real Modal choices there — GPU types,
|
|
289
|
+
image base, Volume names, schedule, endpoint shape — and index it in `02-DOCS/wiki/index.md`. No
|
|
290
|
+
`02-DOCS/`? Skip silently.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: newsletter
|
|
3
|
-
description: "Use when running an email newsletter as a recurring publication —
|
|
3
|
+
description: "Use when running an email newsletter as a recurring publication — subject + preview pair, issues that turn opens into clicks, the welcome sequence, cadence and engagement tiering, growth loops, and a post-Apple-MPP click scorecard. NOT one-off launch or nurture sends (that is `marketing`), NOT SPF/DKIM/DMARC (that is `email-deliverability`)."
|
|
4
4
|
tags: [newsletter, email, growth, copywriting, retention-metrics]
|
|
5
5
|
recommends: [marketing, email-deliverability, brand-voice, landing-copy, ab-testing]
|
|
6
6
|
profiles: []
|
|
@@ -11,29 +11,19 @@ origin: risco
|
|
|
11
11
|
|
|
12
12
|
Run the newsletter as a **product you ship on a cadence**, not a one-off send. The job is the system around the recurring issue: the subject + preview that earns the open, the issue body that earns the click, the welcome sequence that activates a new subscriber, the cadence and segmentation that keep the list healthy, the growth loops that compound it, and a scorecard that still tells the truth after Apple broke open rates. Every send is one episode of an ongoing show — design the show, not the episode.
|
|
13
13
|
|
|
14
|
-
## When to use
|
|
15
|
-
|
|
16
|
-
- Writing the subject line + preview text for an issue and fitting them to inbox truncation.
|
|
17
|
-
- Structuring a recurring issue so opens convert: hook on the first screen, scannable body, one CTA.
|
|
18
|
-
- Writing the welcome / onboarding sequence a confirmed subscriber gets.
|
|
19
|
-
- Planning send cadence, frequency, and engagement-based segmentation.
|
|
20
|
-
- Designing a growth loop: referral program, signup incentive / lead magnet, double opt-in.
|
|
21
|
-
- Choosing which metrics to trust now that Apple MPP inflates opens; building the scorecard.
|
|
22
|
-
- Rescuing a newsletter with high opens but no clicks, or a quietly decaying engaged-reader count.
|
|
23
|
-
|
|
24
14
|
## When NOT to use — route instead
|
|
25
15
|
|
|
26
16
|
| The ask | Route to |
|
|
27
17
|
|---|---|
|
|
28
18
|
| One-off product launch announcement or campaign drip nurture | `../marketing/SKILL.md` |
|
|
29
|
-
| Mail lands in spam; set up SPF / DKIM / DMARC, tracking domain, reputation |
|
|
19
|
+
| Mail lands in spam; set up SPF / DKIM / DMARC, tracking domain, reputation | `../email-deliverability/SKILL.md` |
|
|
30
20
|
| Write the subscribe / opt-in landing page copy | `../landing-copy/SKILL.md` |
|
|
31
21
|
| Define the house voice, tone, and vocabulary the newsletter speaks in | `../brand-voice/SKILL.md` |
|
|
32
|
-
| Win back / reactivate lapsed *paying customers* (lifecycle, not readers) |
|
|
22
|
+
| Win back / reactivate lapsed *paying customers* (lifecycle, not readers) | `../retention/SKILL.md` |
|
|
33
23
|
| Produce the underlying long-form articles the issue links out to | `../content-engine/SKILL.md` |
|
|
34
|
-
| Sample size / significance / MDE math for the test itself |
|
|
35
|
-
| Source or scrape new contacts; prospect an un-opted-in list |
|
|
36
|
-
| Actually wire the send through an ESP / Gmail API and schedule it |
|
|
24
|
+
| Sample size / significance / MDE math for the test itself | `../ab-testing/SKILL.md` |
|
|
25
|
+
| Source or scrape new contacts; prospect an un-opted-in list | `../lead-gen/SKILL.md`, `../cold-outreach/SKILL.md` |
|
|
26
|
+
| Actually wire the send through an ESP / Gmail API and schedule it | `../email-connector/SKILL.md`, `../google-workspace/SKILL.md` |
|
|
37
27
|
|
|
38
28
|
You own the *recurring opted-in publication and its open/click/growth system*. The plumbing under every send and the page that captures the signup are someone else's.
|
|
39
29
|
|
|
@@ -81,7 +71,7 @@ The subject and the preview (preheader) ship together and are tested together
|
|
|
81
71
|
- **Payload in the first ~33 characters**; keep the whole subject ~30–50 chars (≈7–9 words) so it survives mobile truncation.
|
|
82
72
|
- **The preview extends the subject, it never repeats it.** Its first ~35–50 chars are prime real estate; waste them on a duplicate and you've burned the line.
|
|
83
73
|
- **≤2 emojis, at the end, never an all-emoji subject** — an all-emoji subject is the one case that actually trips filters.
|
|
84
|
-
- **The "spam trigger words" list is a myth.** "Free", "guarantee", a normal emoji — these do not sink you; authentication and sender reputation dominate deliverability. Police reputation, not vocabulary; the reputation/auth layer lives in
|
|
74
|
+
- **The "spam trigger words" list is a myth.** "Free", "guarantee", a normal emoji — these do not sink you; authentication and sender reputation dominate deliverability. Police reputation, not vocabulary; the reputation/auth layer lives in `../email-deliverability/SKILL.md`.
|
|
85
75
|
|
|
86
76
|
```text
|
|
87
77
|
Bad (payload past char 33, preview repeats subject):
|
|
@@ -134,13 +124,13 @@ A newsletter is the canonical bulk marketing message, so the Gmail/Yahoo bulk-se
|
|
|
134
124
|
- **RFC 8058 one-click unsubscribe** (`List-Unsubscribe` + `List-Unsubscribe-Post` headers) on every send, plus a **visible footer unsubscribe link.** Both, always.
|
|
135
125
|
- **Keep the spam-complaint rate under 0.1%** and never let it reach 0.3%. This is why you sunset, not why you mail harder.
|
|
136
126
|
|
|
137
|
-
The DNS / authentication side of those rules — SPF, DKIM, DMARC, the sending domain — is **not this skill**; that is
|
|
127
|
+
The DNS / authentication side of those rules — SPF, DKIM, DMARC, the sending domain — is **not this skill**; that is `../email-deliverability/SKILL.md`. This skill applies the rules to the issue and the cadence.
|
|
138
128
|
|
|
139
129
|
## A/B testing the right way
|
|
140
130
|
|
|
141
131
|
- **Test exactly one element at a time** — subject vs subject, or preview vs preview. Change two and the winner is uninterpretable.
|
|
142
132
|
- **Put preview text in the rotation**, not just the subject; it's half the inbox row and usually under-tested.
|
|
143
|
-
- The statistical design — sample size, significance, minimum detectable effect — is
|
|
133
|
+
- The statistical design — sample size, significance, minimum detectable effect — is `../ab-testing/SKILL.md`. This skill tells you *what* to test; that one tells you whether the result is real.
|
|
144
134
|
|
|
145
135
|
## Anti-patterns
|
|
146
136
|
|
|
@@ -151,7 +141,7 @@ The DNS / authentication side of those rules — SPF, DKIM, DMARC, the sending d
|
|
|
151
141
|
| Preview text repeats the subject | Burns half the inbox row on a duplicate | Preview extends the subject with new info |
|
|
152
142
|
| Mailing a decaying list harder | Complaints climb; reputation and inbox placement collapse | Sunset / re-permission the dormant tier |
|
|
153
143
|
| All-emoji subject line | The one emoji case that actually trips filters | ≤2 emojis, at the end, around real words |
|
|
154
|
-
| Policing "spam trigger words" | A myth; reputation/auth decide deliverability | Fix auth + reputation in
|
|
144
|
+
| Policing "spam trigger words" | A myth; reputation/auth decide deliverability | Fix auth + reputation in `../email-deliverability/SKILL.md` |
|
|
155
145
|
| Buying a list / no double opt-in | Spam traps and complaints gate the whole sender | Double opt-in; grow with referral + lead magnet |
|
|
156
146
|
| Testing two variables at once | Winner is uninterpretable | One variable; preview in the rotation |
|
|
157
147
|
| Referral ask bolted on months later | Misses peak engagement | Put the ask inside the welcome sequence |
|
|
@@ -23,7 +23,7 @@ tiering. Numbers below are dated; treat them as calibration, not promises.
|
|
|
23
23
|
generic "join our newsletter."
|
|
24
24
|
- The asset doubles as shareable bait for the referral loop — make it good
|
|
25
25
|
enough to forward.
|
|
26
|
-
- The opt-in *page* and its copy are
|
|
26
|
+
- The opt-in *page* and its copy are `../../landing-copy/SKILL.md`; this skill owns
|
|
27
27
|
what the incentive is and how it ties into the welcome + referral flow.
|
|
28
28
|
|
|
29
29
|
## Opt-in: single vs double
|
|
@@ -64,10 +64,10 @@ this? click to stay") and, if no click, a **sunset** off the active list.
|
|
|
64
64
|
is the lever that protects it. (Yahoo Sender Hub best practices; Google
|
|
65
65
|
Workspace sender guidelines — accessed 2026-06-02.)
|
|
66
66
|
- Re-permission is a newsletter-list hygiene step. Lifecycle reactivation of
|
|
67
|
-
lapsed *paying customers* is a different job — that is
|
|
67
|
+
lapsed *paying customers* is a different job — that is `../../retention/SKILL.md`.
|
|
68
68
|
|
|
69
69
|
## Send-time hypothesis
|
|
70
70
|
|
|
71
71
|
Tuesday/Thursday ~10am or 1–3pm is the cross-industry baseline starting point.
|
|
72
72
|
It is a hypothesis to test against your own list's click data, never a fixed law.
|
|
73
|
-
The test design (sample size, significance) is
|
|
73
|
+
The test design (sample size, significance) is `../../ab-testing/SKILL.md`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: prompt-engineering
|
|
3
|
-
description: "Use when one prompt
|
|
3
|
+
description: "Use when one prompt must give the same right answer across reruns, models, and pasted-in hostile input: forcing a fixed schema, picking the few-shot set, ordering the prompt blocks, or the inline cases you run while tuning. NOT the agent loop, tools, or retrieval (that is `building-agents`), NOT a standing CI eval harness (that is `agent-eval`)."
|
|
4
4
|
tags: [prompts, llm, few-shot, structured-output, evals]
|
|
5
5
|
recommends: [building-agents, agent-eval, structured-extraction]
|
|
6
6
|
origin: risco
|
|
@@ -10,12 +10,6 @@ origin: risco
|
|
|
10
10
|
|
|
11
11
|
You are tuning a single prompt so it produces the same correct output across reruns, across models, and against adversarial input. This is the craft layer — the prompt artifact itself: its block order, its few-shot set, its output contract, and the small eval that proves it. The systems layer (loop, tools, retrieval) is `../building-agents/SKILL.md`.
|
|
12
12
|
|
|
13
|
-
## The one rule
|
|
14
|
-
|
|
15
|
-
> A prompt is not done until it passes a small eval set you wrote **before** you started tuning. Without cases you are fiddling — changing words and trusting a vibe. With 5-15 cases, every edit is a measurement.
|
|
16
|
-
|
|
17
|
-
Write the cases first. They define "right answer" before you fall in love with a phrasing.
|
|
18
|
-
|
|
19
13
|
## Prompt skeleton (this order)
|
|
20
14
|
|
|
21
15
|
Order the blocks so the model reads identity and task before it sees the (untrusted) input. Each block earns its place:
|
|
@@ -86,11 +80,11 @@ Good (range: normal / awkward / edge):
|
|
|
86
80
|
- **Re-state the task after the input** for long inputs. Why: when the input is huge, early instructions fall out of attention — this is the cause of "the model ignores my instructions on long inputs".
|
|
87
81
|
- **Phrase constraints positively.** "Output only the category" survives; "don't add commentary" invites the model to negotiate.
|
|
88
82
|
- **Add a refusal anchor** — one explicit branch for out-of-contract input (`If the ticket is empty or unreadable, output: other`). Why: undefined behavior is where injections and drift live.
|
|
89
|
-
- System-scope abuse handling — refusal policy, monitoring, jailbreak defense across a product — is
|
|
83
|
+
- System-scope abuse handling — refusal policy, monitoring, jailbreak defense across a product — is `../agent-safety/SKILL.md`, not this skill. Here you harden one prompt.
|
|
90
84
|
|
|
91
|
-
## Inline evals
|
|
85
|
+
## Inline evals — write these first
|
|
92
86
|
|
|
93
|
-
|
|
87
|
+
A prompt is not done until it passes a small eval set you wrote **before** you started tuning: 5-15 cases next to the prompt, run before AND after every change. Cases fix what "right answer" means before you fall in love with a phrasing — without them you are fiddling, changing words and trusting a vibe; with them every edit is a measurement.
|
|
94
88
|
|
|
95
89
|
```yaml
|
|
96
90
|
# prompt-eval cases for the triage prompt
|
|
@@ -112,7 +106,7 @@ cases:
|
|
|
112
106
|
expect: { equals: "billing" } # input treated as data, not command
|
|
113
107
|
```
|
|
114
108
|
|
|
115
|
-
Assert on the contract: schema-valid, exact token, contains/not-contains. Keep them in the repo beside the prompt. The standing harness — golden set, LLM-as-judge, CI regression gate, metrics — is
|
|
109
|
+
Assert on the contract: schema-valid, exact token, contains/not-contains. Keep them in the repo beside the prompt; `references/eval-templates.md` has the cases.yaml shape, assertion helpers, and a before/after diff runner. The standing harness — golden set, LLM-as-judge, CI regression gate, metrics — is `../agent-eval/SKILL.md`; this is the small inline set you run while tuning.
|
|
116
110
|
|
|
117
111
|
## Iterate one variable at a time
|
|
118
112
|
|
|
@@ -131,8 +125,3 @@ Assert on the contract: schema-valid, exact token, contains/not-contains. Keep t
|
|
|
131
125
|
| 3 near-identical few-shot examples | Teaches one shape, wastes tokens | 3 deliberately different: normal / awkward / edge |
|
|
132
126
|
| Negative-only constraints ("don't…") | Invites negotiation, ignored on long input | Phrase positively; re-state task after long input |
|
|
133
127
|
| Tuning by vibe, no cases | You are fiddling, not engineering | Write 5-15 cases first; measure each edit |
|
|
134
|
-
|
|
135
|
-
## References
|
|
136
|
-
|
|
137
|
-
- `references/output-contracts.md` — per-provider strict-output recipes, schema surface (pydantic/zod), streaming caveat, retry-on-parse-fail loop.
|
|
138
|
-
- `references/eval-templates.md` — cases.yaml shape, assertion helpers, before/after diff runner, DSPy MIPROv2-vs-GEPA when-to-optimize note.
|
|
@@ -10,7 +10,7 @@ should_trigger:
|
|
|
10
10
|
- prompt: "Make this prompt enforce a fixed schema reliably instead of sometimes returning prose."
|
|
11
11
|
why: "Forcing a fixed schema out of a model — the output-contract decision table (strict json_schema / strict tool use vs JSON mode)."
|
|
12
12
|
- prompt: "Write me a small eval set to check this prompt before I change it."
|
|
13
|
-
why: "Inline eval set authored before tuning —
|
|
13
|
+
why: "Inline eval set authored before tuning — the discipline the 'Inline evals — write these first' section exists to enforce; the small set, not a standing harness."
|
|
14
14
|
- prompt: "Users can paste 'ignore your instructions' into my input field and the model obeys it."
|
|
15
15
|
why: "Prompt-scope injection hardening — delimiting untrusted input and treating it as data, a named robustness rule."
|
|
16
16
|
- prompt: "I'm moving this prompt from one model to another and the behavior shifted; how do I keep it stable?"
|