publish-x-article
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePublish X Article
发布X文章
Publish Markdown content to X (Twitter) Articles editor, preserving formatting with rich text conversion. Automatically handles X Premium limitations by converting unsupported elements to images.
将Markdown内容发布到X(Twitter)Articles编辑器,通过富文本转换保留格式。自动处理X Premium的限制,将不支持的元素转换为图片。
Credits
致谢
This skill is inspired by and based on wshuyi/x-article-publisher-skill. Thank you to the original author for the foundational work.
本技能受wshuyi/x-article-publisher-skill启发并基于其开发。感谢原作者的奠基性工作。
Interactive Setup: Ask Subscription Type
交互式设置:询问订阅类型
IMPORTANT: Before processing the article, ask the user about their X subscription type if not already known.
重要:在处理文章之前,如果尚未知晓用户的X订阅类型,请先询问用户。
Prompt the User
提示用户
Before publishing, I need to know your X subscription type to handle formatting correctly:
1. **X Premium** - Basic tier ($8/month)
2. **X Premium+** - Plus tier ($16/month)
Which subscription do you have? (Premium / Premium+)For Chinese users:
在发布之前,我需要了解您的 X 订阅类型以正确处理格式:
1. **X Premium** - 基础版 ($8/月)
2. **X Premium+** - 高级版 ($16/月)
您使用的是哪个版本?(Premium / Premium+)Before publishing, I need to know your X subscription type to handle formatting correctly:
1. **X Premium** - Basic tier ($8/month)
2. **X Premium+** - Plus tier ($16/month)
Which subscription do you have? (Premium / Premium+)针对中文用户:
在发布之前,我需要了解您的X订阅类型以正确处理格式:
1. **X Premium** - 基础版 ($8/月)
2. **X Premium+** - 高级版 ($16/月)
您使用的是哪个版本?(Premium / Premium+)Remember the Answer
记住用户的回答
Once the user answers, remember their subscription type for the rest of the session. Don't ask again unless they explicitly want to change it.
一旦用户给出回答,在本次会话的剩余时间内记住其订阅类型。除非用户明确要求更改,否则不要再询问。
X Subscription Feature Comparison
X订阅功能对比
| Feature | X Premium | X Premium+ |
|---|---|---|
H1 headers ( | Title only | Title only |
H2 headers ( | Yes | Yes |
H3+ headers ( | No | Yes |
| Markdown tables | No | Yes |
| Mermaid diagrams | No | No (not supported by X) |
| Code blocks | Blockquotes | Blockquotes |
| Bold, italic, links | Yes | Yes |
| Lists | Yes | Yes |
| Blockquotes | Yes | Yes |
| Images | Yes | Yes |
| 功能 | X Premium | X Premium+ |
|---|---|---|
H1标题 ( | 仅用作标题 | 仅用作标题 |
H2标题 ( | 支持 | 支持 |
H3及以上标题 ( | 不支持 | 支持 |
| Markdown表格 | 不支持 | 支持 |
| Mermaid图表 | 不支持 | 不支持(X本身不支持) |
| 代码块 | 转换为块引用 | 转换为块引用 |
| 粗体、斜体、链接 | 支持 | 支持 |
| 列表 | 支持 | 支持 |
| 块引用 | 支持 | 支持 |
| 图片 | 支持 | 支持 |
Pre-Processing Required by Subscription
按订阅类型进行预处理
X Premium (Basic):
- Convert H3+ headers → H2 or bold
- Convert tables → PNG images
- Convert mermaid → PNG images
X Premium+ (Plus):
- Keep H3+ headers as-is
- Keep tables as-is (rendered natively)
- Convert mermaid → PNG images (still not supported)
X Premium(基础版):
- 将H3及以上标题转换为H2或粗体文本
- 将表格转换为PNG图片
- 将Mermaid图表转换为PNG图片
X Premium+(高级版):
- 保留H3及以上标题原样
- 保留表格原样(原生渲染)
- 将Mermaid图表转换为PNG图片(仍不支持)
Prerequisites
前置条件
- Playwright MCP for browser automation
- User logged into X with Premium subscription
- Python 3.9+ with dependencies:
- macOS:
pip install Pillow pyobjc-framework-Cocoa markdown - Windows:
pip install Pillow pywin32 clip-util markdown
- macOS:
- For Mermaid diagrams:
npm install -g @mermaid-js/mermaid-cli
- 用于浏览器自动化的Playwright MCP
- 用户已登录X且拥有Premium订阅
- Python 3.9及以上版本,并安装以下依赖:
- macOS:
pip install Pillow pyobjc-framework-Cocoa markdown - Windows:
pip install Pillow pywin32 clip-util markdown
- macOS:
- 处理Mermaid图表需安装:
npm install -g @mermaid-js/mermaid-cli
Scripts
脚本位置
Located in :
~/.claude/skills/publish-x-article/scripts/位于 :
~/.claude/skills/publish-x-article/scripts/parse_markdown.py
parse_markdown.py
Parse Markdown and extract structured data:
bash
python parse_markdown.py <markdown_file> [--output json|html] [--html-only]Returns JSON with: title, cover_image, content_images (with block_index for positioning), html, total_blocks
解析Markdown并提取结构化数据:
bash
python parse_markdown.py <markdown_file> [--output json|html] [--html-only]返回包含以下内容的JSON:标题、封面图、内容图片(含用于定位的block_index)、HTML、总块数
copy_to_clipboard.py
copy_to_clipboard.py
Copy image or HTML to system clipboard:
bash
undefined将图片或HTML复制到系统剪贴板:
bash
undefinedCopy image (with optional compression)
复制图片(可选择压缩)
python copy_to_clipboard.py image /path/to/image.jpg [--quality 80]
python copy_to_clipboard.py image /path/to/image.jpg [--quality 80]
Copy HTML for rich text paste
复制HTML用于富文本粘贴
python copy_to_clipboard.py html --file /path/to/content.html
undefinedpython copy_to_clipboard.py html --file /path/to/content.html
undefinedtable_to_image.py
table_to_image.py
Convert Markdown tables to PNG images:
bash
python table_to_image.py /path/to/table.md /path/to/output.png [--style dark|light]将Markdown表格转换为PNG图片:
bash
python table_to_image.py /path/to/table.md /path/to/output.png [--style dark|light]Pre-Processing: Handle Unsupported Elements
预处理:处理不支持的元素
Before publishing, scan the Markdown for unsupported elements and convert them to images.
在发布之前,扫描Markdown中的不支持元素并将其转换为图片。
Step 0: Analyze Content for Limitations
步骤0:分析内容中的限制
bash
undefinedbash
undefinedCheck the markdown file for unsupported elements
检查Markdown文件中的不支持元素
cat /path/to/article.md
Look for:
1. **Deep headers (H3+)**: `###`, `####`, etc.
2. **Markdown tables**: Lines with `|` characters forming table structure
3. **Mermaid code blocks**: ` ```mermaid`cat /path/to/article.md
查找以下元素:
1. **深层标题(H3+)**:`###`、`####`等
2. **Markdown表格**:包含`|`字符形成表格结构的行
3. **Mermaid代码块**:` ```mermaid`Converting Unsupported Elements to Images
将不支持的元素转换为图片
1. Markdown Tables → PNG
1. Markdown表格 → PNG
When a table is detected:
bash
undefined当检测到表格时:
bash
undefined1. Extract table to temp file
1. 将表格提取到临时文件
cat > /tmp/table.md << 'TABLE_EOF'
| Column 1 | Column 2 | Column 3 |
|---|---|---|
| Data 1 | Data 2 | Data 3 |
| TABLE_EOF |
cat > /tmp/table.md << 'TABLE_EOF'
| Column 1 | Column 2 | Column 3 |
|---|---|---|
| Data 1 | Data 2 | Data 3 |
| TABLE_EOF |
2. Convert to image
2. 转换为图片
python ~/.claude/skills/publish-x-article/scripts/table_to_image.py /tmp/table.md /tmp/table-001.png
python ~/.claude/skills/publish-x-article/scripts/table_to_image.py /tmp/table.md /tmp/table-001.png
3. Replace table in markdown with image reference
3. 将Markdown中的表格替换为图片引用
undefinedundefined2. Mermaid Diagrams → PNG
2. Mermaid图表 → PNG
When a mermaid block is detected:
bash
undefined当检测到Mermaid代码块时:
bash
undefined1. Extract mermaid to temp file
1. 将Mermaid代码提取到临时文件
cat > /tmp/diagram.mmd << 'MERMAID_EOF'
flowchart TD
A[Start] --> B[Process]
B --> C[End]
MERMAID_EOF
cat > /tmp/diagram.mmd << 'MERMAID_EOF'
flowchart TD
A[Start] --> B[Process]
B --> C[End]
MERMAID_EOF
2. Convert to image using mermaid-cli
2. 使用mermaid-cli转换为图片
mmdc -i /tmp/diagram.mmd -o /tmp/diagram-001.png -b white -s 2
mmdc -i /tmp/diagram.mmd -o /tmp/diagram-001.png -b white -s 2
3. Replace mermaid block in markdown with image reference
3. 将Markdown中的Mermaid代码块替换为图片引用
undefinedundefined3. Deep Headers (H3+) → Simplified Structure
3. 深层标题(H3+)→ 简化结构
Goal: Preserve the article's logical structure and readability while working within X Premium's H2-only limitation.
Guidelines for the AI:
When you encounter H3, H4, or deeper headers in a Premium user's article, think about what the author intended:
-
If the header introduces a distinct subtopic under a section, convert it to bold text as a paragraph opener. This maintains visual hierarchy without breaking X's formatting.
-
If the header is a major section that happens to be H3, consider promoting it to H2 — but only if this doesn't create a flat, meaningless structure. The article should still flow logically.
-
If there's a deep hierarchy (H2 → H3 → H4), flatten thoughtfully:
- Keep H2 as H2
- Convert H3 to bold paragraph
- Convert H4 to italic or just merge into the paragraph naturally
-
Preserve meaning over structure. A header likemight become a bold lead-in:
### Why This Mattersfollowed by the content. Use your judgment.**Why does this matter?** -
Read the content. If an H3 header is just "Example" or "Note", it might work better as a blockquote or inline emphasis rather than a standalone bold line.
The goal is not mechanical conversion — it's creating an article that reads well on X while honoring the author's intent.
目标:在X的格式限制内,保留文章的逻辑结构和可读性。
AI处理指南:
当在Premium用户的文章中遇到H3、H4或更深层级的标题时,思考作者的意图:
-
如果标题是某个小节下的独立子主题,将其转换为粗体文本作为段落开头。这样既保持了视觉层次,又不会破坏X的格式。
-
如果标题是一个主要小节但被设为H3,可以考虑将其提升为H2——但前提是这不会导致结构扁平化、失去意义。文章仍需保持逻辑流畅。
-
如果存在深层层级结构(H2 → H3 → H4),需谨慎扁平化:
- 保留H2为H2
- 将H3转换为粗体段落开头
- 将H4转换为斜体或自然融入段落
-
优先保留含义而非结构。类似的标题可以转换为粗体引导句:
### Why This Matters,后面跟上内容。请根据实际情况判断。**为什么这很重要?** -
阅读内容。如果H3标题只是“示例”或“注意”,作为块引用或行内强调可能比单独的粗体行效果更好。
我们的目标不是机械转换,而是创建一篇在X上阅读体验良好,同时尊重作者意图的文章。
Pre-Processing Workflow
预处理工作流
Before publishing, read through the article and prepare it for X:
-
Understand the article's structure — Read it first. What are the main sections? How does the author use headers to organize ideas?
-
Handle tables and mermaid diagrams — These need to become images. Extract each one, convert to PNG, and note where they should be inserted.
-
Adapt headers for the subscription tier:
- For Premium+ users: Keep headers as-is (H3+ supported)
- For Premium users: Thoughtfully restructure H3+ headers while preserving the article's flow and intent (see guidelines above)
-
Create the modified markdown — Save your adapted version to a temp file, ready for parsing.
The goal is an article that reads naturally on X, not a mechanically transformed document.
发布前,通读文章并为X做准备:
-
理解文章结构——先阅读全文。主要小节有哪些?作者如何使用标题组织观点?
-
处理表格和Mermaid图表——这些需要转换为图片。提取每个元素,转换为PNG,并记录它们的插入位置。
-
根据订阅类型调整标题:
- 对于Premium+用户:保留标题原样(支持H3+)
- 对于Premium用户:在保留文章流畅性和意图的前提下,合理重构H3+标题(参见上述指南)
-
创建修改后的Markdown——将调整后的版本保存到临时文件,以备解析。
目标是让文章在X上自然阅读,而非机械转换的文档。
Main Workflow
主要工作流
Strategy: "先文后图后分割线" (Text First, Images Second, Dividers Last)
For articles with images and dividers, paste ALL text content first, then insert images and dividers at correct positions using block index.
- Pre-process: Convert tables/mermaid to images, flatten deep headers
- Parse modified Markdown with Python script → get title, images, dividers (all with block_index), HTML
- Navigate to X Articles editor
- Upload cover image (first image)
- Fill title
- Copy HTML to clipboard (Python) → Paste with Cmd+V
- Insert content images at positions specified by block_index
- Insert dividers at positions specified by block_index (via Insert > Divider menu)
- Save as draft (NEVER auto-publish)
策略:"先文后图后分割线"(Text First, Images Second, Dividers Last)
对于包含图片和分割线的文章,先粘贴所有文本内容,然后根据块索引在正确位置插入图片和分割线。
- 预处理:将表格/Mermaid图表转换为图片,扁平化深层标题
- 使用Python脚本解析修改后的Markdown → 获取标题、图片、分割线(均含块索引)、HTML
- 导航到X Articles编辑器
- 上传封面图(第一张图片)
- 填写标题
- 使用Python将HTML复制到剪贴板 → 按Cmd+V粘贴
- 根据块索引在正确位置插入内容图片和分割线
- 通过菜单插入分割线(使用块索引定位)
- 保存为草稿(切勿自动发布)
高效执行原则 (Efficiency Guidelines)
高效执行原则 (Efficiency Guidelines)
目标: 最小化操作之间的等待时间,实现流畅的自动化体验。
目标: 最小化操作之间的等待时间,实现流畅的自动化体验。
1. 避免不必要的 browser_snapshot
1. 避免不必要的browser_snapshot
大多数浏览器操作(click, type, press_key 等)都会在返回结果中包含页面状态。不要在每次操作后单独调用 ,直接使用操作返回的页面状态即可。
browser_snapshot❌ 错误做法:
browser_click → browser_snapshot → 分析 → browser_click → browser_snapshot → ...
✅ 正确做法:
browser_click → 从返回结果中获取页面状态 → browser_click → ...大多数浏览器操作(click、type、press_key等)都会在返回结果中包含页面状态。不要在每次操作后单独调用,直接使用操作返回的页面状态即可。
browser_snapshot❌ 错误做法:
browser_click → browser_snapshot → 分析 → browser_click → browser_snapshot → ...
✅ 正确做法:
browser_click → 从返回结果中获取页面状态 → browser_click → ...2. 避免不必要的 browser_wait_for
2. 避免不必要的browser_wait_for
只在以下情况使用 :
browser_wait_for- 等待图片上传完成()
textGone="正在上传媒体" - 等待页面初始加载(极少数情况)
不要使用 来等待按钮或输入框出现 - 它们在页面加载完成后立即可用。
browser_wait_for仅在以下情况使用:
browser_wait_for- 等待图片上传完成()
textGone="正在上传媒体" - 等待页面初始加载(极少数情况)
不要使用等待按钮或输入框出现——页面加载完成后它们立即可用。
browser_wait_for3. 并行执行独立操作
3. 并行执行独立操作
当两个操作没有依赖关系时,可以在同一个消息中并行调用多个工具:
✅ 可以并行:
- 填写标题 (browser_type) + 复制HTML到剪贴板 (Bash)
- 解析Markdown生成JSON + 生成HTML文件
❌ 不能并行(有依赖):
- 必须先点击create才能上传封面图
- 必须先粘贴内容才能插入图片当两个操作没有依赖关系时,可以在同一个消息中并行调用多个工具:
✅ 可以并行:
- 填写标题 (browser_type) + 复制HTML到剪贴板 (Bash)
- 解析Markdown生成JSON + 生成HTML文件
❌ 不能并行(有依赖):
- 必须先点击create才能上传封面图
- 必须先粘贴内容才能插入图片4. 连续执行浏览器操作
4. 连续执行浏览器操作
每个浏览器操作返回的页面状态包含所有需要的元素引用。直接使用这些引用进行下一步操作:
undefined每个浏览器操作返回的页面状态包含所有需要的元素引用。直接使用这些引用进行下一步操作:
undefined理想流程(每步直接执行,不额外等待):
理想流程(每步直接执行,不额外等待):
browser_navigate → 从返回状态找create按钮 → browser_click(create)
→ 从返回状态找上传按钮 → browser_click(上传) → browser_file_upload
→ 从返回状态找应用按钮 → browser_click(应用)
→ 从返回状态找标题框 → browser_type(标题)
→ 点击编辑器 → browser_press_key(Meta+v)
→ ...
undefinedbrowser_navigate → 从返回状态找create按钮 → browser_click(create)
→ 从返回状态找上传按钮 → browser_click(上传) → browser_file_upload
→ 从返回状态找应用按钮 → browser_click(应用)
→ 从返回状态找标题框 → browser_type(标题)
→ 点击编辑器 → browser_press_key(Meta+v)
→ ...
undefined5. 准备工作前置
5. 准备工作前置
在开始浏览器操作之前,先完成所有准备工作:
- 扫描不支持的元素(表格、Mermaid、深层标题)
- 转换表格/Mermaid 为图片
- 解析 Markdown 获取 JSON 数据
- 生成 HTML 文件到 /tmp/
- 记录 title、cover_image、content_images 等信息
这样浏览器操作阶段可以连续执行,不需要中途停下来处理数据。
在开始浏览器操作之前,先完成所有准备工作:
- 扫描不支持的元素(表格、Mermaid、深层标题)
- 转换表格/Mermaid 为图片
- 解析Markdown获取JSON数据
- 生成HTML文件到/tmp/
- 记录title、cover_image、content_images等信息
这样浏览器操作阶段可以连续执行,不需要中途停下来处理数据。
Step 0: Read and Adapt the Article
步骤0:阅读并调整文章
First, read the article. Understand what it's about, how it's structured, and what the author is trying to communicate.
首先,阅读文章。 理解文章主题、结构以及作者想要传达的内容。
Preserve the Original
保留原文
IMPORTANT: Never modify the user's original file. If adaptations are needed:
- Save the adapted version as a copy (e.g., or alongside the original as
/tmp/article_adapted.md)article_for_x.md - Tell the user what was changed and where both files are:
I've adapted your article for X Premium. Here's what changed: - Converted 2 tables to images - Restructured 3 H3 headers to bold text for better flow Original preserved: /path/to/article.md Adapted version: /path/to/article_for_x.md - Proceed with the adapted copy for publishing
This ensures the user can review the changes and keeps their original work intact.
重要:切勿修改用户的原始文件。如果需要调整:
- 将调整后的版本保存为副本(例如或在原文件旁保存为
/tmp/article_adapted.md)article_for_x.md - 告知用户修改内容以及两个文件的位置:
我已为X Premium调整了您的文章。修改内容如下: - 将2个表格转换为图片 - 将3个H3标题重构为粗体文本以提升流畅性 原文位置:/path/to/article.md 调整后版本:/path/to/article_for_x.md - 使用调整后的副本进行发布
这样用户可以查看修改内容,同时保留原始文件不受影响。
Adaptation Based on Subscription
根据订阅类型调整
For Premium Users (Basic Tier)
针对Premium用户(基础版)
Ask yourself:
- Are there tables? → Convert each to a PNG image
- Are there mermaid diagrams? → Convert each to a PNG image
- Are there H3+ headers? → Restructure them thoughtfully (see header guidelines above)
Create a modified version of the markdown that will work within Premium's limitations while preserving readability.
自问:
- 文章中有表格吗?→ 将每个表格转换为PNG图片
- 文章中有Mermaid图表吗?→ 将每个图表转换为PNG图片
- 文章中有H3及以上标题吗?→ 合理重构这些标题(参见上述标题指南)
创建一个符合Premium版限制,同时保持可读性的修改版Markdown。
For Premium+ Users
针对Premium+用户
Ask yourself:
- Are there mermaid diagrams? → Convert to PNG (still not supported on any tier)
- Tables and H3+ headers can stay as-is
自问:
- 文章中有Mermaid图表吗?→ 转换为PNG图片(所有版本均不支持)
- 表格和H3及以上标题可以保留原样
Converting Elements to Images
将元素转换为图片
bash
undefinedbash
undefinedTables → PNG
表格 → PNG
python ~/.claude/skills/publish-x-article/scripts/table_to_image.py /tmp/table-1.md /tmp/table-1.png
python ~/.claude/skills/publish-x-article/scripts/table_to_image.py /tmp/table-1.md /tmp/table-1.png
Mermaid → PNG
Mermaid → PNG
mmdc -i /tmp/diagram-1.mmd -o /tmp/diagram-1.png -b white -s 2
Replace these elements in the markdown with image references, positioning them where the original element was.mmdc -i /tmp/diagram-1.mmd -o /tmp/diagram-1.png -b white -s 2
在Markdown中用图片引用替换这些元素,并保持它们在原文中的位置。Step 1: Parse Markdown (Python)
步骤1:解析Markdown(Python)
Use to extract all structured data:
parse_markdown.pybash
python ~/.claude/skills/publish-x-article/scripts/parse_markdown.py /path/to/modified_article.mdOutput JSON:
json
{
"title": "Article Title",
"cover_image": "/path/to/first-image.jpg",
"content_images": [
{"path": "/tmp/table-1.png", "block_index": 5, "after_text": "context..."},
{"path": "/tmp/mermaid-1.png", "block_index": 12, "after_text": "another context..."}
],
"dividers": [
{"block_index": 7, "after_text": "context before divider..."},
{"block_index": 15, "after_text": "another context..."}
],
"html": "<p>Content...</p><h2>Section</h2>...",
"total_blocks": 45
}Key fields:
- : The image/divider should be inserted AFTER block element at this index (0-indexed)
block_index - : Total number of block elements in the HTML
total_blocks - : Kept for reference/debugging only, NOT for positioning
after_text - : Array of divider positions (markdown
dividersmust be inserted via X's menu, not HTML---)<hr>
Save HTML to temp file for clipboard:
bash
python parse_markdown.py modified_article.md --html-only > /tmp/article_html.html使用提取所有结构化数据:
parse_markdown.pybash
python ~/.claude/skills/publish-x-article/scripts/parse_markdown.py /path/to/modified_article.md输出JSON:
json
{
"title": "Article Title",
"cover_image": "/path/to/first-image.jpg",
"content_images": [
{"path": "/tmp/table-1.png", "block_index": 5, "after_text": "context..."},
{"path": "/tmp/mermaid-1.png", "block_index": 12, "after_text": "another context..."}
],
"dividers": [
{"block_index": 7, "after_text": "context before divider..."},
{"block_index": 15, "after_text": "another context..."}
],
"html": "<p>Content...</p><h2>Section</h2>...",
"total_blocks": 45
}关键字段:
- : 图片/分割线应插入在第N个块元素之后(从0开始计数)
block_index - : HTML中的块元素总数
total_blocks - : 仅用于参考/调试,不用于定位
after_text - : 分割线位置数组(Markdown中的
dividers必须通过X的菜单插入,而非HTML---标签)<hr>
将HTML保存到临时文件以备剪贴板使用:
bash
python parse_markdown.py modified_article.md --html-only > /tmp/article_html.htmlStep 2: Open X Articles Editor
步骤2:打开X Articles编辑器
browser_navigate: https://x.com/compose/articles重要: 页面加载后会显示草稿列表,不是编辑器。需要:
- 等待页面加载完成: 使用 检查页面状态
browser_snapshot - 立即点击 "create" 按钮: 不要等待 "添加标题" 等编辑器元素,它们只有点击 create 后才出现
- 等待编辑器加载: 点击 create 后,等待编辑器元素出现
undefinedbrowser_navigate: https://x.com/compose/articles重要: 页面加载后会显示草稿列表,而非编辑器。需要:
- 等待页面加载完成: 使用检查页面状态
browser_snapshot - 立即点击"create"按钮: 不要等待“添加标题”等编辑器元素,这些元素只有点击create后才会出现
- 等待编辑器加载: 点击create后,等待编辑器元素出现
undefined1. 导航到页面
1. 导航到页面
browser_navigate: https://x.com/compose/articles
browser_navigate: https://x.com/compose/articles
2. 获取页面快照,找到 create 按钮
2. 获取页面快照,找到create按钮
browser_snapshot
browser_snapshot
3. 点击 create 按钮(通常 ref 类似 "create" 或带有 create 标签)
3. 点击create按钮(通常ref类似"create"或带有create标签)
browser_click: element="create button", ref=<create_button_ref>
browser_click: element="create button", ref=<create_button_ref>
4. 现在编辑器应该打开了,可以继续上传封面图等操作
4. 现在编辑器应该已打开,可以继续上传封面图等操作
**注意**: 不要使用 `browser_wait_for text="添加标题"` 来等待页面加载,因为这个文本只有在点击 create 后才出现,会导致超时。
If login needed, prompt user to log in manually.
**注意**: 不要使用`browser_wait_for text="添加标题"`等待页面加载,因为该文本只有点击create后才会出现,会导致超时。
如果需要登录,请提示用户手动登录。Step 3: Upload Cover Image
步骤3:上传封面图
- Click "添加照片或视频" button
- Use browser_file_upload with the cover image path (from JSON output)
- Verify image uploaded
- 点击“添加照片或视频”按钮
- 使用browser_file_upload上传封面图(来自JSON输出的路径)
- 验证图片上传完成
Step 4: Fill Title
步骤4:填写标题
- Find textbox with "添加标题" placeholder
- Use browser_type to input title (from JSON output)
- 找到带有“添加标题”占位符的文本框
- 使用browser_type输入标题(来自JSON输出)
Step 5: Paste Text Content (Python Clipboard)
步骤5:粘贴文本内容(Python剪贴板)
Copy HTML to system clipboard using Python, then paste:
bash
undefined使用Python将HTML复制到系统剪贴板,然后粘贴:
bash
undefinedCopy HTML to clipboard
将HTML复制到剪贴板
python ~/.claude/skills/publish-x-article/scripts/copy_to_clipboard.py html --file /tmp/article_html.html
Then in browser:browser_click on editor textbox
browser_press_key: Meta+v
This preserves all rich text formatting (H2, bold, links, lists).python ~/.claude/skills/publish-x-article/scripts/copy_to_clipboard.py html --file /tmp/article_html.html
然后在浏览器中执行:browser_click on editor textbox
browser_press_key: Meta+v
这样可以保留所有富文本格式(H2、粗体、链接、列表)。Step 6: Insert Content Images (Block Index Positioning)
步骤6:插入内容图片(按块索引定位)
关键改进: 使用 精确定位,而非依赖文字匹配。
block_index关键改进: 使用精确定位,而非依赖文字匹配。
block_index定位原理
定位原理
粘贴 HTML 后,编辑器中的内容结构为一系列块元素(段落、标题、引用等)。每张图片的 表示它应该插入在第 N 个块元素之后。
block_index粘贴HTML后,编辑器中的内容由一系列块元素(段落、标题、引用等)组成。每张图片的表示它应该插入在第N个块元素之后。
block_index操作步骤
操作步骤
- 获取所有块元素: 使用 browser_snapshot 获取编辑器内容,找到 textbox 下的所有子元素
- 按索引定位: 根据 点击对应的块元素
block_index - 粘贴图片: 复制图片到剪贴板后粘贴
For each content image (from array):
content_imagesbash
undefined- 获取所有块元素: 使用browser_snapshot获取编辑器内容,找到textbox下的所有子元素
- 按索引定位: 根据点击对应的块元素
block_index - 粘贴图片: 将图片复制到剪贴板后粘贴
对于每个内容图片(来自数组):
content_imagesbash
undefined1. Copy image to clipboard (with compression)
1. 将图片复制到剪贴板(带压缩)
python ~/.claude/skills/publish-x-article/scripts/copy_to_clipboard.py image /path/to/img.jpg --quality 85
undefinedpython ~/.claude/skills/publish-x-article/scripts/copy_to_clipboard.py image /path/to/img.jpg --quality 85
undefined2. Click the block element at block_index
2. 点击block_index对应的块元素
Example: if block_index=5, click the 6th block element (0-indexed)
示例:如果block_index=5,点击第6个块元素(从0开始计数)
browser_click on the element at position block_index in the editor
browser_click on the element at position block_index in the editor
3. Paste image
3. 粘贴图片
browser_press_key: Meta+v
browser_press_key: Meta+v
4. Wait for upload (use short time, returns immediately when done)
4. 等待上传完成(短时间等待,完成后立即返回)
browser_wait_for textGone="正在上传媒体" time=2
undefinedbrowser_wait_for textGone="正在上传媒体" time=2
undefined反向插入
反向插入
注意: 每插入一张图片后,后续图片的实际位置会偏移。建议按 从大到小的顺序插入图片。
block_index如果有3张图片,block_index 分别为 5, 12, 27:
- 先插入 block_index=27 的图片
- 再插入 block_index=12 的图片
- 最后插入 block_index=5 的图片
注意: 每插入一张图片后,后续图片的实际位置会偏移。建议按从大到小的顺序插入图片。
block_index如果有3张图片,block_index分别为5、12、27:
- 先插入block_index=27的图片
- 再插入block_index=12的图片
- 最后插入block_index=5的图片
Step 6.5: Insert Dividers (Via Menu)
步骤6.5:插入分割线(通过菜单)
重要: Markdown 中的 分割线不能通过 HTML 标签粘贴(X Articles 会忽略它)。必须通过 X Articles 的 Insert 菜单插入。
---<hr>重要: Markdown中的分割线不能通过HTML 标签粘贴(X Articles会忽略它)。必须通过X Articles的Insert菜单插入。
---<hr>为什么需要特殊处理
为什么需要特殊处理
X Articles 有自己的原生分割线元素,只能通过 Insert > Divider 菜单插入。HTML 标签会被完全忽略。
<hr>X Articles有自己的原生分割线元素,只能通过Insert > Divider菜单插入。HTML 标签会被完全忽略。
<hr>操作步骤
操作步骤
For each divider (from array), in reverse order of block_index:
dividersundefined对于每个分割线(来自数组),按从大到小的顺序插入:
dividersblock_indexundefined1. Click the block element at block_index position
1. 点击block_index位置的块元素
browser_click on the element at position block_index in the editor
browser_click on the element at position block_index in the editor
2. Open Insert menu
2. 打开Insert菜单
browser_click on "Insert" button (Add Media button)
browser_click on "Insert" button(添加媒体按钮)
3. Click Divider menu item
3. 点击Divider菜单项
browser_click on "Divider" menuitem
browser_click on "Divider" menuitem
Divider is inserted at cursor position
分割线会插入到光标位置
undefinedundefined反向插入
反向插入
和图片一样,按 从大到小的顺序插入分割线,避免位置偏移问题。
block_index和图片一样,按从大到小的顺序插入分割线,避免位置偏移问题。
block_index与图片的插入顺序
与图片的插入顺序
建议先插入所有图片,再插入所有分割线。两者都按 block_index 从大到小的顺序:
- 插入所有图片(从最大 block_index 开始)
- 插入所有分割线(从最大 block_index 开始)
建议先插入所有图片,再插入所有分割线。两者都按block_index从大到小的顺序:
- 插入所有图片(从最大的block_index开始)
- 插入所有分割线(从最大的block_index开始)
Step 7: Save Draft
步骤7:保存草稿
- Verify content pasted (check word count indicator)
- Draft auto-saves, or click Save button if needed
- Click "预览" to verify formatting
- Report: "Draft saved. Review and publish manually."
- 验证内容已粘贴(检查字数统计指示器)
- 草稿会自动保存,如有需要可点击Save按钮
- 点击“预览”验证格式
- 告知用户:“草稿已保存。请查看并手动发布。”
Critical Rules
关键规则
- NEVER publish - Only save draft
- Pre-process first - Convert tables/mermaid/deep headers before parsing
- First image = cover - Upload first image as cover image
- Rich text conversion - Always convert Markdown to HTML before pasting
- Use clipboard API - Paste via clipboard for proper formatting
- Block index positioning - Use block_index for precise image/divider placement
- Reverse order insertion - Insert images and dividers from highest to lowest block_index
- H1 title handling - H1 is used as title only, not included in body
- Dividers via menu - Markdown must be inserted via Insert > Divider menu (HTML
---is ignored)<hr>
- 切勿自动发布 - 仅保存为草稿
- 先预处理 - 解析前先转换表格/Mermaid图表/深层标题
- 第一张图片作为封面 - 上传第一张图片作为封面
- 富文本转换 - 发布前始终将Markdown转换为HTML
- 使用剪贴板API - 通过剪贴板粘贴以保证格式正确
- 按块索引定位 - 使用block_index精确定位图片/分割线
- 反向插入 - 按block_index从大到小的顺序插入图片和分割线
- H1标题处理 - H1仅用作标题,不包含在正文中
- 通过菜单插入分割线 - Markdown中的必须通过Insert > Divider菜单插入(HTML
---会被忽略)<hr>
Supported Formatting (After Pre-Processing)
支持的格式(预处理后)
| Element | Support | Notes |
|---|---|---|
H2 ( | Native | Section headers |
Bold ( | Native | Strong emphasis |
Italic ( | Native | Emphasis |
Links ( | Native | Hyperlinks |
| Ordered lists | Native | 1. 2. 3. |
| Unordered lists | Native | - bullets |
Blockquotes ( | Native | Quoted text |
| Code blocks | Converted | → Blockquotes |
| Tables | Converted | → PNG images |
| Mermaid | Converted | → PNG images |
| H3+ headers | Converted | → H2 or bold |
Dividers ( | Menu insert | → Insert > Divider |
| 元素 | 支持情况 | 说明 |
|---|---|---|
H2 ( | 原生支持 | 小节标题 |
粗体 ( | 原生支持 | 强强调 |
斜体 ( | 原生支持 | 强调 |
链接 ( | 原生支持 | 超链接 |
| 有序列表 | 原生支持 | 1. 2. 3. |
| 无序列表 | 原生支持 | - 项目符号 |
块引用 ( | 原生支持 | 引用文本 |
| 代码块 | 转换后支持 | → 块引用 |
| 表格 | 转换后支持 | → PNG图片 |
| Mermaid图表 | 转换后支持 | → PNG图片 |
| H3及以上标题 | 转换后支持 | → H2或粗体文本 |
分割线 ( | 通过菜单插入 | → Insert > Divider |
Example Flow
示例流程
User: "Publish /path/to/article.md to X"
bash
undefined用户:“将/path/to/article.md发布到X”
bash
undefinedStep 0: Analyze content
步骤0:分析内容
Found: 1 table, 1 mermaid diagram, 2 H3 headers
发现:1个表格、1个Mermaid图表、2个H3标题
Step 0.1: Convert table to image
步骤0.1:将表格转换为图片
python ~/.claude/skills/publish-x-article/scripts/table_to_image.py /tmp/table-1.md /tmp/table-1.png
python ~/.claude/skills/publish-x-article/scripts/table_to_image.py /tmp/table-1.md /tmp/table-1.png
Step 0.2: Convert mermaid to image
步骤0.2:将Mermaid图表转换为图片
mmdc -i /tmp/mermaid-1.mmd -o /tmp/mermaid-1.png -b white -s 2
mmdc -i /tmp/mermaid-1.mmd -o /tmp/mermaid-1.png -b white -s 2
Step 0.3: Create modified markdown with image refs and flattened headers
步骤0.3:创建包含图片引用和扁平化标题的修改版Markdown
Save to /tmp/article_modified.md
保存到/tmp/article_modified.md
Step 1: Parse modified markdown
步骤1:解析修改后的Markdown
python ~/.claude/skills/publish-x-article/scripts/parse_markdown.py /tmp/article_modified.md > /tmp/article.json
python ~/.claude/skills/publish-x-article/scripts/parse_markdown.py /tmp/article_modified.md --html-only > /tmp/article_html.html
2. Navigate to https://x.com/compose/articles
3. Click create, upload cover image (browser_file_upload for cover only)
4. Fill title (from JSON: `title`)
5. Copy & paste HTML:
```bash
python ~/.claude/skills/publish-x-article/scripts/copy_to_clipboard.py html --file /tmp/article_html.htmlThen: browser_press_key Meta+v
6. For each content image (including converted table/mermaid PNGs), in reverse order of block_index:
bash
python copy_to_clipboard.py image /path/to/img.jpg --quality 85- Click block element at position
block_index - browser_press_key Meta+v
- Wait until upload complete
- Verify in preview
- "Draft saved. Please review and publish manually."
python ~/.claude/skills/publish-x-article/scripts/parse_markdown.py /tmp/article_modified.md > /tmp/article.json
python ~/.claude/skills/publish-x-article/scripts/parse_markdown.py /tmp/article_modified.md --html-only > /tmp/article_html.html
2. 导航到https://x.com/compose/articles
3. 点击create,上传封面图(仅封面图使用browser_file_upload)
4. 填写标题(来自JSON中的`title`)
5. 复制并粘贴HTML:
```bash
python ~/.claude/skills/publish-x-article/scripts/copy_to_clipboard.py html --file /tmp/article_html.html然后执行:browser_press_key Meta+v
6. 对于每个内容图片(包括转换后的表格/Mermaid PNG),按block_index从大到小的顺序:
bash
python copy_to_clipboard.py image /path/to/img.jpg --quality 85- 点击block_index位置的块元素
- browser_press_key Meta+v
- 等待上传完成
- 在预览中验证
- 告知用户:“草稿已保存。请查看并手动发布。”
Best Practices
最佳实践
为什么用 block_index 而非文字匹配?
为什么使用block_index而非文字匹配?
- 精确定位: 不依赖文字内容,即使多处文字相似也能正确定位
- 可靠性: 索引是确定性的,不会因为文字相似而混淆
- 调试方便: 仍保留用于人工核验
after_text
- 精确定位: 不依赖文字内容,即使多处文字相似也能正确定位
- 可靠性: 索引是确定性的,不会因文字相似而混淆
- 调试方便: 仍保留用于人工核验
after_text
为什么用 Python 而非浏览器内 JavaScript?
为什么使用Python而非浏览器内JavaScript?
- 本地处理更可靠: Python 直接操作系统剪贴板,不受浏览器沙盒限制
- 图片压缩: 上传前压缩图片 (--quality 85),减少上传时间
- 代码复用: 脚本固定不变,无需每次重新编写转换逻辑
- 调试方便: 脚本可单独测试,问题易定位
- 本地处理更可靠: Python直接操作系统剪贴板,不受浏览器沙箱限制
- 图片压缩: 上传前压缩图片(--quality 85),减少上传时间
- 代码复用: 脚本固定不变,无需每次重新编写转换逻辑
- 调试方便: 脚本可单独测试,问题易定位
等待策略
等待策略
关键理解: 的 参数会在文字消失时立即返回, 只是最大等待时间,不是固定等待时间。
browser_wait_fortextGonetimeundefined关键理解: 的参数会在文字消失时立即返回,只是最大等待时间,而非固定等待时间。
browser_wait_fortextGonetimeundefined正确用法:短 time 值,条件满足立即返回
正确用法:短time值,条件满足立即返回
browser_wait_for textGone="正在上传媒体" time=2
browser_wait_for textGone="正在上传媒体" time=2
错误用法:固定长时间等待
错误用法:固定长时间等待
browser_wait_for time=5 # 无条件等待5秒,浪费时间
undefinedbrowser_wait_for time=5 # 无条件等待5秒,浪费时间
undefined封面图 vs 内容图
封面图 vs 内容图
- 封面图: 使用 browser_file_upload(因为有专门的上传按钮)
- 内容图: 使用 Python 剪贴板 + 粘贴(更高效)
- 封面图: 使用browser_file_upload(因为有专门的上传按钮)
- 内容图: 使用Python剪贴板+粘贴(更高效)
Troubleshooting
故障排除
Table not rendering correctly
表格渲染不正确
- Ensure Pillow is installed:
pip install pillow - Check table markdown syntax is valid
- 确保已安装Pillow:
pip install pillow - 检查Markdown表格语法是否有效
Mermaid conversion fails
Mermaid转换失败
- Install mermaid-cli:
npm install -g @mermaid-js/mermaid-cli - Check mermaid syntax is valid
- 安装mermaid-cli:
npm install -g @mermaid-js/mermaid-cli - 检查Mermaid语法是否有效
Deep headers still showing
深层标题仍显示
- Manually flatten →
###or##**bold** - Re-run pre-processing
- 手动将转换为
###或##**粗体** - 重新执行预处理
Image upload timeout
图片上传超时
- Compress images with
--quality 70 - Use shorter
browser_wait_for time=2
- 使用压缩图片
--quality 70 - 使用更短的
browser_wait_for time=2

