Preserve valuable content from X into an Obsidian vault to build a searchable knowledge asset.
Customer-readable description
What this skill can do
Archive X/Twitter tweets, threads, and Articles to an Obsidian vault. Based on the fxtwitter API, zero configuration for single items; optionally sync Telegram favorites. When PDF is needed, prefer Obsidian export
| Customer wants | Skill will do | Customer can see |
|---|---|---|
| Complete the work covered by this skill | Read the user request, necessary context, and this skill's main workflow, then execute the minimal reliable steps | The customer will see Obsidian/vault file changes, terminal logs, generated artifact paths, and a final receipt. |
| Missing dependencies, permissions, configuration, or keys | Stop actions that require external state and clearly state what is missing | Install commands, application URLs, configuration paths, or questions requiring customer confirmation |
| Execution complete | Summarize successes, skips, failures, file changes, and verification results | A completion receipt that can be copied into a ticket/log |
How the customer uses it
- State the goal in natural language and provide the necessary inputs: files, URLs, repos, workspaces, proposals, vaults, or platform account status.
- The Agent first determines whether this skill applies, then checks dependencies, configuration, permissions, and risky actions.
- For actions that can be dry-run or previewed, provide a preview first; for actions involving deletion, overwriting, sending, publishing, or writing remote state, ask the customer for confirmation first.
- After execution, verify the actual output; do not substitute "looks successful" for evidence.
- The final reply must give the customer a visible summary: what was done, log summary, file changes, issues, and next steps.
Dependencies and installation
Install this skill (single skill):
npx skills add soia-team/soia-open-skills -g -a '*' -s soia-pkm-clip-x -y
Configuration conventions:
~/.config/soia-skills/soia-open-skills/soia-pkm/soia-pkm-clip-x/config.yml
SOIA_PKM_CLIP_X_CONFIG_FILE=<custom-config-path>
- If this skill does not require private configuration, you may skip creating
config.yml。 - If an API key, cookie, session, provider home, or local path is required, it may only go into private
config.yml, the process environment, or the provider's own login state; it must not be written into the repository, vault body, or logs. - Strong dependencies, optional dependencies, and third-party skill relationships must be based on this
SKILL.mdand the subsequent "dependencies / prerequisites / resources / boundaries" description; if it is not clearly written, add the description first or ask the customer, do not guess. - Third-party skills may only declare dependencies and installation methods; do not directly modify third-party skill files.
Logs and completion receipt
Every execution must let the customer see the process and results. Minimum receipt format:
完成:<一句话说明本次完成了什么>。
日志摘要:
- started: <检查到的输入/配置/依赖,不打印秘密值>
- processed: <数量或范围>
- created/updated: <数量或路径>
- skipped/failed: <数量和原因>
文件变化:
- <绝对路径或“未改动文件”>
验证:
- <运行过的检查、命令或人工核对点>
问题与下一步:
- <缺 key / 缺依赖 / 需要客户确认 / 建议下一条命令;没有则写“无”>
Positioning
X's native UI is not conducive to long-term review: threads are scattered across the timeline, Article formatting is messy, links easily expire, and search is weak. This skill preserves high-quality long-form content from X into Obsidian in one click:
- Complete thread unroll
- X Article full content retrieval
content.blocks - Complete metadata (author, metrics, direct media links, created_at)
- frontmatter topic double links, convenient for MOC aggregation
- Multilingual recognition (zh / en / ja / ko)
Prerequisites
- Obsidian vault (any structure)
- Python 3, pure stdlib (no third-party dependencies, archives a single tweet)
- Optional:
pip install telethon(only for MTProto sync) - Vault location priority:
- command line
--vault <path> - environment variable
OBSIDIAN_VAULT - automatically discover vault upward from the current working directory (look for
AGENTS.md/.obsidian)
- command line
- Article directory location priority:
- command line
--articles-dir <subdir> - environment variable
OBSIDIAN_ARTICLES - fall back to the generic default
Articles; the script will print the following warning to stderr, and the exit code remains 0:WARN: 未找到 articles 目录配置(--articles-dir / OBSIDIAN_ARTICLES / config.yml),已落默认 Articles/——该目录不是本 vault 的正式归档位,请确认或配置
- command line
Note: tools such as Claude Code / Codex / Gemini CLI / opencode often execute commands in a non-login shell and may not inherit the
exportfrom shell startup files. The script will first load the privateconfig.yml, then automatically discover the vault from the cwd; if the agent is already in the vault directory, just run it directly.
-
Private
config.yml(optional,do not place in the vault or an open-source skill repository):Priority:
$SOIA_PKM_CLIP_X_CONFIG_FILE(or compatible alias$SOIA_PKM_CLIP_X_ENV_FILE)>~/.config/soia-skills/soia-open-skills/soia-pkm/soia-pkm-clip-x/config.yml。Supported variable names:
OBSIDIAN_VAULT、OBSIDIAN_ARTICLES、X_ARCHIVE_LANG; only MTProto sync requiresTELEGRAM_API_ID/TELEGRAM_API_HASH/TELEGRAM_SESSION_STRING. Real values are written only in the privateconfig.yml, not in this file.
Core API: fxtwitter
Replace the x.com in the X URL with api.fxtwitter.com, and directly GET back JSON. No X API key, no login, zero cost.
| Key field | Purpose |
|---|---|
tweet.text / tweet.raw_text.text |
Tweet body |
tweet.article.title |
X Article title |
tweet.article.content.blocks[] |
Article long-form blocks |
tweet.replying_to_status |
Previous tweet (thread backtracking) |
tweet.quote |
Quoted tweet |
tweet.media[] |
Media (direct image/video links) |
tweet.created_timestamp |
UNIX timestamp |
tweet.views / likes / bookmarks / retweets |
metrics |
Fallback: fxtwitter failure → cdn.syndication.twimg.com public endpoint.
Trigger words
| User says | Invoke |
|---|---|
| "Archive this X: URL" / "archive this: URL" | Run in the vault root archive_x.py <URL>; if not inside the vault, add --vault <path>. For non-Chinese content, a translation is automatically added by default (see step 4 of the workflow below); no need to additionally say "translate" |
| "Archive and convert to PDF: URL" / "Archive and export PDF: URL" | First write and complete the Markdown according to the default archiving workflow, then follow references/obsidian-pdf-export.md to use Obsidian's native export; do not prioritize pandoc/wkhtmltopdf |
| "Organize this thread: URL" | Same as above, force thread backtracking |
| "Sync my Telegram favorites" + provide JSON path | sync_telegram_export.py <path> --dry-run check first, then actually run after confirmation |
| "Sync Telegram via API" (credentials already available) | sync_telegram_saved.py |
Workflow (default archiving)
- Parse URL → handle + status_id
- Call script
archive_x.py <URL> - The script checks whether the vault already has it archived (by frontmatter
url:field)- Already exists → output SKIP, exit
- Otherwise → fetch fxtwitter, write to vault
- AI later supplements:
- 1-sentence Chinese
## 摘要 - 1-3
topicsDual-chain +peopledual-chain - Non-Chinese content (
languageis not zh): by default, fill the## 中文译文segment into a complete translation, without the user needing to additionally say "translate". Requirementsfree translation, not literal translation— it should read like Chinese written by a human, not machine-translation-ese; proper nouns, product names, and code/command/API parameters keep their original English, and only narrative text and explanations are translated
- 1-sentence Chinese
- The "My take" section is always left blank for the user
Export PDF after archiving
When the user also requests "convert to PDF / export PDF", first complete the Markdown archiving, summary, topics/people, and month placement, then read and execute references/obsidian-pdf-export.md. As long as the target file is inside the Obsidian vault, prefer calling Obsidian's built-in "Export PDF"; external PDF engines can only serve as an explicit fallback.
Telegram Saved Messages batch sync
Batch-archive X links casually forwarded from a phone to Telegram "Saved Messages" into the vault.Recommended JSON export path(zero risk, zero dependencies).
Complete steps, commands, and caveats for both paths (JSON export / MTProto API) → see references/telegram-sync.md。
File naming
<YYYY-MM-DD>-X-<handle>-<title前 50 字>.md
Example:
2026-05-24-X-cyrilXBT-How-to-Organize-Your-Obsidian-Vault.md2026-05-29-X-ObsidianOtaku-保存版AIエージェントのためのObsidian活用術.md
Multiple posts by the same author on the same day → append -<status_id 后 6 位>。
Output frontmatter
---
tags: [文章摘抄]
source: X
url: https://x.com/<handle>/status/<id>
author: <显示名>
handle: "@<handle>"
published_at: YYYY-MM-DD HH:mm
captured_at: YYYY-MM-DD HH:mm
language: zh / en / ja / ko
type: tweet / thread / article
topics: ["[[xxx]]", ...] # AI 填
people: ["[[xxx]]", ...] # AI 填
media: [...] / 0
content_complete: true
metrics:
views: N
likes: N
bookmarks: N
---
Boundaries and exceptions
| Scenario | Handling |
|---|---|
| fxtwitter returns 404 | Tweet deleted/private, suggest checking archive.org |
| fxtwitter 5xx | Retry once, fall back to the syndication endpoint on failure |
| URL is not x.com / twitter.com | Reject, suggest using Web Clipper |
| Tweet text empty and no article and no media | Warn: "pure retweet/pure reply, may have no standalone content" |
| Duplicate filename for same author on same day | Append -<status_id 后 6 位> |
| Video media | frontmatter media[] record the mp4 direct link, do not embed |
Command-line reference (archiving)
python3 archive_x.py <URL>
python3 archive_x.py <URL> --force # 覆盖已归档
python3 archive_x.py <URL> --vault /path/to/vault # 覆盖环境变量
python3 archive_x.py <URL> --articles-dir <articles-subdir>
Telegram sync command → see references/telegram-sync.md。
Completion receipt
Delivery order: first write the file to disk, then output the receipt below; never the reverse; uncertain metadata (such as author or publish time that failed to parse) must be explicitly marked "unverified" in the receipt, do not fabricate.
After executionmustoutput to the user (do not silently finish):
- What was done — a one-sentence summary of the completed work.
- File changes — list newly created / modified / moved files (full paths); if no files were changed, state "no files changed".
- The receipt must include the actual on-disk directory; if the
Articles/fallback was used, it must explicitly note that this directory is not the official archive location of this vault, and suggest the user configure--articles-dir、OBSIDIAN_ARTICLESor a privateconfig.ymland then relocate it.
- The receipt must include the actual on-disk directory; if the
- Next steps — optional follow-up suggestions (such as the next skill to connect with).