Compose and publish a post (text, image, or video) to Twitter/X using camoufox-cli (headless browser automation; built-in browser tool only as fallback). Supports single posts, threads, quote tweets, reply tweets, and long posts (Premium/Blue up to 25,000 chars).
65
80%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./crews/main/skills/twitter-post/SKILL.mdUse this skill when:
Prerequisites: camoufox-cli session 已登录 x.com(登录态持久化在 session profile 里)。冷会话先访问一次首页预热。本 skill 与 login-manager 完全无关——Twitter 发布是纯浏览器操作,走持久化 session twitter(与 twitter-interact 共用同一个 session 名 twitter,靠 session 名字符串约定共享同一 profile 目录与登录态——twitter-interact 登录后 twitter-post 不需重登,反之亦然),登录态在 session profile 里闭环,不导出 cookie/UA 落中央存储。
走持久化 session twitter(与 twitter-interact 共用)。探活方式:开 session open 平台首页 + snapshot 看是否跳登录页。
# 探活(默认无头模式)
camoufox-cli --session twitter --persistent --json open "https://x.com/"
sleep 3
camoufox-cli --session twitter --json snapshot
# snapshot 看页面是否跳到登录页 / 出现登录按钮 / 推文是否正常可见
# → 没跳登录页、内容正常 = 登录态有效,探活完即 close session(登录态在磁盘 profile,后续操作按需重起无头复用)
# → 跳到登录页 / 出现登录按钮 = 登录态失效,走重登重登流程(失效时)——登录流程按 browser-guide skill 走有头手动登录(手机号+验证码 / Twitter APP 扫码),登录导出后close session——登录态落磁盘 profile + 中央存储,不留进程占内存。本 skill 做发布操作 + twitter-interact 做互动操作时用 --session twitter --persistent 重起无头即恢复,用完再 close。只在 session 卡死时由调用方手动 camoufox-cli --session twitter --json close teardown。
# X 登录风控对无头 + QR 识别严格,有头人工登录最稳
camoufox-cli --session twitter --persistent --headed --json open "https://x.com/login"
# 告知用户「**Twitter/X** 浏览器已打开,请在窗口里手动完成登录(账号密码 / 手机 APP 扫码),完成后告诉我」
# 等用户回复后 snapshot 验登录态就位
# 登录就位后 close session——登录态落磁盘 profile,本 skill + twitter-interact 按需重起无头复用不导出 cookie/UA——登录态只在 session profile 里闭环,不落 ~/.openclaw/logins/。本 skill 不调用 cookies export / identity export。
优先 camoufox-cli,且除了登录外,其他都可以默认的无头方式进行
下面 workflow 步骤(Navigate / Click / snapshot eval / upload)默认用 camoufox-cli 执行。若 camoufox-cli 在 X 上持续触发风控,等 60s 后开新 session 重试;仍触发则报告用户该平台当日风控未解,择日再试。
upload 命令(camoufox-cli --session <s> --persistent --json upload <ref> <file>,底层 Playwright setInputFiles,无需 DataTransfer hack)type + slowly: true,不要用 fill()~/.openclaw/agents/main/sessions/twitter-frequency.json(每次 post 后 append)| 场景 | 用哪个 Workflow | 入口 URL |
|---|---|---|
| 新推纯文/图/视频 | Workflow: Post Plain Text / Image / Video | https://x.com/compose/post |
| 推连续串 | Workflow: Thread | https://x.com/compose/post |
| 引用某推+评论 | Workflow: Quote Tweet | https://x.com/compose/post(从其他推页 quote) |
| 回复某推 | Workflow: Reply to Tweet | https://x.com/<user>/status/<id>(回复按钮) |
| 长文(>280 字符) | Workflow: Long Post | https://x.com/compose/post(检测 Premium 蓝标) |
| 标准帖发后取 stats | Workflow: Post Parse Stats | 任意已发推 |
1. Navigate to https://x.com/compose/post
2. Wait for the compose box to load
3. Click into the text area and type the content
- Plain text only (no Markdown)
- Max 280 characters for standard accounts
4. Verify character count — trim if over limit
5. **立即点击 "Post" 按钮——不要等待用户确认!**
6. Wait for success confirmation (URL changes or "Your post was sent" toast)
7. Extract and report the post URL
8. **Parse stats**:
- snapshot eval: `JSON.stringify({
retweet: document.querySelector('[data-testid="retweet"]')?.innerText,
like: document.querySelector('[data-testid="like"]')?.innerText,
reply: document.querySelector('[data-testid="reply"]')?.innerText,
view: document.querySelector('[href*="/analytics"]')?.innerText,
permalink: window.location.href
})`
9. Update frequency tracker1. Navigate to https://x.com/compose/post
2. Wait for the compose box to load
3. Click the media icon (camera/photo button below compose box)
4. Upload the image file using the file picker
5. Wait for image upload to complete (thumbnail appears)
6. Click into the caption area and type the caption
- Plain text only (no Markdown)
- Max 280 characters for standard accounts
7. **立即点击 "Post" 按钮——不要等待用户确认!**
8. Wait for confirmation and report the post URL
9. Parse stats (same as plain text)
10. Update frequency trackerforked cli 的
upload命令底层走 PlaywrightsetInputFiles,穿透 shadow DOM,无需locator.drop()hack。
1. Navigate to https://x.com/compose/post
2. Click the media icon
3. Upload the video file (MP4 recommended, max 512MB, max 2min 20sec)
4. Wait for video processing — this can take 30–120 seconds or more for larger files. Look for the thumbnail preview to confirm completion.
5. Click into the caption area and type the caption
- Plain text only (no Markdown)
- Max 280 characters for standard accounts
6. **立即点击 "Post" 按钮——不要等待用户确认!**
7. Wait for upload confirmation and report the post URL
8. Parse stats (same as plain text)
9. Update frequency tracker1. Navigate to https://x.com/compose/post
2. Click into the compose box and type the first tweet
- Plain text only (no Markdown)
- Max 280 characters for standard accounts
3. Click the "+" icon to add another tweet to the thread
4. Click into the new compose box and type the second tweet
- Plain text only (no Markdown)
- Max 280 characters for standard accounts
5. Repeat for each additional tweet
6. Click "Post all" to publish the full thread
7. Parse stats for the **last** tweet (representative)
8. Update frequency tracker (count = number of tweets in thread)场景:引用别人的推 + 自己的评论(BD / 互动 / 营销场景强)
1. Navigate to source tweet URL(如 https://x.com/username/status/1234567890)
2. Click "Repost" icon → 选择 "Quote"(不是 "Repost")
- ⚠️ 区分 "Repost"(纯转推,无评论)vs "Quote"(引用+评论)
3. Compose box 打开,**已自动填入引用卡片**
4. Click into text area below the quoted card
5. Type your comment (max 280 chars)
6. Verify character count
7. **立即点击 "Post" 按钮**
8. Wait for confirmation, report post URL
9. Parse stats (same as plain text)
10. Update frequency trackerPitfall:
场景:BD 监控 mentions → 智能回复(也可作 twitter-interact skill 的入口)
1. Navigate to source tweet URL(如 https://x.com/username/status/1234567890)
2. Click "Reply" icon(不是 reply 文本框)
3. Compose box 打开,**自动显示 reply context**
4. Type your reply (max 280 chars)
5. Verify character count
6. **立即点击 "Reply" 按钮**(不是 "Post")
7. Wait for confirmation, report reply URL
8. Parse stats (replies can also get view counts)
9. Update frequency trackerPitfall:
前置:用户是 Premium / Blue 订阅(X 蓝标)。普通账号本工作流不适用。
检测 Premium:
snapshot eval: document.querySelector('[data-testid="icon-verified"]') !== null
// 或 UI 中是否有 "Premium" 字样1. Navigate to https://x.com/compose/post
2. Wait for compose box to load
3. Type content up to 25,000 chars
4. **注意**:URL 仍 23 字符,Emoji 仍 2 字符
5. 按钮文字从 "Post" 变成 "**Post all**"(X 长帖是 1 个"post all"动作,但内容被服务端分页)
6. Click "Post all"
7. Wait for confirmation (URL changes)
8. Extract permalink (实际是 thread 形式:tweet + 续贴)
9. Parse stats for **first** tweet
10. Update frequency tracker (count = 1,long post 算 1 次)Pitfall:
post 后立即拿 stats(view / reply / retweet / like),用于复盘。
1. After post success (any workflow ending with "Wait for confirmation")
2. 已在推文页面,URL = https://x.com/<user>/status/<id>
3. Wait 3-5s for X to populate stats
4. snapshot eval:
const stats = JSON.stringify({
retweet: document.querySelector('[data-testid="retweet"]')?.innerText,
like: document.querySelector('[data-testid="like"]')?.innerText,
reply: document.querySelector('[data-testid="reply"]')?.innerText,
view: document.querySelector('a[href*="/analytics"]')?.innerText,
bookmark: document.querySelector('[data-testid="bookmark"]')?.innerText,
permalink: window.location.href
})
5. Output: { ok, permalink, stats: { retweet, like, reply, view, bookmark } }注意:
document.querySelector('selector')?.innerText —— selector 可能因 X UI 改版变,部署后真机验证(见 docs/post-deploy-verification.md)# ~/.openclaw/agents/main/sessions/twitter-frequency.json
{
"last_post_at": "2026-07-05T09:30:00+08:00",
"today_count": 5,
"week_count": 23,
"platform": "twitter"
}每次 post 成功后 append:
| Type | Limit |
|---|---|
| Text (standard) | 280 characters (URL=23, Emoji=2) |
| Text (Premium/Blue) | 25,000 characters (long post) |
| Images | Up to 4 per post |
| Video | Max 512 MB, max 2m 20s |
| GIF | Max 15 MB |
| Reply | 280 characters |
| Quote Tweet | 280 characters (in comment) |
| Thread | Unlimited tweets, each ≤ 280 |
| Situation | Action |
|---|---|
| Login page appears | Session expired — inform user to re-login via browser |
| Character limit exceeded (280) | Trim content or use thread format |
| Character limit exceeded (Premium 25K) | Trim or use thread |
| Media upload fails | Retry once; check file format and size |
| Rate limit error | Wait 30 min minimum (not 15) + check frequency tracker |
| Post button greyed out | Content is empty or over limit — check before clicking |
| Frequency tracker warns high-risk | Ask user: continue or defer to tomorrow? |
| Quote 按钮选成 Repost | Undo(出现"Reposted"提示 → click "Undo" → 重新选 Quote) |
| Reply 按钮消失 | Refresh page(X UI 偶发 bug) |
| Long post 按钮文字不是 "Post all" | 用户不是 Premium → 切换到 standard 280 流程 |
bcef823
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.