byjimliu· 68 skills
Converts X (Twitter) tweets and articles to markdown with YAML front matter. Uses reverse-engineered API requiring user consent. Use when user mentions "X to markdown", "tweet to markdown", "save tweet", or provides x.com/twitter.com URLs for conversion.
$npx -y skills add jimliu/baoyu-skills --skill baoyu-danger-x-to-markdownInstalls into the current project.
Run `npx skills use "https://github.com/jimliu/baoyu-skills" --skill "jimliu/baoyu-skills/baoyu-danger-x-to-markdown"` and follow the generated skill instructions now. Read its complete output, redirecting it to a temporary file first if necessary. Resolve relative paths from the supporting-files directory it provides.
Use the skills in "https://github.com/jimliu/baoyu-skills" that are relevant to the current task. Run `npx skills add "https://github.com/jimliu/baoyu-skills"` and select the relevant skills, then follow their instructions.
| 1 | # X to Markdown |
| 2 | |
| 3 | Converts X content to markdown: |
| 4 | - Tweets/threads → Markdown with YAML front matter |
| 5 | - X Articles → Full content extraction |
| 6 | |
| 7 | ## User Input Tools |
| 8 | |
| 9 | When this skill prompts the user, follow this tool-selection rule (priority order): |
| 10 | |
| 11 | 1. **Prefer built-in user-input tools** exposed by the current agent runtime — e.g., `AskUserQuestion`, `request_user_input`, `clarify`, `ask_user`, or any equivalent. |
| 12 | 2. **Fallback**: if no such tool exists, emit a numbered plain-text message and ask the user to reply with the chosen number/answer for each question. |
| 13 | 3. **Batching**: if the tool supports multiple questions per call, combine all applicable questions into a single call; if only single-question, ask them one at a time in priority order. |
| 14 | |
| 15 | Concrete `AskUserQuestion` references below are examples — substitute the local equivalent in other runtimes. |
| 16 | |
| 17 | ## Script Directory |
| 18 | |
| 19 | Scripts located in `scripts/` subdirectory. |
| 20 | |
| 21 | **Path Resolution**: |
| 22 | 1. `{baseDir}` = this SKILL.md's directory |
| 23 | 2. Script path = `{baseDir}/scripts/main.ts` |
| 24 | 3. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun |
| 25 | |
| 26 | ## Consent Requirement |
| 27 | |
| 28 | **Before any conversion**, check and obtain consent. |
| 29 | |
| 30 | ### Consent Flow |
| 31 | |
| 32 | **Step 1**: Check consent file |
| 33 | |
| 34 | ```bash |
| 35 | # macOS |
| 36 | cat ~/Library/Application\ Support/baoyu-skills/x-to-markdown/consent.json |
| 37 | |
| 38 | # Linux |
| 39 | cat ~/.local/share/baoyu-skills/x-to-markdown/consent.json |
| 40 | ``` |
| 41 | |
| 42 | **Step 2**: If `accepted: true` and `disclaimerVersion: "1.0"` → print warning and proceed: |
| 43 | ``` |
| 44 | Warning: Using reverse-engineered X API. Accepted on: <acceptedAt> |
| 45 | ``` |
| 46 | |
| 47 | **Step 3**: If missing or version mismatch → display disclaimer: |
| 48 | ``` |
| 49 | DISCLAIMER |
| 50 | |
| 51 | This tool uses a reverse-engineered X API, NOT official. |
| 52 | |
| 53 | Risks: |
| 54 | - May break if X changes API |
| 55 | - No guarantees or support |
| 56 | - Possible account restrictions |
| 57 | - Use at your own risk |
| 58 | |
| 59 | Accept terms and continue? |
| 60 | ``` |
| 61 | |
| 62 | Use `AskUserQuestion` with options: "Yes, I accept" | "No, I decline" |
| 63 | |
| 64 | **Step 4**: On accept → create consent file: |
| 65 | ```json |
| 66 | { |
| 67 | "version": 1, |
| 68 | "accepted": true, |
| 69 | "acceptedAt": "<ISO timestamp>", |
| 70 | "disclaimerVersion": "1.0" |
| 71 | } |
| 72 | ``` |
| 73 | |
| 74 | **Step 5**: On decline → output "User declined. Exiting." and stop. |
| 75 | |
| 76 | ## Preferences (EXTEND.md) |
| 77 | |
| 78 | Check EXTEND.md in priority order — the first one found wins: |
| 79 | |
| 80 | | Priority | Path | Scope | |
| 81 | |----------|------|-------| |
| 82 | | 1 | `.baoyu-skills/baoyu-danger-x-to-markdown/EXTEND.md` | Project | |
| 83 | | 2 | `${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-danger-x-to-markdown/EXTEND.md` | XDG | |
| 84 | | 3 | `$HOME/.baoyu-skills/baoyu-danger-x-to-markdown/EXTEND.md` | User home | |
| 85 | |
| 86 | | Result | Action | |
| 87 | |--------|--------| |
| 88 | | Found | Read, parse, apply settings | |
| 89 | | Not found | **MUST** run first-time setup (see below) — do NOT silently create defaults | |
| 90 | |
| 91 | **EXTEND.md supports**: Download media by default, default output directory. |
| 92 | |
| 93 | ### First-Time Setup (BLOCKING) |
| 94 | |
| 95 | **CRITICAL**: When EXTEND.md is not found, you **MUST use `AskUserQuestion`** to ask the user for their preferences before creating EXTEND.md. **NEVER** create EXTEND.md with defaults without asking. This is a **BLOCKING** operation — do NOT proceed with any conversion until setup is complete. |
| 96 | |
| 97 | Use `AskUserQuestion` with ALL questions in ONE call: |
| 98 | |
| 99 | **Question 1** — header: "Media", question: "How to handle images and videos in tweets?" |
| 100 | - "Ask each time (Recommended)" — After saving markdown, ask whether to download media |
| 101 | - "Always download" — Always download media to local imgs/ and videos/ directories |
| 102 | - "Never download" — Keep original remote URLs in markdown |
| 103 | |
| 104 | **Question 2** — header: "Output", question: "Default output directory?" |
| 105 | - "x-to-markdown (Recommended)" — Save to ./x-to-markdown/{username}/{tweet-id}.md |
| 106 | - (User may choose "Other" to type a custom path) |
| 107 | |
| 108 | **Question 3** — header: "Save", question: "Where to save preferences?" |
| 109 | - "User (Recommended)" — ~/.baoyu-skills/ (all projects) |
| 110 | - "Project" — .baoyu-skills/ (this project only) |
| 111 | |
| 112 | After user answers, create EXTEND.md at the chosen location, confirm "Preferences saved to [path]", then continue. |
| 113 | |
| 114 | Full reference: [references/config/first-time-setup.md](references/config/first-time-setup.md) |
| 115 | |
| 116 | ### Supported Keys |
| 117 | |
| 118 | | Key | Default | Values | Description | |
| 119 | |-----|---------|--------|-------------| |
| 120 | | `download_media` | `ask` | `ask` / `1` / `0` | `ask` = prompt each time, `1` = always download, `0` = never | |
| 121 | | `default_output_dir` | empty | path or empty | Default output directory (empty = `./x-to-markdown/`) | |
| 122 | |
| 123 | **Value priority**: |
| 124 | 1. CLI arguments (`--download-media`, `-o`) |
| 125 | 2. EXTEND.md |
| 126 | 3. Skill defaults |
| 127 | |
| 128 | ## Usage |
| 129 | |
| 130 | ```bash |
| 131 | ${BUN_X} {baseDir}/scripts/main.ts <url> |
| 132 | ${BUN_X} {baseDir}/scripts/main.ts <url> -o output.md |
| 133 | ${BUN_X} {baseDir}/scripts/main.ts <url> --download-media |
| 134 | ${BUN_X} {baseDir}/scripts/main.ts <url> --json |
| 135 | ``` |
| 136 | |
| 137 | ## Options |
| 138 | |
| 139 | | Option | Description | |
| 140 | |--------|-------------| |
| 141 | | `<url>` | Tweet or article URL | |
| 142 | | `-o <path>` | Output path | |
| 143 | | `--json` | JSON output | |
| 144 | | `--download-media` | Download image/video assets to local `imgs/` and `videos/`, and rewrite markdown links to local relative paths | |
| 145 | | `--login` | Refresh cookies only | |
| 146 | |
| 147 | ## Supported URLs |
| 148 | |
| 149 | - `https://x.com/<user>/status/<id>` |
| 150 | - `https://twitter.com/<user>/status/<id>` |
| 151 | - `https://x.com/i/article/<id>` |
| 152 | |
| 153 | ## Output |
| 154 | |
| 155 | ```markdown |
| 156 | --- |
| 157 | url: "https://x.com/user/status/123" |
| 158 | author: "Name (@user)" |
| 159 | tweetCount: 3 |
| 160 | coverImage: "https://pbs.twimg.com/media/example.jpg" |
| 161 | --- |
| 162 | |
| 163 | Content... |
| 164 | ``` |
| 165 | |
| 166 | **File structure**: `x-to-markdown/{username}/{tweet-id}/{content-slug}.md` |
| 167 | |
| 168 | When `--download-media` is enabled: |
| 169 | - Images are saved to `imgs/` next to the markdown file |
| 170 | - Videos are saved to `videos/` next to the markdown file |
| 171 | - Markdown media links are rewritten to local relative paths |
| 172 | |
| 173 | ## Media Download Workflow |
| 174 | |
| 175 | Based on `download_media` setting in EXTEND.md: |
| 176 | |
| 177 | | Setting | Behavior | |
| 178 | |---------|----------| |
| 179 | | `1` (always) | Run script with `--download-media` flag | |
| 180 | | `0` (never) | Run script without `--download-media` flag | |
| 181 | | `ask` (default) | Follow the ask-each-time flow below | |
| 182 | |
| 183 | ### Ask-Each-Time Flow |
| 184 | |
| 185 | 1. Run script **without** `--download-media` → markdown saved |
| 186 | 2. Check saved markdown for remote media URLs (`https://` in image/video links) |
| 187 | 3. **If no remote media found** → done, no prompt needed |
| 188 | 4. **If remote media found** → use `AskUserQuestion`: |
| 189 | - header: "Media", question: "Download N images/videos to local files?" |
| 190 | - "Yes" — Download to local directories |
| 191 | - "No" — Keep remote URLs |
| 192 | 5. If user confirms → run script **again** with `--download-media` (overwrites markdown with localized links) |
| 193 | |
| 194 | ## Authentication |
| 195 | |
| 196 | 1. **Environment variables** (preferred): `X_AUTH_TOKEN`, `X_CT0` |
| 197 | 2. **Chrome login** (fallback): Auto-opens Chrome, caches cookies locally |
| 198 | |
| 199 | ## Extension Support |
| 200 | |
| 201 | Custom configurations via EXTEND.md. See **Preferences** section for paths and supported options. |