leek.io leek.io
contact
#ai #tooling #claude-code #tutorial

Turning a Creator's X Tips Into Agent Rules Claude Actually Reads

CJ
Chris Jones · @leek
Jul 1, 2026 · 8 min read · 1,523 words
Turning a Creator's X Tips Into Agent Rules Claude Actually Reads

I’ve followed Povilas Korop (Laravel Daily) for years. His Laravel, Eloquent, and Filament tips are some of the best on X: small, sharp, immediately useful. And they scroll by in my feed and vanish, forever, because that’s what timelines do.

This week I decided to stop losing them. Not by bookmarking harder, but by turning them into something my AI coding agents load automatically: rules. Two stages. First, harvest a creator’s tips out of X. Then distill the durable ones into versioned agent-rules repos that Claude Code and Codex load in the folders where they apply.

Here’s the whole thing, including the parts that didn’t work.

A bookmark is something you read once. A rule is something your agent enforces every time it touches the relevant file. Those are very different things.

The two halves

The job splits in two:

  1. Harvest: pull every “tip” tweet from one account, including the ones where the code lives inside a screenshot, into one searchable index.
  2. Distill: decide which tips are durable, enforceable practices, and fold those into per-directory rule files my agents already load.

The first half is an X scraping problem. The second is an editorial one: decide what counts as a rule, then ship it as something versioned.

Part 1: Harvesting the tips with xurl

I drive the X API with xurl, a curl-like CLI that handles OAuth for you. My instinct was the obvious one: search for the tips.

xurl search "tip (from:PovilasKorop)" -n 20 --auth oauth1

That 401’d. So did the raw recent-search endpoint:

xurl --auth oauth1 "/2/tweets/search/recent?query=tip%20(from:PovilasKorop)&max_results=10"
# {"title":"Unauthorized","status":401,"detail":"Unauthorized"}

Recent-search isn’t enabled on my access tier, and full-archive search (/2/tweets/search/all) needs Pro. Then a different wall. The metered endpoints started returning 402:

{"detail":"credits depleted","status":402,"title":"Payment Required",
 "type":"https://api.x.com/2/problems/credits-depleted"}

But /2/users/me kept working. The whoami endpoint isn’t metered, so I knew auth was fine; everything useful was just paywalled. I topped up credits and gave up on search.

The endpoint that actually works: the user timeline

You don’t need search to read one person’s posts. The user-timeline endpoint does it, paginated:

xurl --auth oauth1 "/2/users/993118867/tweets?max_results=100\
&tweet.fields=created_at,public_metrics,attachments,entities\
&expansions=attachments.media_keys\
&media.fields=url,preview_image_url,type,alt_text\
&exclude=retweets,replies"

993118867 is Povilas’s numeric user ID. Each response carries a meta.next_token; append it as &pagination_token=$token and loop until you hit your cutoff date.

One gotcha cost me a while. I tried to bound the query server-side with start_time, but the ISO timestamp contains colons, and those colons break xurl’s OAuth 1.0a signature. Every request with start_time came back 401. The fix is boring: drop start_time, paginate, and filter by created_at locally.

When a query parameter mysteriously 401s under OAuth 1.0a, suspect the signature base string before you suspect your credentials. Special characters in a param value are a classic culprit.

The 3,200 reality check

I’d asked to go back six months. I got about three and a half: 696 original tweets, stopping around March 19th after seven pages. That’s not a bug, it’s the API. The user-timeline endpoint only exposes a user’s ~3,200 most recent posts, and Povilas posts and replies often enough that 3,200 of them only reaches back a few months. The full six months would have needed that Pro-tier full-archive search, the one that 401’d. Good enough. 696 tweets is a lot of tips.

Part 2: The code is in the images

This is where it stops being a jq script: most of the best tips are screenshots of code. The tweet text says “You can do X” and the actual ->whereRelation(...) lives in a syntax-highlighted PNG.

I didn’t reach for Tesseract. The images came down free from the CDN (pbs.twimg.com isn’t metered; request name=large), and I let Claude read them directly with vision. 96 code images, downloaded from a generated TSV:

# dl.tsv: <url>\t<local-path> per line
while IFS=$'\t' read -r url path; do curl -s -L -o "$path" "$url"; done < dl.tsv

Transcribing 96 images serially would have been slow and context-heavy, so I fanned it out: seven parallel subagents, each handed one batch of images with the same brief:

