# Scroll X

> Extract posts from X.com feed via Libretto workflow, then analyze for comment-worthy and generally interesting content

- Skill: `tanishqkancharla/scroll-x` (Agent Skill)
- Install (CLI): `npx skillmds@latest add tanishqkancharla/scroll-x`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tanishqkancharla/scroll-x/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: tanishqkancharla (https://skillmd.com/u/tanishqkancharla)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tanishqkancharla/scroll-x

---


# Scroll X Feed Extraction

Runs the Libretto workflow to extract posts from X.com, then analyzes the results for:
1. **Posts worth commenting on given your expertise**
2. **Posts that are generally interesting to you**

Always present **comment-worthy posts first**.

## Usage

```
[skill:scroll-x] [target posts]
```

**Default target:** 50 posts

## Step 1: Run the Libretto Workflow

Run the extraction workflow headlessly with the saved auth profile:

```bash
libretto run ./workflows/scroll-x.ts --headless --auth-profile x.com --params '{"targetPosts": 50}'
```

If the user specified a custom target count, pass it instead:

```bash
libretto run ./workflows/scroll-x.ts --headless --auth-profile x.com --params '{"targetPosts": 80}'
```

**If the workflow fails with an auth error**, the profile may have expired. Re-login:

```bash
libretto open https://x.com --session login-x
# Log in manually...
libretto save x.com --session login-x
libretto close --session login-x
```

Then re-run the workflow.

## Step 2: Analyze the Output

After the workflow completes, read the output file and present a two-part analysis.

### Load Summary History

Read `x_summary_history.json` from the project root — if it doesn't exist, start with an empty array. Filter out any posts whose IDs appear in the history.

If there are no new posts, tell the user: **"No new X posts since last summary."**

### User profile for filtering

Read `profile.md` from the project root to understand what topics the user cares about, what they're trying to grow, and what their engagement style is. Use this to judge which posts are comment-worthy vs. interesting vs. skippable.

### Link rules (critical)

- **Never reconstruct or guess X URLs.**
- Always use the exact `link` field from the extracted JSON as the **post link**.
- If `externalLinks` is non-empty, include them as **supplementary links**.
- If an external link is a t.co link, still include it — do not invent a resolved URL.

### What belongs in **Good posts to comment on**

Include posts where the user has a real angle worth adding.

Be selective. Quality over quantity. **0-6 posts** is normal.

For each such post, explain:
- why it is a strong commenting opportunity
- what angle would be natural/helpful to take

Do **not** draft the full comment unless explicitly asked.

### What belongs in **Interesting generally**

Include posts that align with the user's broader interests even if they are not obvious commenting opportunities.

### What to Skip

- low-signal memes, shitposts, vague jokes
- generic hype discourse without substance
- engagement bait
- vague teasers with no concrete product/technical substance
- commentary where the user would have no distinctive perspective

## Formatting

Always present **comment-worthy posts first**.

### Section 1: Good posts to comment on

Use this exact format:

```md
## Good posts to comment on

**<Short title>** — <Why this is relevant to comment on>
> *"<Relevant snippet from the post>"* — **<Author>**
> **Why comment:** <1 sentence>
> **Angle:** <1 sentence describing the helpful angle to take>
> **Post:** [link](<exact link field from JSON>)
> **Supplementary:** [link 1](<url>), [link 2](<url>)
```

If there are no supplementary links, omit the Supplementary line.

If there are none, say:

```md
## Good posts to comment on

No especially strong X commenting opportunities this run.
```

### Section 2: Interesting generally

Use this exact format:

```md
## Interesting generally

**<Short title>** — <Why this is interesting>
> *"<Relevant snippet from the post>"* — **<Author>**
> **Post:** [link](<exact link field from JSON>)
> **Supplementary:** [link 1](<url>), [link 2](<url>)
```

If there are no supplementary links, omit the Supplementary line.

## Persist Summary History

After generating the summary, save the IDs of all newly surfaced posts back to `x_summary_history.json` so they are not shown again next run.

## Post Structure

Each post in the output file:

```json
{
  "id": "2016927763652055300",
  "author": "Display Name",
  "handle": "username",
  "text": "Post content (truncated to 1000 chars)",
  "link": "https://x.com/username/status/2016927763652055300",
  "time": "2026-01-29T17:33:46.000Z",
  "externalLinks": ["https://example.com/blog-post"]
}
```

## Troubleshooting

- **Auth expired** - Re-login and save profile: `libretto open https://x.com --session login && libretto save x.com --session login`
- **Fewer than target posts** - X may throttle or recycle content. Getting close to target is the goal, not a strict guarantee.
- **Want to reset history?** - Delete `x_summary_history.json` to start fresh

