promote
Generate X/Twitter release promotion posts with ASCII tables and CodeSnap rendering. Use when writing release posts, promotion tweets, plugin announcements, or preparing social media content for new versions.
Install
npx skills add https://github.com/oliver-kriska/claude-elixir-phoenix/tree/main/.claude/skills/promote
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install oliver-kriska-claude-elixir-phoenix@llmmart
git clone https://github.com/oliver-kriska/claude-elixir-phoenix.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole oliver-kriska/claude-elixir-phoenix collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
/promote — Release Promotion Post Generator
Generate data-driven X/Twitter posts for plugin releases with ASCII cards ready for CodeSnap screenshots.
When to use
Run /promote vX.Y.Z after tagging a release. Optionally add a title: /promote v2.8.0 "LiveView Streams Overhaul".
Output
All files go to scratchpad/x-posts/{version}-release.md (create directory if needed).
The output file contains three sections:
- ASCII Card — box-drawing table for CodeSnap screenshot
- Tweet Thread — 3-5 tweets in proven format
- CodeSnap Command — exact CLI command to render the card
- Fact-Check — every claim with verifiable data source
Execution Flow
Step 1: Gather Data
Collect these metrics (all are verifiable commands — run them, don't estimate):
| Metric | How to get it |
|---|---|
| File count + insertions/deletions | git diff --stat {prev-tag}..{tag} |
| Skill count | ls plugins/elixir-phoenix/skills/ \| wc -l |
| Agent count | ls plugins/elixir-phoenix/agents/*.md \| wc -l |
| Iron Law count | Grep for numbered Iron Laws in CLAUDE.md |
| Eval scores | make eval-all (run it, report actual numbers) |
| Changelog entries | Read CHANGELOG.md for this version's section |
| Before/after metrics | Depends on release — look for quantifiable changes |
The strongest posts have before/after comparisons. Look for changes in CHANGELOG.md that have measurable deltas (line counts, counts of affected files, error rates, coverage numbers).
Step 2: Write the ASCII Card
The card is the visual centerpiece — it gets screenshotted via CodeSnap and attached to tweet 1.
Rules:
- Exactly 72 characters wide (including borders) — consistent with past posts
- Use Unicode box-drawing:
┌─┐│└┘╞═╡╤╪╧for borders and separators - Include: version + title, headline stats, before/after table, repo URL
- The table content comes from Step 1 data — pick the 3-5 most impressive changes
- VERIFY ALIGNMENT: After writing the table, run a Python script to check every line has the same visual width. Off-by-one errors are the most common problem — em dashes (
—) and arrows (→) are single-width but easy to miscount. Every line between the top┌and bottom└borders must be exactly 72 visual characters
Also save the ASCII card as a separate .txt file at scratchpad/x-posts/{version}-table.txt for CodeSnap input.
See ${CLAUDE_SKILL_DIR}/references/templates.md for the proven card format and past examples.
Step 3: Write the Tweet Thread
Follow the hook → findings → details → CTA structure. Read ${CLAUDE_SKILL_DIR}/references/templates.md for proven tweet patterns.
Thread rules (from analytics on 7 posts, 6.9K-9.9K views):
- Tweet 1 (Hook): Version + one compelling sentence about what changed. Include headline stats (files changed, skills, agents). Repo link here — not in a reply. Add
#ElixirLang #ClaudeCodehashtags. - Tweet 2-3 (Findings): The specific changes with numbers. Use numbered lists. Before/after metrics are the highest-performing content type.
- Tweet 4-5 (Details/CTA): Additional changes + soft CTA ("Try it and let me know how it feels"). Link to release page.
- Max 5 tweets — casual readers drop off after 4-6. If you have more content, cut the least impactful items.
Voice and tone:
- Data-heavy, transparent, no-hype — this is the proven #1 strength
- Write like a builder sharing real numbers, not a marketer
- Concrete numbers over adjectives ("32/40 descriptions rewritten" not "improved many descriptions")
- Never mention API costs or token prices — subscription user, cost per call is irrelevant
Step 4: CodeSnap Command
Output the exact command to render the ASCII card as an image. The card .txt file from Step 2 is the input.
Use the config file at scratchpad/x-posts/codesnap-claude-dark.json (dark gradient, tight margins, no watermark):
codesnap -f scratchpad/x-posts/{version}-table.txt \
-o scratchpad/x-posts/{version}-card.png \
--config scratchpad/x-posts/codesnap-claude-dark.json \
--title "claude-elixir-phoenix {version}" \
-l text
Then render and verify the image looks correct by reading the output PNG.
Step 5: Fact-Check
Every claim in the tweets must have a corresponding entry in the fact-check section:
## Fact-Check
- File stats: `git diff --stat {prev}..{tag}` (output: N files, +X/-Y)
- Eval scores: `make eval-all` output — N skills avg X.XXX, N agents X.XXX
- [claim]: [exact command or file:line that proves it]
If a claim can't be verified with a command or file reference, flag it as UNVERIFIED and suggest rewording.
Bundling Strategy
When deciding whether a release warrants its own post:
- Standalone post: Major features, impressive before/after metrics, new capabilities
- Bundle with next release: Bug fixes, description tweaks, minor config changes
- Skip entirely: Patch releases with <5 files changed and no user-facing changes
The v2.6.1 post (37 likes, 1.4K views) vs v2.6.0 (150 likes, 5.5K views) demonstrates this — back-to-back releases dilute signal. When in doubt, wait and bundle.
Files (claude-elixir-phoenix)
-
references
-
templates.md 8.5 KB
# Proven Post Templates Reference patterns extracted from 7 promotional posts (Feb-Apr 2026). Analytics: 144 likes / 9.9K views at peak, 153 bookmarks on announcement. ## ASCII Card Template Use Unicode box-drawing characters for a polished look. Every line must be **exactly 72 visual characters wide**. After writing, verify alignment with a Python script (see Verification section below). ``` ┌──────────────────────────────────────────────────────────────────────┐ │ │ │ Elixir/Phoenix Plugin vX.Y.Z — Short Title │ │ N files changed | +N lines | N skills | N agents │ │ │ ╞═══════════════════════════════════╤══════════╤═══════════════════════╡ │ Change │ Before │ After │ ╞═══════════════════════════════════╪══════════╪═══════════════════════╡ │ Row 1 description │ val │ val │ │ Row 2 description │ val │ val │ │ Row 3 description │ val │ val │ │ Row 4 description │ val │ val │ ╞═══════════════════════════════════╧══════════╧═══════════════════════╡ │ │ │ Additional context line if needed │ │ │ │ github.com/oliver-kriska/claude-elixir-phoenix │ │ │ └──────────────────────────────────────────────────────────────────────┘ ``` ### Column widths The table area between `╞` borders has 3 columns: - Col 1 (Change): 35 chars - Col 2 (Before): 10 chars - Col 3 (After): 23 chars ### Verification After writing the table, run this to verify all lines are 72 chars: ```python import unicodedata def vw(s): return sum(2 if unicodedata.east_asian_width(c) in ('F','W') else 1 for c in s) lines = open('scratchpad/x-posts/{version}-table.txt').read().strip().split('\n') target = vw(lines[0]) for i, line in enumerate(lines): w = vw(line) if w != target: print(f"L{i+1}: {w} chars (expected {target}): {line}") ``` If any line is off, add or remove spaces before the closing `│`. ### Alternatives For releases without before/after data (new features only): ``` ┌──────────────────────────────────────────────────────────────────────┐ │ │ │ Elixir/Phoenix Plugin vX.Y.Z — Title │ │ N files changed | +N lines │ │ │ │ What's new: │ │ · Feature 1 description │ │ · Feature 2 description │ │ · Feature 3 description │ │ │ │ github.com/oliver-kriska/claude-elixir-phoenix │ │ │ └──────────────────────────────────────────────────────────────────────┘ ``` ## Tweet Thread Patterns ### Pattern A: Changelog Audit (v2.7.0 — 4 tweets, 670 views early) **Tweet 1**: Version + what prompted the release ("Claude Code shipped 46 releases since we last checked"). Headline stats. Repo link. **Tweet 2**: Numbered list of what was found/fixed. Before/after where possible. **Tweet 3**: Secondary feature with depth (Oban Pro rewrite, from real incident). **Tweet 4**: CTA + release link. "If you're building Elixir/Phoenix with Claude Code, try it." ### Pattern B: Source-Informed (v2.6.1 — 3 tweets, 1.4K views) **Tweet 1**: What triggered the work ("I asked Claude to go through TypeScript source"). Headline stats. Repo link. **Tweet 2**: Numbered findings — each with concrete numbers. "80% of descriptions silently truncated" > "many descriptions were too long." **Tweet 3**: Smaller changes as bullet list + eval scores + CTA. ### Pattern C: Metrics-Driven (v2.4.0 — standalone, 3.8K views) **Single tweet**: Version + headline. Before/after metrics as formatted list. Brief explanation of changes. File stats. Repo link. Best for releases with strong quantitative improvements. No thread needed. ### Pattern D: Deep-Dive (reply thread — 9.9K views, highest) Reply to a relevant conversation in the Claude Code space. Share your experience and data. This gets the highest views because it piggybacks on existing engagement. Best used opportunistically, not for every release. ### Pattern E: Long-Form (v2.6.0 — 150 likes, best overall) **7-9 tweets** covering a major milestone. Data-heavy throughout. Works when the content is genuinely excellent (self-improving skills, 0/8 → 8/8 eval scores). Risk: longer threads lose casual readers. Only use for truly big releases. ## Top-Performing Elements (from analytics) | Element | Impact | Example | |---------|--------|---------| | Before/after metrics | Highest engagement | "340K → 120K tokens (-65%)" | | Concrete numbers | High trust signal | "32/40 descriptions rewritten under 200 chars" | | Real incident stories | High bookmarks | "72k+ orphaned jobs before someone caught it" | | Transparent methodology | Builds authority | "Validated across 75 real sessions" | | Eval scores | Credibility closer | "All 51 skills pass eval (avg 0.986)" | ## Anti-Patterns (from analytics) | What | Why it hurts | |------|-------------| | Back-to-back releases | v2.6.1 got 37 likes vs v2.6.0's 150 — diluted signal | | Threads >6 tweets | Casual readers drop after 4-6 | | Missing hashtags | Recent posts without #ElixirLang got lower discoverability | | API cost mentions | User uses subscription — per-call costs are irrelevant | | Hype language | "Game-changer" / fire emojis erode dev trust | | Vague claims | "Improved performance" < "340K → 120K tokens (-65%)" | ## CodeSnap Rendering **ALWAYS render via the config file, never inline color flags.** Current `codesnap` ignores a single-color `--background` when a theme gradient is set ("candy" theme → bright green gradient). The config's structured `background.stops` is the only reliable override. This is the canonical command (matches every prior correct card, e.g. v280): ```bash codesnap \ -f scratchpad/x-posts/{version}-table.txt \ -o scratchpad/x-posts/{version}-card.png \ --config scratchpad/x-posts/codesnap-claude-dark.json \ --title "claude-elixir-phoenix {version}" \ -l text ``` `codesnap-claude-dark.json` (committed in `scratchpad/x-posts/`) sets the dark gradient (`#0f1115` → `#1a1f2b`), mac window bar, border, JetBrains Mono, and an **empty watermark**. Default for all releases. Always `Read` the output PNG to confirm: dark background, no green, no watermark, table aligned. > **Do NOT** use the old inline-flag form > (`--background "#0f1115" --watermark … --shadow-radius …`). It > rendered correctly in April but the current codesnap leaves the > green "candy" gradient and adds an unwanted watermark. For a > celebratory accent variant, copy the config to a `*-accent.json` > and change `background.stops` + `title_config.color` there — keep > it config-driven.
-
-
SKILL.md 5.4 KB
--- name: promote description: Generate X/Twitter release promotion posts with ASCII tables and CodeSnap rendering. Use when writing release posts, promotion tweets, plugin announcements, or preparing social media content for new versions. effort: medium --- # /promote — Release Promotion Post Generator Generate data-driven X/Twitter posts for plugin releases with ASCII cards ready for CodeSnap screenshots. ## When to use Run `/promote vX.Y.Z` after tagging a release. Optionally add a title: `/promote v2.8.0 "LiveView Streams Overhaul"`. ## Output All files go to `scratchpad/x-posts/{version}-release.md` (create directory if needed). The output file contains three sections: 1. **ASCII Card** — box-drawing table for CodeSnap screenshot 2. **Tweet Thread** — 3-5 tweets in proven format 3. **CodeSnap Command** — exact CLI command to render the card 4. **Fact-Check** — every claim with verifiable data source ## Execution Flow ### Step 1: Gather Data Collect these metrics (all are verifiable commands — run them, don't estimate): | Metric | How to get it | |--------|---------------| | File count + insertions/deletions | `git diff --stat {prev-tag}..{tag}` | | Skill count | `ls plugins/elixir-phoenix/skills/ \| wc -l` | | Agent count | `ls plugins/elixir-phoenix/agents/*.md \| wc -l` | | Iron Law count | Grep for numbered Iron Laws in CLAUDE.md | | Eval scores | `make eval-all` (run it, report actual numbers) | | Changelog entries | Read CHANGELOG.md for this version's section | | Before/after metrics | Depends on release — look for quantifiable changes | The strongest posts have **before/after comparisons**. Look for changes in CHANGELOG.md that have measurable deltas (line counts, counts of affected files, error rates, coverage numbers). ### Step 2: Write the ASCII Card The card is the visual centerpiece — it gets screenshotted via CodeSnap and attached to tweet 1. Rules: - **Exactly 72 characters wide** (including borders) — consistent with past posts - Use Unicode box-drawing: `┌─┐│└┘╞═╡╤╪╧` for borders and separators - Include: version + title, headline stats, before/after table, repo URL - The table content comes from Step 1 data — pick the 3-5 most impressive changes - **VERIFY ALIGNMENT**: After writing the table, run a Python script to check every line has the same visual width. Off-by-one errors are the most common problem — em dashes (`—`) and arrows (`→`) are single-width but easy to miscount. Every line between the top `┌` and bottom `└` borders must be exactly 72 visual characters Also save the ASCII card as a separate `.txt` file at `scratchpad/x-posts/{version}-table.txt` for CodeSnap input. See `${CLAUDE_SKILL_DIR}/references/templates.md` for the proven card format and past examples. ### Step 3: Write the Tweet Thread Follow the **hook → findings → details → CTA** structure. Read `${CLAUDE_SKILL_DIR}/references/templates.md` for proven tweet patterns. **Thread rules (from analytics on 7 posts, 6.9K-9.9K views):** - **Tweet 1 (Hook)**: Version + one compelling sentence about what changed. Include headline stats (files changed, skills, agents). Repo link here — not in a reply. Add `#ElixirLang #ClaudeCode` hashtags. - **Tweet 2-3 (Findings)**: The specific changes with numbers. Use numbered lists. Before/after metrics are the highest-performing content type. - **Tweet 4-5 (Details/CTA)**: Additional changes + soft CTA ("Try it and let me know how it feels"). Link to release page. - **Max 5 tweets** — casual readers drop off after 4-6. If you have more content, cut the least impactful items. **Voice and tone:** - Data-heavy, transparent, no-hype — this is the proven #1 strength - Write like a builder sharing real numbers, not a marketer - Concrete numbers over adjectives ("32/40 descriptions rewritten" not "improved many descriptions") - Never mention API costs or token prices — subscription user, cost per call is irrelevant ### Step 4: CodeSnap Command Output the exact command to render the ASCII card as an image. The card `.txt` file from Step 2 is the input. Use the config file at `scratchpad/x-posts/codesnap-claude-dark.json` (dark gradient, tight margins, no watermark): ``` codesnap -f scratchpad/x-posts/{version}-table.txt \ -o scratchpad/x-posts/{version}-card.png \ --config scratchpad/x-posts/codesnap-claude-dark.json \ --title "claude-elixir-phoenix {version}" \ -l text ``` Then render and verify the image looks correct by reading the output PNG. ### Step 5: Fact-Check Every claim in the tweets must have a corresponding entry in the fact-check section: ```markdown ## Fact-Check - File stats: `git diff --stat {prev}..{tag}` (output: N files, +X/-Y) - Eval scores: `make eval-all` output — N skills avg X.XXX, N agents X.XXX - [claim]: [exact command or file:line that proves it] ``` If a claim can't be verified with a command or file reference, flag it as **UNVERIFIED** and suggest rewording. ## Bundling Strategy When deciding whether a release warrants its own post: - **Standalone post**: Major features, impressive before/after metrics, new capabilities - **Bundle with next release**: Bug fixes, description tweaks, minor config changes - **Skip entirely**: Patch releases with <5 files changed and no user-facing changes The v2.6.1 post (37 likes, 1.4K views) vs v2.6.0 (150 likes, 5.5K views) demonstrates this — back-to-back releases dilute signal. When in doubt, wait and bundle.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.