“You are transcribing Laravel/PHP tips from X into a markdown file. This is OCR + light formatting work — accuracy of the transcribed code is the top priority.”

Each subagent read its batch and wrote a part file; the main agent concatenated them. Out came a single ~91 KB PovilasKorop-Laravel-Tips-Index.md: a linked table of contents plus one section per tip (date, category, link, prose, and a real code fence transcribed from the screenshot). 83 tips, sorted into Laravel (69), Filament (13), Eloquent (9), PHP (6), Testing (4), and Livewire (3). I dropped eight “tip” tweets that were about careers or AI or marketing rather than code.

Vision models are a general-purpose OCR you already have. On screenshots of code, where a dumb OCR mangles indentation and symbols, a model that understands the code transcribes it far more faithfully. Parallelize the reads and it’s fast, too.

Part 3: From tips to rules

An 83-tip index is a great bookmark file. It isn’t yet guidance my agents use. For that, the tips have to become rules, and they have to live where the agent will actually load them.

I already keep my AI rules in two distribution repos, laravel-agent-rules and filament-agent-rules, installed into projects with apply-agent-rules. The canonical rules are per-directory CLAUDE.md files that mirror a Laravel app tree:

app/Models/CLAUDE.md
app/Observers/CLAUDE.md
app/Http/Requests/CLAUDE.md
app/Http/Resources/CLAUDE.md
routes/CLAUDE.md
tests/CLAUDE.md
app/Filament/Resources/Tables/CLAUDE.md
app/Filament/Widgets/CLAUDE.md
...

Put a rule about query safety in app/Models/CLAUDE.md and an agent editing a model loads it. No root-file bloat, no rule firing on the wrong file.

The filter that matters: not every tip is a rule

I pointed the agent at the index with one instruction:

“If any of the tips would make a good rule / belongs in our rules repo for best practices, let’s add it.”

That “if” does all the work. A tip is only a rule if it’s durable and enforceable: a “must / prefer / avoid” you’d want applied every time. So a lot got skipped: package promos, news, one-off installer flags, narrow helper snippets, and anything already covered. What made the cut folded into the nearest existing section:

  • Laravel: route parameter constraints, query-safety around soft deletes and query-builder writes that bypass observers, observer side-effect discipline, tenant-scoped validation rules, API JSON exception rendering, 204 responses, factory state naming, and LazilyRefreshDatabase in tests.
  • Filament: cached navigation badges, custom filter indicators, form-bearing bulk actions, schemas built dynamically from config, wizard step persistence, and disabling default widget polling.

Each addition was written as guidance (“prefer… / avoid…”), not a quoted tweet. The tip is the seed; the rule is the generalized practice.

Ship it like software: tag a release

Because these repos are consumed by version, distilling tips ends with a release, not just a commit. Two focused commits, then an annotated tag in each repo:

git add app/Models/CLAUDE.md routes/CLAUDE.md tests/CLAUDE.md ...
git commit -m "feat: add Laravel Daily rule guidance"

git tag -a v0.13.0 -m "v0.13.0"
git push origin main v0.13.0

Now any project can pull the new guidance deliberately:

apply-agent-rules apply leek/laravel-agent-rules --agents claude,codex

The same source rule ships to Claude (CLAUDE.md + symlinked .claude/rules/*.md), Codex (AGENTS.md), and Cursor (.cursor/rules/*.mdc). One edit, every agent convention, versioned by git tag.

Why go to all this trouble

I could have kept bookmarking tweets. But a bookmark asks me to remember, at the exact moment I’m writing a query, that six weeks ago someone showed a better way. That never happens. Baking the durable ones into app/Models/CLAUDE.md means the reminder shows up on its own, in the file where it applies.

None of this is specific to Povilas. Harvest with the boring endpoint (timeline, not search) and filter locally. Transcribe the screenshots with a vision model instead of fighting classical OCR. Distill ruthlessly, because most content is a bookmark and only durable, enforceable practices become rules. Then ship the survivors as a versioned release so every project pulls them on purpose.

Povilas spent years turning what he’s learned into 280-character tips. The least I could do was give the best of them a home where they get used instead of scrolled past.

Full credit to Povilas Korop / Laravel Daily: this is his knowledge, I just changed its shape. Everything here used public tweets for a personal reference.

CJ
Reply by email
I read everything.
$ reply