SuperAPI AI Directory

substack-tools

Writing & research

View repository

Updated 10-16 04:38

About this skill

Substack Tools

CLI to automate Substack post management: draft, schedule, publish, list, sections, batch operations + scan/crawl other newsletters (fetch all posts via archive API). Uses python-substack (reverse-engineered) + public JSON API (/api/v1/).

Initial setup

Dependencies

test -d ~/.venv/claude || uv venv ~/.venv/claude
uv pip install --python ~/.venv/claude/bin/python python-substack feedparser httpx beautifulsoup4 markdownify

Configure credentials

The script needs 2 variables: SUBSTACK_COOKIE and SUBSTACK_PUBLICATION_URL. Lookup order: env var → .env in the skill directory → .env in CWD.

How When
Env var (~/.zshrc) Use frequently — set once, use forever
File .env Multiple publications — one per directory .env (needs python-dotenv)

Get cookie: Substack dashboard (logged in) → F12 → Application → Cookies → copy substack.sid. Expires after 1-2 weeks.

First-time setup details → setup-guide.

Commands

PY=~/.venv/claude/bin/python
SCRIPT=<skill-path>/scripts/substack_cli.py

draft — Create draft

$PY $SCRIPT draft ARTICLE.md COVER.png [--section "Tên section"] [--subtitle "..."]
  • ARTICLE.md: line 1 = title (auto strip #), line 2+ = body markdown
  • COVER.png: upload to Substack S3, insert at the top of the post as cover + inline image

schedule — Create draft + schedule

$PY $SCRIPT schedule ARTICLE.md COVER.png --at 2026-04-20T09:00:00 [--audience everyone]
Flag Default Value
--at required ISO 8601. No timezone → use local. With timezone → use as is
--audience everyone everyone / only_paid / only_free / founding

publish — Create draft + publish immediately

$PY $SCRIPT publish ARTICLE.md COVER.png [--no-send]

WARNING: not reversible. The post goes public immediately, the email sent to subscribers cannot be recalled. Always ask the user for confirmation before running publish.

publish-existing — Publish an existing draft

$PY $SCRIPT publish-existing DRAFT_ID [--no-send]

unschedule — Cancel schedule, revert to draft

$PY $SCRIPT unschedule DRAFT_ID

list — List posts

$PY $SCRIPT list [--filter draft|scheduled|published|all] [--limit 25]

sections — List newsletter sections

$PY $SCRIPT sections

set-section — Assign a section to multiple drafts

$PY $SCRIPT set-section "Tên Section" DRAFT_ID1 DRAFT_ID2 ...

Scan / Crawl other newsletters (read-only, no auth needed)

scan — Scan the post list

$PY $SCRIPT scan <slug> [--limit 10] [--json] [--all]
  • slug: Substack slug (e.g.: platformer), full URL, or domain
  • Display a table: date, author, title
  • --json: output JSON instead of a table
  • --all: fetch ALL posts via archive API (by default uses RSS, max ~25 posts)

crawl — Download 1 post as .md

$PY $SCRIPT crawl <URL> [--output-dir ./crawled]
  • Download the full post, convert HTML → Markdown, save with YAML frontmatter
  • Skip if the file already exists (idempotent)

crawl-feed — Batch download N posts from the feed

$PY $SCRIPT crawl-feed <slug> [--limit 5] [--output-dir ./crawled] [--all]
  • Default: download the N latest posts from RSS
  • --all: download ALL posts via archive API (ignores --limit)
  • Automatic random 2-5s delay between each post (avoid rate limit)

Troubleshooting details → crawl-guide.

Common flags

  • --dry-run: print payload, do not call API. Place AFTER the subcommand name.
  • --section "...": assign post to section (applies to draft/schedule/publish).
  • --subtitle "...": subtitle displayed below the title.

Action boundaries

Do it yourself Must ask the user first
draft, schedule, list, sections, set-section, unschedule publish / publish-existing — sends a real email, cannot be recalled
scan, crawl, crawl-feed (read-only) Delete a published post
--dry-run to check the payload

Do not commit .env — contains auth cookies.

Reference documentation

  • references/setup-guide.md — details on configuring credentials for the first time
  • references/api-quirks.md — endpoint quirks, rate limit, troubleshooting
  • references/batch-operations.md — delay + retry pattern for batch schedule
  • references/crawl-guide.md — troubleshooting scan/crawl: selectors, rate limit, paywall