← 返回
未分类 Key 中文

Substack

Publish, edit, and manage Substack posts for the Alternative Partners publication (alternativepartners.substack.com) via the internal REST API. Use this skil...
通过内部 REST API 为 Alternative Partners 刊物(alternativepartners.substack.com)发布、编辑和管理 Substack 帖子。
breynol01 breynol01 来源
未分类 clawhub v1.0.0 1 版本 100000 Key: 需要
★ 0
Stars
📥 438
下载
💾 0
安装
1
版本
#latest

概述

Substack Skill

Manages publishing and editing for the Alternative Partners Substack publication via the internal REST API. No Playwright, no browser — pure requests with a session cookie.

Auth

This skill requires a connect.sid session cookie from Substack. Store it securely and provide it as the SUBSTACK_SID environment variable (or equivalent in your secrets manager).

This is the connect.sid cookie. Valid for months unless you sign out of Substack in Chrome. To rotate: sign out of Substack → sign back in → open DevTools → copy substack.sid cookie value → update your secrets store.

The publisher module at publishers/substack.py handles auth automatically. Always use it rather than calling the API directly.


API Endpoints (alternativepartners.substack.com)

ActionMethodEndpoint
--------------------------
Create draftPOST/api/v1/drafts
Publish draftPOST/api/v1/drafts/{id}/publish
Update existing postPUT/api/v1/drafts/{id}
Fetch post by slugGET/api/v1/posts/{slug}
List postsGET/api/v1/posts?limit=N

Key discovery (2026-03-20): PUT /api/v1/drafts/{id} works on already-published posts too — it edits them in place. The post ID is the same as the draft ID used to create it.

Does NOT exist: PUT /api/v1/posts/{id} returns 404. Always use the /drafts/{id} endpoint even for published posts.


Body Format

Substack uses ProseMirror JSON for post bodies. The publisher converts plain text → ProseMirror automatically.

Input format: Plain text with double-newline paragraph breaks.

Output format (internal): ProseMirror doc object, serialized as a JSON string and passed as draft_body.

def _build_prosemirror_doc(body: str) -> dict:
    paragraphs = [p.strip() for p in body.strip().split("\n\n") if p.strip()]
    return {
        "type": "doc",
        "content": [
            {"type": "paragraph", "content": [{"type": "text", "text": p}]}
            for p in paragraphs
        ]
    }

Limitation: This produces plain paragraphs only. Bold, headers, lists, links require richer ProseMirror nodes — not yet implemented.


Common Operations

1. Publish a new post

from publishers.substack import publish_substack

url = publish_substack(
    title="Your Post Title",
    body="First paragraph.\n\nSecond paragraph.",
    publish=True   # False = save as draft only
)

Or via CLI from the pipeline directory:

cd ~/Documents/Codex/Content/ap-content-pipeline
python3 publishers/substack.py "Title Here" "Body paragraph one.\n\nParagraph two."

2. Update / edit an existing post

Need the numeric post ID. Get it by fetching the post:

curl -s -b "substack.sid=$SUBSTACK_SID" \
  "https://alternativepartners.substack.com/api/v1/posts/{slug}" \
  | python3 -c "import json,sys; d=json.load(sys.stdin); print('id:', d.get('id'))"

Then update:

from publishers.substack import update_substack

url = update_substack(
    post_id=191631753,
    title="Updated Title",
    body="New body content.\n\nSecond paragraph."
)

3. Get a post's ID from its slug

The slug is the last segment of the Substack URL:

https://alternativepartners.substack.com/p/the-revops-ai-reality-check-nobodys

→ slug = the-revops-ai-reality-check-nobodys

curl -s -b "substack.sid=$SUBSTACK_SID" \
  "https://alternativepartners.substack.com/api/v1/posts/THE-SLUG-HERE" \
  | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('id'))"

4. Save as draft without publishing

url = publish_substack(title, body, publish=False)
# Returns: https://alternativepartners.substack.com/publish/post/{id}

Email Blast Behavior

publish endpoint is called with {"send_email": False} — posts go live on the web but do not trigger a subscriber email blast. This is intentional for automated/pipeline posts.

To send an email blast, Benjamin needs to manually click "Send" in the Substack editor UI. Do not change send_email to True without explicit confirmation.


Pipeline Integration

The AP Content Pipeline at ~/Documents/Codex/Content/ap-content-pipeline/ handles end-to-end publishing including veto window, soft-veto Slack notification, and scheduling. For single one-off posts, call the publisher directly. For managed pipeline runs, use publish_runner.py.

The pipeline also has a research_gate.py that runs a web search competitive sweep + LLM differentiation analysis before drafting. Posts in idea_inbox.json with research_status: "pending" will be researched before drafting. Requires a search API key configured in your environment.


Troubleshooting

SymptomLikely causeFix
---------------------------
401 UnauthorizedCookie expiredRotate: sign out/in of Substack in Chrome, grab new substack.sid, update your secrets store
PUT /api/v1/posts/... → 404Wrong endpointUse /api/v1/drafts/{id} for updates, not /api/v1/posts/{id}
POST /api/v1/drafts/{id}/publish failsPost already publishedThat's OK — post is already live, return the known URL
Body renders as one giant paragraphMissing double-newlinesInput body must use \n\n between paragraphs
substack.sid not foundCookie env var not setEnsure SUBSTACK_SID is set in your environment before running

版本历史

共 1 个版本

  • v1.0.0 当前
    2026-05-03 09:11 安全 安全

安全检测

腾讯云安全 (Keen)

安全,无风险
查看报告

腾讯云安全 (Sanbu)

安全,无风险
查看报告

🔗 相关推荐

ai-agent

self-improving agent

pskoett
捕获经验教训、错误及修正内容,以实现持续改进。适用于以下场景:(1)命令或操作意外失败;(2)用户纠正Claude(如“不,那不对……”“实际上……”);(3)用户请求的功能不存在;(4)外部API或工具出现故障;(5)Claude发现自身
★ 4,081 📥 809,648
ai-agent

Self-Improving + Proactive Agent

ivangdavila
自我反思+自我批评+自我学习+自组织记忆。智能体评估自身工作、发现错误并持续改进。
★ 1,378 📥 320,362
ai-agent

Skill Vetter

spclaudehome
AI智能体技能安全预审工具。安装ClawdHub、GitHub等来源技能前,检查风险信号、权限范围及可疑模式。
★ 1,226 📥 267,763