Initial commit: Hermes Agent skills collection

- Trading skills (OKX, dividend, lottery, quantitative)
- Creative skills (ASCII art, diagrams, video)
- Development skills (GitHub, debugging, TDD)
- Research skills (arXiv, blog monitoring)
- Productivity skills (email, documents, notes)
- MCP integration skills
- Custom user skills
This commit is contained in:
Hermes Skills Manager
2026-07-05 02:31:15 -04:00
commit 6770bc9b9d
908 changed files with 239614 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
---
description: Skills for interacting with social platforms and social-media workflows — posting, reading, monitoring, and account operations.
---
+115
View File
@@ -0,0 +1,115 @@
---
name: xiaohongshu-style
description: 小红书发文风格指南。生成符合平台调性、规避风控的投资/理财/生活类内容。当用户说"发小红书"、"小红书风格"、"做成小红书内容"时使用。
version: 1.1.0
tags: [xiaohongshu, social-media, content, finance]
---
# 小红书发文风格指南
## 核心调性
- **人设**:真实分享者,不是专家/老师。用"我自己在用"、"分享一下"口吻
- **语气**:轻松活泼,像跟朋友聊天。可用感叹号但不过度
- **结构**:短段落 + 分隔线 + emoji标记,每段2-3行
- **长度**:正文控制在 **500-650字**,用户明确要求"简洁"。1000字太长没人看。
- **标题**:最多 **20字**(小红书限制),含emoji。例:"💰月投7500|高息股阶梯买入法"
## 排版规范
- 用 ━━━ 分隔大段落
- 用 emoji 数字 1️⃣2️⃣3️⃣ 做列表
- 每段开头用 emoji 点缀(💡📊🔖🎯💰📈)
- 关键数据用 | 或 分隔
- 结尾必有互动引导 + 免责声明 + 标签
## 风控红线(必须遵守)
1. **不提具体股票代码/名称** → 用"某XX龙头"、"某银行股"代替
2. **不说"推荐/建议买入"** → 用"分享思路/我的做法"
3. **不承诺收益** → 用"按X%算≈"、"预估",必须加免责
4. **不写具体金额** → 不写"月投7500"、"年息6300"等数字,用"每月闲钱"、"年息还不错"代替。只写百分比(股息率、PE、PB),不写绝对金额
5. **不用"稳赚/保本/无风险"** → 违反广告法+平台规则
6. **不引导加群/私聊/外链** → 纯内容分享,评论区自然互动
7. **免责声明必放** → "以上纯属个人记录,不构成投资建议"
## 互动设计
- 结尾问句引导评论:"你们有在做XX的吗?评论区聊聊"
- "懂的评论区聊~" 制造信息差吸引互动
- 适当留悬念引发好奇
## 发布流程 (opencli)
```bash
# 发布笔记(需要 Chrome + opencli 浏览器扩展已连接)
opencli xiaohongshu publish "<正文>" --title "<标题>" --images "img1.png,img2.png" --topics "高息股,港股,美股"
# 保存为草稿(不直接发布)
opencli xiaohongshu publish "<正文>" --title "<标题>" --images "img1.png" --draft
# 检查连接状态
opencli doctor
```
**⚠️ PITFALL: Browser Bridge 未连接**
如果 `opencli doctor` 显示 `[MISSING] Extension: not connected`,自动发布不可用。
需要:Chrome 安装 opencli 扩展 → 开启开发者模式 → 连接。
**Fallback**: 准备好内容+图片,让用户手动发布。
## 配图生成流程
1. 写 HTML 卡片(单卡单文件,宽 420px)
2. 用 browser 工具截图(`browser_navigate``browser_vision`,截图自动保存)
3. 复制到 `~/.hermes/output/xhs_images/`
4. ⚠️ **chromium snap 有 AppArmor 限制**`--screenshot` 写文件会 permission denied。用 browser 工具代替。
5. 每张卡片单独一个 HTML 文件,避免截到多余空白。
## 配图风格(小红书卡片)
- **工具**:生成 HTML 卡片截图,深色背景 + 亮色点缀
- **色调**:深蓝/深灰底 + 金色/绿色/橙色数据
- **字体**:大标题醒目,数据突出,正文简洁
- **布局**:单图信息量要大,像"一张图讲清楚"
- **必备元素**:标题、核心数据、emoji、免责声明小字
### 卡片模板类型
1. **数据卡**:核心数字大字体 + 对比数据
2. **流程卡**:步骤1→2→3,箭头连接
3. **对比卡**:左右/上下对比两种方案
4. **清单卡**:勾选列表,每项一行
### HTML卡片代码模式
```html
<!-- 深色背景 + 金色数据 -->
<div style="background:#1a1a2e;color:#fff;padding:40px;font-family:sans-serif;border-radius:20px">
<h2 style="color:#f0c040">📊 标题</h2>
<div style="font-size:48px;color:#00d4aa">7.5%</div>
<p style="color:#aaa;font-size:12px">免责声明...</p>
</div>
```
## 标签策略
- 8-15个标签
- 前3个放核心关键词(#高息股 #港股 #美股
- 中间放场景词(#月薪理财 #被动收入
- 最后放泛标签(#理财 #投资
- 标签之间空格分隔,不用逗号
## 支持文件
- `templates/xhs_card_template.html` — 深色卡片模板(数据卡+持仓卡),可直接复用修改
- `references/publishing-workflow.md` — opencli 发布命令详解 + 故障排查
## 典型结构模板
```
[吸睛开头 - 1-2句痛点/亮点]
━━━━━━━━━━━━━━
[核心内容1 - 简洁]
[核心数据]
━━━━━━━━━━━━━━
[核心内容2 - 方法/步骤]
━━━━━━━━━━━━━━
[个人经验/纪律]
━━━━━━━━━━━━━━
⚠️ 免责声明
💬 互动引导
🏷️ #标签
```
@@ -0,0 +1,53 @@
# 小红书发布工作流
## opencli 发布命令
```bash
opencli xiaohongshu publish "<content>" \
--title "<标题>" \
--images "path1.png,path2.png" \
--topics "标签1,标签2,标签3" \
--draft # 可选:先存草稿
```
### 参数约束
- `title`: 最多 20 字(含 emoji
- `content`: 笔记正文,支持换行
- `images`: 逗号分隔,最多 9 张,支持 jpg/png/gif/webp
- `topics`: 逗号分隔,不含 # 号
- `--draft`: true/false,存草稿不直接发布
### 前置条件
1. Chrome 已安装 opencli 浏览器扩展
2. 已登录小红书创作者中心
3. `opencli doctor` 显示 Extension: connected
### 故障排查
```
opencli doctor
```
- `[MISSING] Extension: not connected` → Chrome 扩展未安装/未启用
- `BROWSER_CONNECT` 错码 → 需要重启 daemon: `opencli daemon restart`
- 如果扩展已装但连不上 → Chrome 需要保持打开状态
## 配图生成
### 流程
1. 写 HTML 卡片(单卡单文件,width: 420px
2. 用 Hermes browser 工具截图:
- `browser_navigate(url='file:///tmp/card.html')`
- `browser_vision(question='截图')` → 自动保存 screenshot_path
3. 截图路径在 `/home/openclaw/.hermes/cache/screenshots/`
4. 复制到 `~/.hermes/output/xhs_images/` 供 opencli 使用
### ⚠️ chromium snap 限制
snap 版 chromium 的 `--screenshot` 参数受 AppArmor 限制,写文件会 permission denied。
**不要用** `chromium-browser --headless --screenshot=...`
**用** Hermes 内置 browser 工具(browser_navigate + browser_vision)。
### 卡片设计规范
- 宽度 420px,深色背景 (#1a1a2e#16213e 渐变)
- 金色 (#f0c040) 标题/强调
- 青绿 (#00d4aa) 数据
- 圆角 24px,内边距 36px 28px
- 免责声明小字 10px #555
@@ -0,0 +1,84 @@
<!DOCTYPE html>
<html><head><meta charset="utf-8"><style>
*{margin:0;padding:0;box-sizing:border-box}
body{background:#0d1117;display:flex;flex-direction:column;align-items:center;padding:20px;font-family:-apple-system,'PingFang SC','Noto Sans SC',sans-serif}
.card{width:420px;background:linear-gradient(135deg,#1a1a2e 0%,#16213e 100%);border-radius:24px;padding:36px 28px;color:#fff;position:relative;overflow:hidden;margin-bottom:30px}
.card::before{content:'';position:absolute;top:-50%;right:-50%;width:100%;height:100%;background:radial-gradient(circle,rgba(0,212,170,0.08) 0%,transparent 70%)}
.tag{display:inline-block;background:rgba(0,212,170,0.15);color:#00d4aa;padding:4px 12px;border-radius:20px;font-size:12px;margin-bottom:16px}
h1{font-size:22px;line-height:1.4;margin-bottom:20px;color:#f0f0f0}
.section{margin:18px 0;padding:16px;background:rgba(255,255,255,0.04);border-radius:14px;border-left:3px solid #f0c040}
.section-title{color:#f0c040;font-size:14px;font-weight:700;margin-bottom:10px}
.row{display:flex;justify-content:space-between;align-items:center;padding:6px 0}
.label{color:#8b949e;font-size:13px}
.value{color:#00d4aa;font-size:15px;font-weight:700}
.value-warn{color:#f0c040;font-size:15px;font-weight:700}
.big-num{text-align:center;margin:20px 0}
.big-num .num{font-size:52px;font-weight:900;background:linear-gradient(135deg,#00d4aa,#f0c040);-webkit-background-clip:text;-webkit-text-fill-color:transparent}
.big-num .unit{font-size:16px;color:#8b949e;margin-top:4px}
.ladder{display:flex;gap:8px;margin:12px 0}
.step{flex:1;text-align:center;padding:12px 4px;border-radius:12px;background:rgba(255,255,255,0.06)}
.step-n{font-size:11px;color:#8b949e;margin-bottom:4px}
.step-pct{font-size:22px;font-weight:900;color:#f0c040}
.step-label{font-size:11px;color:#666;margin-top:4px}
.divider{height:1px;background:rgba(255,255,255,0.08);margin:16px 0}
.footer{font-size:10px;color:#555;line-height:1.6;margin-top:20px}
.stock-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin:10px 0}
.stock-item{padding:10px;background:rgba(255,255,255,0.04);border-radius:10px;text-align:center}
.stock-flag{font-size:20px}
.stock-name{font-size:12px;color:#ccc;margin-top:2px}
.stock-yield{font-size:18px;font-weight:900;color:#00d4aa}
.stock-sub{font-size:10px;color:#666}
</style></head><body>
<!-- 卡片1: 数据主题卡 -->
<div class="card">
<div class="tag">💰 懒人收息法</div>
<h1>月投7500港币<br>高息股阶梯买入</h1>
<div class="big-num"><div class="num">7.5%</div><div class="unit">平均股息率</div></div>
<div class="ladder">
<div class="step"><div class="step-n">第1档</div><div class="step-pct">40%</div><div class="step-label">现价买入</div></div>
<div class="step" style="border:1px solid rgba(240,192,64,0.3)"><div class="step-n">第2档</div><div class="step-pct">30%</div><div class="step-label">小跌加仓</div></div>
<div class="step"><div class="step-n">第3档</div><div class="step-pct">30%</div><div class="step-label">大跌抄底</div></div>
</div>
<div class="divider"></div>
<div class="section">
<div class="section-title">📊 收息预估</div>
<div class="row"><span class="label">年投</span><span class="value">90,000 港币</span></div>
<div class="row"><span class="label">第二年起年息</span><span class="value-warn">≈ 6,300</span></div>
<div class="row"><span class="label">第五年累计股息</span><span class="value-warn">≈ 22,000+</span></div>
</div>
<div class="footer">⚠️ 个人记录,不构成投资建议 · 股市有风险</div>
</div>
<!-- 卡片2: 持仓清单卡 -->
<div class="card">
<div class="tag">📋 我的DCA组合</div>
<h1>7只标的 · 3档阶梯</h1>
<div style="color:#f0c040;font-size:13px;font-weight:700;margin:16px 0 8px">🇭🇰 港股(防守型)</div>
<div class="stock-grid">
<div class="stock-item"><div class="stock-flag">🏦</div><div class="stock-name">某保险龙头</div><div class="stock-yield">5.4%</div><div class="stock-sub">PE<7 破净</div></div>
<div class="stock-item"><div class="stock-flag">🏛️</div><div class="stock-name">某银行龙头</div><div class="stock-yield">6.9%</div><div class="stock-sub">PE 7 破净</div></div>
</div>
<div class="stock-grid" style="margin-top:8px">
<div class="stock-item"><div class="stock-flag">📡</div><div class="stock-name">某电信央企</div><div class="stock-yield">6.1%</div><div class="stock-sub">破净</div></div>
<div></div>
</div>
<div class="divider"></div>
<div style="color:#f0c040;font-size:13px;font-weight:700;margin:16px 0 8px">🇺🇸 美股(收息型)</div>
<div class="stock-grid">
<div class="stock-item"><div class="stock-flag">🏠</div><div class="stock-name">某mREIT</div><div class="stock-yield">13.2%</div><div class="stock-sub">PE 7.7</div></div>
<div class="stock-item"><div class="stock-flag">🚀</div><div class="stock-name">某科技BDC</div><div class="stock-yield">10.5%</div><div class="stock-sub">PE 8.5</div></div>
</div>
<div class="stock-grid" style="margin-top:8px">
<div class="stock-item"><div class="stock-flag">💼</div><div class="stock-name">某最大BDC</div><div class="stock-yield">10.2%</div><div class="stock-sub">PE 11.7</div></div>
<div class="stock-item"><div class="stock-flag">📱</div><div class="stock-name">某电信巨头</div><div class="stock-yield">4.9%</div><div class="stock-sub">PE 7.5</div></div>
</div>
<div class="divider"></div>
<div class="section" style="border-left-color:#00d4aa">
<div class="section-title" style="color:#00d4aa">🎯 5条纪律</div>
<div style="font-size:13px;color:#ccc;line-height:2">① 每月固定操作 ② 没到价位不动<br>③ 股息复投 ④ 只选盈利高分红<br>⑤ 港美股各半</div>
</div>
<div class="footer">⚠️ 个人记录,不构成投资建议 · 💬 评论区交流</div>
</div>
</body></html>
+432
View File
@@ -0,0 +1,432 @@
---
name: xurl
description: "X/Twitter via xurl CLI: post, search, DM, media, v2 API."
version: 1.1.1
author: xdevplatform + openclaw + Hermes Agent
license: MIT
platforms: [linux, macos]
prerequisites:
commands: [xurl]
metadata:
hermes:
tags: [twitter, x, social-media, xurl, official-api]
homepage: https://github.com/xdevplatform/xurl
upstream_skill: https://github.com/openclaw/openclaw/blob/main/skills/xurl/SKILL.md
---
# xurl — X (Twitter) API via the Official CLI
`xurl` is the X developer platform's official CLI for the X API. It supports shortcut commands for common actions AND raw curl-style access to any v2 endpoint. All commands return JSON to stdout.
Use this skill for:
- posting, replying, quoting, deleting posts
- searching posts and reading timelines/mentions
- liking, reposting, bookmarking
- following, unfollowing, blocking, muting
- direct messages
- media uploads (images and video)
- raw access to any X API v2 endpoint
- multi-app / multi-account workflows
This skill replaces the older `xitter` skill (which wrapped a third-party Python CLI). `xurl` is maintained by the X developer platform team, supports OAuth 2.0 PKCE with auto-refresh, and covers a substantially larger API surface.
---
## Secret Safety (MANDATORY)
Critical rules when operating inside an agent/LLM session:
- **Never** read, print, parse, summarize, upload, or send `~/.xurl` to LLM context.
- **Never** ask the user to paste credentials/tokens into chat.
- The user must fill `~/.xurl` with secrets manually on their own machine. In Docker, this must be the `~` seen by Hermes tool subprocesses; see the Docker note below.
- **Never** recommend or execute auth commands with inline secrets in agent sessions.
- **Never** use `--verbose` / `-v` in agent sessions — it can expose auth headers/tokens.
- To verify credentials exist, only use: `xurl auth status`.
Forbidden flags in agent commands (they accept inline secrets):
`--bearer-token`, `--consumer-key`, `--consumer-secret`, `--access-token`, `--token-secret`, `--client-id`, `--client-secret`
App credential registration and credential rotation must be done by the user manually, outside the agent session. After credentials are registered, the user authenticates with `xurl auth oauth2` — also outside the agent session. Tokens persist to `~/.xurl` in YAML. Each app has isolated tokens. OAuth 2.0 tokens auto-refresh.
---
## Installation
Pick ONE method. On Linux, the shell script or `go install` are the easiest.
```bash
# Shell script (installs to ~/.local/bin, no sudo, works on Linux + macOS)
curl -fsSL https://raw.githubusercontent.com/xdevplatform/xurl/main/install.sh | bash
# Homebrew (macOS)
brew install --cask xdevplatform/tap/xurl
# npm
npm install -g @xdevplatform/xurl
# Go
go install github.com/xdevplatform/xurl@latest
```
Verify:
```bash
xurl --help
xurl auth status
```
If `xurl` is installed but `auth status` shows no apps or tokens, the user needs to complete auth manually — see the next section.
---
## One-Time User Setup (user runs these outside the agent)
These steps must be performed by the user directly, NOT by the agent, because they involve pasting secrets. Direct the user to this block; do not execute it for them.
1. Create or open an app at https://developer.x.com/en/portal/dashboard
2. Set the redirect URI to `http://localhost:8080/callback`
3. Copy the app's Client ID and Client Secret
4. Register the app locally (user runs this):
```bash
xurl auth apps add my-app --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET
```
5. Authenticate (specify `--app` to bind the token to your app):
```bash
xurl auth oauth2 --app my-app
```
(This opens a browser for the OAuth 2.0 PKCE flow.)
If X returns a `UsernameNotFound` error or 403 on the post-OAuth `/2/users/me` lookup, pass your handle explicitly (xurl v1.1.0+):
```bash
xurl auth oauth2 --app my-app YOUR_USERNAME
```
This binds the token to your handle and skips the broken `/2/users/me` call.
6. Set the app as default so all commands use it:
```bash
xurl auth default my-app
```
7. Verify:
```bash
xurl auth status
xurl whoami
```
After this, the agent can use any command below without further setup. OAuth 2.0 tokens auto-refresh.
> **Common pitfall:** If you omit `--app my-app` from `xurl auth oauth2`, the OAuth token is saved to the built-in `default` app profile — which has no client-id or client-secret. Commands will fail with auth errors even though the OAuth flow appeared to succeed. If you hit this, re-run `xurl auth oauth2 --app my-app` and `xurl auth default my-app`.
> **Docker HOME pitfall:** In the official Hermes Docker layout, `/opt/data` is `HERMES_HOME`, but Hermes tool subprocesses use `/opt/data/home` as `HOME`. That means `~/.xurl` resolves to `/opt/data/home/.xurl` for Hermes-run `xurl` commands, not `/opt/data/.xurl`. Run the user setup with the same HOME:
> ```bash
> HOME=/opt/data/home xurl auth apps add my-app --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET
> HOME=/opt/data/home xurl auth oauth2 --app my-app YOUR_USERNAME
> HOME=/opt/data/home xurl auth default my-app YOUR_USERNAME
> HOME=/opt/data/home xurl auth status
> ```
> If `HOME=/opt/data xurl auth status` succeeds but `HOME=/opt/data/home xurl auth status` shows no apps or tokens, Hermes tool calls will not see the credentials.
---
## Quick Reference
| Action | Command |
| --- | --- |
| Post | `xurl post "Hello world!"` |
| Reply | `xurl reply POST_ID "Nice post!"` |
| Quote | `xurl quote POST_ID "My take"` |
| Delete a post | `xurl delete POST_ID` |
| Read a post | `xurl read POST_ID` |
| Search posts | `xurl search "QUERY" -n 10` |
| Who am I | `xurl whoami` |
| Look up a user | `xurl user @handle` |
| Home timeline | `xurl timeline -n 20` |
| Mentions | `xurl mentions -n 10` |
| Like / Unlike | `xurl like POST_ID` / `xurl unlike POST_ID` |
| Repost / Undo | `xurl repost POST_ID` / `xurl unrepost POST_ID` |
| Bookmark / Remove | `xurl bookmark POST_ID` / `xurl unbookmark POST_ID` |
| List bookmarks / likes | `xurl bookmarks -n 10` / `xurl likes -n 10` |
| Follow / Unfollow | `xurl follow @handle` / `xurl unfollow @handle` |
| Following / Followers | `xurl following -n 20` / `xurl followers -n 20` |
| Block / Unblock | `xurl block @handle` / `xurl unblock @handle` |
| Mute / Unmute | `xurl mute @handle` / `xurl unmute @handle` |
| Send DM | `xurl dm @handle "message"` |
| List DMs | `xurl dms -n 10` |
| Upload media | `xurl media upload path/to/file.mp4` |
| Media status | `xurl media status MEDIA_ID` |
| List apps | `xurl auth apps list` |
| Remove app | `xurl auth apps remove NAME` |
| Set default app | `xurl auth default APP_NAME [USERNAME]` |
| Per-request app | `xurl --app NAME /2/users/me` |
| Auth status | `xurl auth status` |
Notes:
- `POST_ID` accepts full URLs too (e.g. `https://x.com/user/status/1234567890`) — xurl extracts the ID.
- Usernames work with or without a leading `@`.
---
## Command Details
### Posting
```bash
xurl post "Hello world!"
xurl post "Check this out" --media-id MEDIA_ID
xurl post "Thread pics" --media-id 111 --media-id 222
xurl reply 1234567890 "Great point!"
xurl reply https://x.com/user/status/1234567890 "Agreed!"
xurl reply 1234567890 "Look at this" --media-id MEDIA_ID
xurl quote 1234567890 "Adding my thoughts"
xurl delete 1234567890
```
### Reading & Search
```bash
xurl read 1234567890
xurl read https://x.com/user/status/1234567890
xurl search "golang"
xurl search "from:elonmusk" -n 20
xurl search "#buildinpublic lang:en" -n 15
```
For X Articles, use raw API mode instead of the `read` shortcut. `xurl read`
expects a post ID or post URL; do not put `read` before a `/2/tweets/...`
endpoint. Request the `article` tweet field and ingest `data.article.plain_text`
from the JSON response:
```bash
xurl --app APP_NAME '/2/tweets/2057909493250539891?expansions=author_id,attachments.media_keys,referenced_tweets.id&tweet.fields=created_at,lang,public_metrics,context_annotations,entities,possibly_sensitive,conversation_id,in_reply_to_user_id,referenced_tweets,article'
```
### Users, Timeline, Mentions
```bash
xurl whoami
xurl user elonmusk
xurl user @XDevelopers
xurl timeline -n 25
xurl mentions -n 20
```
### Engagement
```bash
xurl like 1234567890
xurl unlike 1234567890
xurl repost 1234567890
xurl unrepost 1234567890
xurl bookmark 1234567890
xurl unbookmark 1234567890
xurl bookmarks -n 20
xurl likes -n 20
```
### Social Graph
```bash
xurl follow @XDevelopers
xurl unfollow @XDevelopers
xurl following -n 50
xurl followers -n 50
# Another user's graph
xurl following --of elonmusk -n 20
xurl followers --of elonmusk -n 20
xurl block @spammer
xurl unblock @spammer
xurl mute @annoying
xurl unmute @annoying
```
### Direct Messages
```bash
xurl dm @someuser "Hey, saw your post!"
xurl dms -n 25
```
### Media Upload
```bash
# Auto-detect type
xurl media upload photo.jpg
xurl media upload video.mp4
# Explicit type/category
xurl media upload --media-type image/jpeg --category tweet_image photo.jpg
# Videos need server-side processing — check status (or poll)
xurl media status MEDIA_ID
xurl media status --wait MEDIA_ID
# Full workflow
xurl media upload meme.png # returns media id
xurl post "lol" --media-id MEDIA_ID
```
---
## Raw API Access
The shortcuts cover common operations. For anything else, use raw curl-style mode against any X API v2 endpoint:
```bash
# GET
xurl /2/users/me
# POST with JSON body
xurl -X POST /2/tweets -d '{"text":"Hello world!"}'
# DELETE / PUT / PATCH
xurl -X DELETE /2/tweets/1234567890
# Custom headers
xurl -H "Content-Type: application/json" /2/some/endpoint
# Force streaming
xurl -s /2/tweets/search/stream
# Full URLs also work
xurl https://api.x.com/2/users/me
```
---
## Global Flags
| Flag | Short | Description |
| --- | --- | --- |
| `--app` | | Use a specific registered app (overrides default) |
| `--auth` | | Force auth type: `oauth1`, `oauth2`, or `app` |
| `--username` | `-u` | Which OAuth2 account to use (if multiple exist) |
| `--verbose` | `-v` | **Forbidden in agent sessions** — leaks auth headers |
| `--trace` | `-t` | Add `X-B3-Flags: 1` trace header |
---
## Streaming
Streaming endpoints are auto-detected. Known ones include:
- `/2/tweets/search/stream`
- `/2/tweets/sample/stream`
- `/2/tweets/sample10/stream`
Force streaming on any endpoint with `-s`.
---
## Output Format
All commands return JSON to stdout. Structure mirrors X API v2:
```json
{ "data": { "id": "1234567890", "text": "Hello world!" } }
```
Errors are also JSON:
```json
{ "errors": [ { "message": "Not authorized", "code": 403 } ] }
```
---
## Common Workflows
### Post with an image
```bash
xurl media upload photo.jpg
xurl post "Check out this photo!" --media-id MEDIA_ID
```
### Reply to a conversation
```bash
xurl read https://x.com/user/status/1234567890
xurl reply 1234567890 "Here are my thoughts..."
```
### Search and engage
```bash
xurl search "topic of interest" -n 10
xurl like POST_ID_FROM_RESULTS
xurl reply POST_ID_FROM_RESULTS "Great point!"
```
### Check your activity
```bash
xurl whoami
xurl mentions -n 20
xurl timeline -n 20
```
### Multiple apps (credentials pre-configured manually)
```bash
xurl auth default prod alice # prod app, alice user
xurl --app staging /2/users/me # one-off against staging
```
---
## Error Handling
- Non-zero exit code on any error.
- API errors are still printed as JSON to stdout, so you can parse them.
- Auth errors → have the user re-run `xurl auth oauth2` outside the agent session.
- Commands that need the caller's user ID (like, repost, bookmark, follow, etc.) will auto-fetch it via `/2/users/me`. An auth failure there surfaces as an auth error.
---
## Agent Workflow
1. Verify prerequisites: `xurl --help` and `xurl auth status`.
2. **Check default app has credentials.** Parse the `auth status` output. The default app is marked with ``. If the default app shows `oauth2: (none)` but another app has a valid oauth2 user, tell the user to run `xurl auth default <that-app>` to fix it. This is the most common setup mistake — the user added an app with a custom name but never set it as default, so xurl keeps trying the empty `default` profile.
3. If auth is missing entirely, stop and direct the user to the "One-Time User Setup" section — do NOT attempt to register apps or pass secrets yourself.
4. Start with a cheap read (`xurl whoami`, `xurl user @handle`, `xurl search ... -n 3`) to confirm reachability.
5. Confirm the target post/user and the user's intent before any write action (post, reply, like, repost, DM, follow, block, delete).
6. Use JSON output directly — every response is already structured.
7. Never paste `~/.xurl` contents back into the conversation.
---
## Troubleshooting
| Symptom | Cause | Fix |
| --- | --- | --- |
| Auth errors after successful OAuth flow | Token saved to `default` app (no client-id/secret) instead of your named app | `xurl auth oauth2 --app my-app` then `xurl auth default my-app` |
| `unauthorized_client` during OAuth | App type set to "Native App" in X dashboard | Change to "Web app, automated app or bot" in User Authentication Settings |
| `UsernameNotFound` or 403 on `/2/users/me` right after OAuth | X not returning username reliably from `/2/users/me` | Re-run `xurl auth oauth2 --app my-app YOUR_USERNAME` (xurl v1.1.0+) to pass the handle explicitly |
| 401 on every request | Token expired or wrong default app | Check `xurl auth status` — verify `` points to an app with oauth2 tokens |
| `client-forbidden` / `client-not-enrolled` | X platform enrollment issue | Dashboard → Apps → Manage → Move to "Pay-per-use" package → Production environment |
| `CreditsDepleted` | $0 balance on X API | Buy credits (min $5) in Developer Console → Billing |
| `media processing failed` on image upload | Default category is `amplify_video` | Add `--category tweet_image --media-type image/png` |
| Two "Client Secret" values in X dashboard | UI bug — first is actually Client ID | Confirm on the "Keys and tokens" page; ID ends in `MTpjaQ` |
---
## Notes
- **Rate limits:** X enforces per-endpoint rate limits. A 429 means wait and retry. Write endpoints (post, reply, like, repost) have tighter limits than reads.
- **Scopes:** OAuth 2.0 tokens use broad scopes. A 403 on a specific action usually means the token is missing a scope — have the user re-run `xurl auth oauth2`.
- **Token refresh:** OAuth 2.0 tokens auto-refresh. Nothing to do.
- **Multiple apps:** Each app has isolated credentials/tokens. Switch with `xurl auth default` or `--app`.
- **Multiple accounts per app:** Select with `-u / --username`, or set a default with `xurl auth default APP USER`.
- **Token storage:** `~/.xurl` is YAML. In Docker, use the Hermes subprocess HOME (`/opt/data/home` in the official image) so tokens land under `/opt/data/home/.xurl`. Never read or send this file to LLM context.
- **Cost:** X API access is typically paid for meaningful usage. Many failures are plan/permission problems, not code problems.
---
## Attribution
- Upstream CLI: https://github.com/xdevplatform/xurl (X developer platform team, Chris Park et al.)
- Upstream agent skill: https://github.com/openclaw/openclaw/blob/main/skills/xurl/SKILL.md
- Hermes adaptation: reformatted for Hermes skill conventions; safety guardrails preserved verbatim.