$npx -y skills add mphinance/alpha-skills --skill mph-substack-publishEnd-to-end Substack pipeline. Take a subject, produce a draft (or publish it) at mphinance.substack.com. Chains mph-substack-writer (voice) + mph-figure (images) + the local create_draft_from_md.py pusher. Triggers on "write a Substack about X", "draft a post on Y", "publish to S
| 1 | # MPH Substack Publish |
| 2 | |
| 3 | End-to-end pipeline. Subject in → draft in mphinance.substack.com out (or published post if asked explicitly). |
| 4 | |
| 5 | ## Inputs |
| 6 | |
| 7 | - **Subject** (required) — what the post is about. One line is fine; longer briefs are better. |
| 8 | - **Mode** (default: `draft`) — `draft` creates a draft only. `publish` calls `/api/v1/drafts/{id}/publish` after the draft lands. **Always confirm explicitly with Michael before `publish` mode** — that triggers the subscriber email blast and is not reversible. |
| 9 | - **Post category** (inferred from subject, or asked once if ambiguous): |
| 10 | - `builder` — build-in-public, tool launches, code drops. No NFA needed. **Default.** |
| 11 | - `trade` — specific positions / picks / "I bought X". NFA disclaimer required. |
| 12 | - `paid_tease` — free post with a paywalled follow-up; include the "what's behind the paywall" section. |
| 13 | - `recovery` — personal / sappy / non-finance reflection. No NFA. |
| 14 | |
| 15 | ## Pipeline |
| 16 | |
| 17 | 1. **Read the voice corpus.** Read `~/.claude/skills/mph-substack-writer/SKILL.md` and `~/.claude/skills/mph-voice-refresh/VOICE.md`. The hard rules and RETIRED phrases there supersede anything else. |
| 18 | |
| 19 | 2. **Pick a slug + workspace.** |
| 20 | - Slug: `YYYY-MM-DD_kebab-case-title` |
| 21 | - Workspace: `~/.mph-substack-cache/<slug>/` (create if missing). All intermediate files live here, not in the project repo. NEVER write Substack drafts to `docs/substack/drafts/` anymore — Michael does not want post markdown checked into git. |
| 22 | |
| 23 | 3. **Draft the post** following the mph-substack-writer skeleton: |
| 24 | - H1 title (Title Case, terse) |
| 25 | - One-line italic subtitle (the "dek") |
| 26 | - Optional `` reference |
| 27 | - Bold opener (1-2 short paragraphs) |
| 28 | - Context section |
| 29 | - The meat (data + figures + voice) |
| 30 | - "Here's the truth..." pivot |
| 31 | - Optional paywall tease (for `paid_tease` category) |
| 32 | - **Standardized footer** (see template below — do NOT improvise this) |
| 33 | |
| 34 | 4. **Render any figures.** For tables, comparison cards, stat blocks — write HTML in the workspace folder, render via mph-figure: |
| 35 | ``` |
| 36 | node ~/.claude/skills/mph-figure/scripts/render.mjs --in <workspace>/foo.html --out <workspace>/foo.png --html |
| 37 | ``` |
| 38 | Reference in markdown as ``. Substack will receive these as uploaded S3 images. |
| 39 | |
| 40 | 5. **Push to Substack** via the script (handles image upload + ProseMirror conversion + cover image). The pusher lives in the mphinance repo, but the repo path differs per machine, so resolve it for wherever you're running: |
| 41 | - Windows workstation: `C:/Users/mphan/OneDrive/Documents/GitHub/mphinance/substack_social/create_draft_from_md.py` |
| 42 | - Coolify/Linux box (user `mph`): `~/mphinance/substack_social/create_draft_from_md.py` |
| 43 | - Otherwise: find it with `git rev-parse --show-toplevel` from inside the mphinance checkout, or `find ~ -path '*substack_social/create_draft_from_md.py'`. |
| 44 | |
| 45 | ``` |
| 46 | python <pusher> <workspace>/post.md |
| 47 | ``` |
| 48 | It prints the edit URL. Surface that URL to Michael. |
| 49 | |
| 50 | 6. **If mode is `publish`** (only with Michael's explicit confirmation): |
| 51 | - Run `python <pusher> <workspace>/post.md --publish` (same `<pusher>` resolved in step 5) |
| 52 | - Surface the live post URL. |
| 53 | |
| 54 | ## Standardized footer template |
| 55 | |
| 56 | Use one of these three at the end of EVERY post. Replace the `---` separator with markdown horizontal rule (Substack handles it). Do not improvise alternative sign-offs or CTAs; consistency matters more than novelty here. |
| 57 | |
| 58 | ### `builder` (default) — no NFA |
| 59 | |
| 60 | ``` |
| 61 | — Michael |
| 62 | |
| 63 | --- |
| 64 | |
| 65 | *If this helped, subscribe so the next one lands in your inbox.* |
| 66 | ``` |
| 67 | |
| 68 | ### `trade` — with NFA |
| 69 | |
| 70 | ``` |
| 71 | — Michael |
| 72 | |
| 73 | --- |
| 74 | |
| 75 | *Not financial advice. Do your own research. Don't trade on someone else's conviction.* |
| 76 | |
| 77 | *If this helped, subscribe so the next one lands in your inbox.* |
| 78 | ``` |
| 79 | |
| 80 | ### `paid_tease` — with paywall section above the footer |
| 81 | |
| 82 | ``` |
| 83 | ## What's behind the paywall |
| 84 | |
| 85 | [one-paragraph tease of the paid follow-up — what it covers, when it drops, why it's worth paying for] |
| 86 | |
| 87 | — Michael |
| 88 | |
| 89 | --- |
| 90 | |
| 91 | *If this helped, subscribe so the next one lands in your inbox. Paid subs get the deep version on [day].* |
| 92 | ``` |
| 93 | |
| 94 | ## Path note (works from any CWD) |
| 95 | |
| 96 | The pusher script `create_draft_from_md.py` lives in the mphinance repo. The absolute path above means this skill works whether Claude is invoked from the mphinance repo, a different repo, or anywhere else. If Michael moves the repo, update the path in this SKILL.md. |
| 97 | |
| 98 | The script reads `secrets.env` from the mphinance repo automatically (resolved relative to the script's parent dir), so SUBSTACK_SID lookup works regardless of CWD. |
| 99 | |
| 100 | ## Hard rules (enforced) |
| 101 | |
| 102 | - **Sign-off is exactly `— Michael`.** No last name. No |