skills/obsidian-to-x/SKILL.md
发布内容和文章到 X (Twitter)。支持常规推文(文字/图片/视频)和 X Articles(长文 Markdown)。使用真实 Chrome 浏览器绕过反机器人检测。当用户说"发推"、"发到 X"、"发到 twitter"、"分享到 X"、"分享到 twitter"、"发 tweet"、"同步到 X"、"发布到 X"、提到"X Articles"、想从 Obsidian 笔记发布长文内容、或需要转换 Obsidian Markdown 到 X 格式时使用。适用于所有 X/Twitter 发布任务。
npx skillsauth add libukai/awesome-agent-skills obsidian-to-xInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Posts text, images, videos, and long-form articles to X via real Chrome browser (bypasses anti-bot detection).
When user invokes this skill without specifying what to publish (e.g., just says "发到 X" or uses slash command):
Clean Chrome CDP processes first (see CDP Cleanup below)
Get current active file,按优先级依次尝试:
优先级 1:<current_note> 标签(Claudian 注入,最准确)
检查用户消息末尾是否有 <current_note> 标签,直接提取路径,无需执行任何命令。
优先级 2:workspace.json(本地 fallback)
jq -r '.lastOpenFiles[] | select(endswith(".md"))' .obsidian/workspace.json | head -1
优先级 3:Obsidian CLI(最后手段)
obsidian file active
Read the file content using Read tool
Auto-detect publishing type:
是否长文: true是否长文: true → Publish as X Article (long-form)是否长文: false, 是否长文 absent, or no frontmatter → Publish as Regular Post (short-form)Inform user of detected type and proceed with publishing
Execute appropriate workflow:
x-article.ts (handles Obsidian conversion internally)md-to-post.ts → Publish with x-post.tsExecute publishing scripts via Bash background process (REQUIRED - do NOT use Agent run_in_background=true):
& with log redirected to vault: bun ... > .temp/x-article-output.log 2>&1 &run_in_background=true — the output file lands in /private/tmp/ which is blocked by vault permission hooks, causing TaskOutput to fail and triggering a duplicate execution.temp/x-article-output.log with sleep N && cat .temp/x-article-output.log | tail -30Success Detection: Check .temp/x-article-output.log for success markers:
Image upload verified occurrences matching expected image countPost composed (preview mode) or Browser remains openArticle composed or Browser remains opensleep 15 && cat .temp/x-article-output.log | tail -30 to pollExample:
User: "发到 X"
AI: ✓ Detected current file: Articles/news/my-article.md
✓ Found `是否文章: true` → Publishing as X Article
[proceeds with article publishing workflow]
Run this before every publishing script to prevent "Chrome debug port not ready" errors. Do it automatically — no need to ask the user.
pkill -f "Chrome.*remote-debugging-port"; pkill -f "Chromium.*remote-debugging-port"; sleep 2
X Articles vs Regular Posts:
| Feature | X Articles | Regular Posts |
|---------|-----------|---------------|
| Content | Rich text (Markdown) | Plain text only |
| Formatting | ✅ Bold, italic, headers, lists | ❌ All stripped |
| Code blocks | ✅ Syntax highlighting | ❌ Not supported |
| Images | ✅ Multiple images | ✅ Max 4 images |
| Length | Long-form (unlimited) | Short (280 chars) |
| Requirements | X Premium | Free |
| Script | x-article.ts | x-post.ts |
| Conversion | md-to-article.ts | md-to-post.ts |
When to use:
For Obsidian users who want to publish the currently active article:
bash ${SKILL_DIR}/scripts/publish-active.sh
This automatically:
Important: All scripts are located in the scripts/ subdirectory of this skill.
Agent Execution Instructions:
SKILL_DIR${SKILL_DIR}/scripts/<script-name>.ts${SKILL_DIR} in this document with the actual path${BUN_X} runtime: if bun installed → bun; if npx available → npx -y bun; else suggest installing bunScript Reference:
| Script | Purpose |
|--------|---------|
| Publishing Scripts | |
| scripts/x-post.ts | Publish regular posts (text + images, max 4) |
| scripts/x-video.ts | Publish video posts (text + video) |
| scripts/x-quote.ts | Publish quote tweet with comment |
| scripts/x-article.ts | Publish X Articles (rich text + images + code) |
| Conversion Scripts | |
| scripts/md-to-post.ts | Convert Obsidian Markdown → plain text + images (for Posts) |
| scripts/md-to-article.ts | Convert Obsidian Markdown → HTML + images (for Articles) |
| Utilities | |
| scripts/publish-active.sh | One-command publish for active Obsidian file |
bun runtimejq tool (brew install jq on macOS)Before first use, suggest running the environment check:
${BUN_X} ${SKILL_DIR}/scripts/check-paste-permissions.ts
Checks: Chrome, Bun, Accessibility permissions, clipboard, paste keystroke.
If any check fails, provide fix guidance per item:
| Check | Fix |
|-------|-----|
| Chrome | Install Chrome or set X_BROWSER_CHROME_PATH env var |
| Bun runtime | brew install oven-sh/bun/bun (macOS) or npm install -g bun |
| Accessibility (macOS) | System Settings → Privacy & Security → Accessibility → enable terminal app |
| Paste keystroke (Linux) | Install xdotool (X11) or ydotool (Wayland) |
For Obsidian users, this skill can automatically detect the currently active file and convert Obsidian-specific syntax.
Quick workflow:
# One-command publish
bash ${SKILL_DIR}/scripts/publish-active.sh
Manual workflow:
# Step 1: Get active file (workspace.json method, 39x faster)
ACTIVE_FILE=$(jq -r '.lastOpenFiles[0]' .obsidian/workspace.json)
# Step 2: Publish (x-article.ts handles Obsidian conversion internally)
bun ${SKILL_DIR}/scripts/x-article.ts "$ACTIVE_FILE"
For detailed Obsidian integration, see references/obsidian-integration.md:
For Obsidian syntax conversion, see references/obsidian-conversion.md:
![[]] image syntaxText + up to 4 images. Plain text only (all Markdown formatting stripped).
Step 1: CDP cleanup (see CDP Cleanup section)
Step 2: Convert Markdown to plain text + images
# Extract content from Markdown file
# Supports both standard Markdown  and Obsidian ![[path]] image syntax
# --output-dir keeps downloaded images inside the vault (.temp) to avoid permission issues
bun ${SKILL_DIR}/scripts/md-to-post.ts "Articles/my-post.md" --output-dir ".temp/x-post" > .temp/post-content.json
TEXT=$(jq -r '.text' .temp/post-content.json)
IMAGES=$(jq -r '.images[]' .temp/post-content.json)
Image Syntax Support:
![[path/to/image.png]] or ![[https://example.com/image.jpg]]Step 2.5: 提取封面图作为第一张图
从文件 frontmatter 中读取 封面 属性,若存在则将其路径作为第一张图片:
# 提取 封面 属性(支持 ![[path]] 和裸路径两种格式)
COVER_RAW=$(grep -m1 '^封面:' "Articles/my-post.md" | sed 's/^封面: *//' | tr -d '"')
# 解析 Obsidian wikilink 格式 ![[path]] → path
COVER_PATH=$(echo "$COVER_RAW" | sed 's/^!\[\[//;s/\]\]$//')
# 组合图片列表:封面优先,正文图片补充(总数上限 4 张)
IMAGE_ARGS=""
if [ -n "$COVER_PATH" ]; then
IMAGE_ARGS="--image \"$COVER_PATH\""
fi
for img in $IMAGES; do
IMAGE_ARGS="$IMAGE_ARGS --image \"$img\""
done
封面 属性为空或不存在,则跳过,仅使用正文图片Step 3: Publish post
eval "${BUN_X} ${SKILL_DIR}/scripts/x-post.ts \"$TEXT\" $IMAGE_ARGS"
${BUN_X} ${SKILL_DIR}/scripts/x-post.ts "Hello!" --image ./photo.png
Parameters:
| Parameter | Description |
|-----------|-------------|
| <text> | Post content (plain text, positional) |
| --image <path> | Image file (repeatable, max 4) |
| --profile <dir> | Custom Chrome profile |
Content Processing:
Browser Behavior:
--submit flag to auto-publish (closes after 2 seconds)AI Success Detection (for background execution):
Image upload verified in output matching expected image countPost composed (preview mode) or Browser remains open1. Know you're uploading 3 images
2. Wait 10-15s for uploads
3. Check output: grep "Image upload verified" | wc -l
4. If count == 3 → Report success immediately
Text + video file.
Step 1: CDP cleanup (see CDP Cleanup section)
Step 2: Publish video post
${BUN_X} ${SKILL_DIR}/scripts/x-video.ts "Check this out!" --video ./clip.mp4
Parameters:
| Parameter | Description |
|-----------|-------------|
| <text> | Post content (positional) |
| --video <path> | Video file (MP4, MOV, WebM) |
| --profile <dir> | Custom Chrome profile |
Limits: Regular 140s max, Premium 60min. Processing: 30-60s.
Quote an existing tweet with comment.
Step 1: CDP cleanup (see CDP Cleanup section)
Step 2: Publish quote tweet
${BUN_X} ${SKILL_DIR}/scripts/x-quote.ts https://x.com/user/status/123 "Great insight!"
Parameters:
| Parameter | Description |
|-----------|-------------|
| <tweet-url> | URL to quote (positional) |
| <comment> | Comment text (positional, optional) |
| --profile <dir> | Custom Chrome profile |
Long-form Markdown articles (requires X Premium).
Step 1: CDP cleanup (see CDP Cleanup section)
Step 2: Publish article
${BUN_X} ${SKILL_DIR}/scripts/x-article.ts article.md
${BUN_X} ${SKILL_DIR}/scripts/x-article.ts article.md --cover ./cover.jpg
Parameters:
| Parameter | Description |
|-----------|-------------|
| <markdown> | Markdown file (positional) |
| --cover <path> | Cover image |
| --title <text> | Override title |
Frontmatter: title / 标题, cover_image / 封面 / 配图 supported in YAML front matter.
Title Resolution (for X Articles):
# 优先读 frontmatter 的 `标题` 属性,为空则 fallback 到文件名
TITLE=$(obsidian property:read name="标题" path="$NOTE_PATH" 2>/dev/null | tr -d '[:space:]')
if [ -z "$TITLE" ]; then
TITLE=$(basename "$NOTE_PATH" .md)
fi
# 传入脚本
${BUN_X} ${SKILL_DIR}/scripts/x-article.ts "$NOTE_PATH" --title "$TITLE"
Note: Script opens browser with article filled in. User reviews and publishes manually.
Code blocks are automatically extracted from Markdown and inserted into X Articles editor. Supports all languages (JavaScript, Python, TypeScript, Rust, Go, Shell, etc.). No manual action required.
Common issues:
md-to-post.ts downloads images to system /tmp by default, which may be blocked by vault-restricted hooks. Fix: always pass --output-dir ".temp/x-post" to keep images inside the vault:
bun ${SKILL_DIR}/scripts/md-to-post.ts "Articles/my-post.md" --output-dir ".temp/x-post"
For detailed troubleshooting, see references/troubleshooting.md.
references/obsidian-integration.md - Obsidian file detection and integrationreferences/obsidian-conversion.md - Converting Obsidian syntax to standard Markdownreferences/regular-posts.md - Regular posts workflow and troubleshootingreferences/articles.md - X Articles detailed guidereferences/troubleshooting.md - Common issues and solutionsreferences/browser-automation-lessons.md - Browser automation patterns and lessons learned (CDP, DraftJS, background tabs)Custom configurations via EXTEND.md. Check these paths (priority order):
.libukai-skills/obsidian-to-x/EXTEND.md (project directory)$HOME/.libukai-skills/obsidian-to-x/EXTEND.md (user home)EXTEND.md Supports: Default Chrome profile
--submit flag)development
This skill should be used when setting up SFTP deployment for static websites to production servers, including converting projects from Docker/Express to static hosting, deploying Vue/React/Angular builds, setting up Slidev presentations, or configuring Hugo/Jekyll/Gatsby sites. Use this when the user asks to "setup SFTP deployment", "deploy static site to server", "configure Nginx for static files", "convert from Docker to static hosting", "deploy Vue build to production", "setup subdomain hosting", or "configure SFTP in VS Code". Provides SFTP configuration templates and production-ready Nginx configurations with security headers and caching.
tools
This skill should be used when configuring VS Code Port Monitor extension for development server monitoring. Use when the user asks to "set up port monitoring for Vite", "monitor my dev server ports", "configure port monitor for Next.js", "track which ports are running", "set up multi-port monitoring", "monitor frontend and backend ports", or "check port status in VS Code". Provides ready-to-use configuration templates for Vite (5173), Next.js (3000), and microservices architectures with troubleshooting guidance.
tools
Configure VSCode with httpYac for API testing and automation. This skill should be used specifically when converting API documentation to executable .http files (10+ endpoints), setting up authentication flows with pre-request scripts, implementing request chaining with response data, organizing multi-file collections with environment management, or establishing Git-based API testing workflows with CI/CD integration.
tools
Configure MCP (Model Context Protocol) servers for Claude Code. Manage MCP servers at user or project scope with best practices to avoid context pollution.