← back to Axel Bitblaze Scout
initial scaffold: axel-bitblaze-scout skill (X scout for @Axel_bitblaze69 AI/Claude posts)
7e82c819e9ec218bd4924c3cfc85846a43678f4f · 2026-07-22 21:57:36 -0700 · Steve Abrams
Files touched
A .gitignoreA README.mdA SKILL.mdA references/evaluation-rubric.mdA references/sources.mdA scripts/gh-repo-stats.jsA scripts/hydrate-tweet.js
Diff
commit 7e82c819e9ec218bd4924c3cfc85846a43678f4f
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Jul 22 21:57:36 2026 -0700
initial scaffold: axel-bitblaze-scout skill (X scout for @Axel_bitblaze69 AI/Claude posts)
---
.gitignore | 8 +++
README.md | 20 ++++++
SKILL.md | 133 ++++++++++++++++++++++++++++++++++++++++
references/evaluation-rubric.md | 78 +++++++++++++++++++++++
references/sources.md | 72 ++++++++++++++++++++++
scripts/gh-repo-stats.js | 123 +++++++++++++++++++++++++++++++++++++
scripts/hydrate-tweet.js | 132 +++++++++++++++++++++++++++++++++++++++
7 files changed, 566 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1924158
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+node_modules/
+.env*
+tmp/
+*.log
+.DS_Store
+dist/
+build/
+.next/
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a0f1128
--- /dev/null
+++ b/README.md
@@ -0,0 +1,20 @@
+# axel-bitblaze-scout
+
+Claude Code skill that scouts Axel Bitblaze 🪓 (@Axel_bitblaze69) on X for
+Claude Code / AI-agent / local-AI tool posts, filters the account's heavy
+crypto/airdrop noise, verifies every claim against the real repo, dedupes
+against the existing skill/agent stack, and drafts gated adopt/watch/skip
+memos. Never a hype relay, never an auto-install.
+
+Live at `~/.claude/skills/axel-bitblaze-scout` (symlink into this repo).
+
+- Entry point: `SKILL.md`
+- Retrieval map + hype calibration: `references/sources.md`
+- Scoring + gating: `references/evaluation-rubric.md`
+- `scripts/hydrate-tweet.js` — X post → text/links, $0, no auth
+- `scripts/gh-repo-stats.js` — repo → stars/license/freshness (claim verification)
+
+Sibling skills: `gurisingh-scout`, `tiktok-architect`.
+
+Seeded from: https://x.com/axel_bitblaze69/status/2078551452201754980
+(the `video-use` post), 2026-07-22.
diff --git a/SKILL.md b/SKILL.md
new file mode 100644
index 0000000..ab4de4c
--- /dev/null
+++ b/SKILL.md
@@ -0,0 +1,133 @@
+---
+name: axel-bitblaze-scout
+description: Scout the Claude Code / AI-agent / local-AI tool and workflow posts that Axel Bitblaze 🪓 (@Axel_bitblaze69) publishes on X, filter out the account's heavy crypto/airdrop noise, VERIFY every claim (star counts, "free", capabilities) against the real repo, dedupe against Steve's existing stack, score fit/leverage/trust with a hype discount, and draft gated adopt/codify memos. Use when Steve says "axel bitblaze", "/axel-bitblaze-scout", "what is axel posting", "scout axel's feed", drops an x.com/axel_bitblaze69 link and asks what it is and whether to adopt it, or wants Axel's AI tool picks evaluated. Retrieval survives the X auth wall via mirror fan-out (unrollnow, rattibha, vanlett, vibepicked, syndication endpoint).
+---
+
+# Axel Bitblaze Scout
+
+## Overview
+
+Axel Bitblaze (@Axel_bitblaze69, ~128K followers, ~11 posts/day since 2015) is
+a high-volume X account that historically posted crypto/airdrop alpha and now
+posts a steady stream of **Claude Code workflows, MCP tools, local-AI stacks,
+and agent side-hustles** — e.g. the Claude Code + NotebookLM + Obsidian
+research pipeline, the `video-use` transcript-first video editor, Higgsfield
+MCP real-estate packages, Mac-hardware-for-AI guides.
+
+The signal is real but the delivery is engagement-farmed: round-number star
+counts, "X matches a 685B model", "$8–15k more a year" — every number is a
+CLAIM until verified. This skill harvests the AI posts, drops the crypto,
+verifies the claims against the actual repos, and turns survivors into
+**adopt / watch / skip** decisions for Steve's stack. Never a hype relay,
+never an auto-install.
+
+Sibling skills: `gurisingh-scout` (tool-drop educator), `tiktok-architect`
+(rules/tips educator). Same gates, same rubric family — this one adds the
+noise filter and hype discount that Axel's feed specifically needs.
+
+## When to use
+
+- Periodic sweep: "what has Axel posted lately that's worth adopting?"
+- One-off: Steve drops an `x.com/axel_bitblaze69/status/<id>` link.
+- Cross-check: another scout or the idea-loop surfaces a tool that Axel also
+ covered — pull his write-up as one more (low-trust) source.
+
+## Workflow
+
+### 1. Retrieve (fan out — X is auth-walled)
+
+Direct X reads fail unauthenticated. Follow `references/sources.md` for the
+full mirror map. The proven order:
+
+```bash
+node scripts/hydrate-tweet.js <tweet-id-or-url> # $0, syndication endpoint; exit 3 = tombstone
+```
+
+- Per-thread mirror: `https://www.unrollnow.com/status/<tweet-id>` (best —
+ serves full thread text, verified working 2026-07).
+- Profile archives: `en.rattibha.com/Axel_bitblaze69`,
+ `vanlett.com/Axel_bitblaze69` (includes reposts), and
+ `vibepicked.com/builder/@Axel_bitblaze69/` (his own built projects).
+- Discovery of NEW posts: Exa search (`mcp__exa__web_search_exa`) scoped to
+ the handle — metered, show the cost.
+- `threadreaderapp.com` is login-walled as of 2026-07 — deprioritize.
+
+### 2. Classify — the noise filter (Axel-specific, do this FIRST)
+
+Bucket every post before spending any verification effort:
+
+| Bucket | Examples | Action |
+|---|---|---|
+| `ai-claude` | Claude Code skills/workflows, MCP servers, subagent patterns | Proceed |
+| `ai-general` | Ollama/local models, ChatGPT agent mode, AI hardware guides | Proceed |
+| `hustle-promo` | "make $X with this AI side hustle" framing around a real tool | Proceed, but strip the income claims — evaluate only the tool |
+| `crypto` | airdrops, trading bots, token threads, Telegram-channel funnels | SKIP silently — never surfaces in output |
+
+Reposts: credit the ORIGINAL author, and note whether that account merits its
+own scout entry in `references/sources.md`.
+
+### 3. Extract + verify (claims are claims)
+
+For each surviving post capture: tool name, repo URL (resolve `t.co`), what
+it claims to do, and the specific verifiable claims (stars, license, "free",
+capabilities). Then verify:
+
+```bash
+node scripts/gh-repo-stats.js <github-url-or-owner/repo> # $0; GITHUB_TOKEN raises rate limit
+```
+
+Compare claimed vs. actual stars/license/freshness. A claim that misses by
+>2x (e.g. "17,000 stars" on a 900-star repo) is itself a trust signal —
+record the delta in the output.
+
+### 4. Dedupe against Steve's existing kit
+
+```bash
+ls ~/.claude/skills/ | grep -i "<keyword>"
+grep -ril "<capability>" ~/.claude/skills/*/SKILL.md 2>/dev/null
+```
+
+Steve has 400+ skills and a full agent cabinet. Video editing → `hyperframes`
+family; research pipelines → `last30`, `deep-research`, `web-extract`,
+`knowledge-layer`; local models → Ollama fleet + `prism`. If an equivalent
+exists, the useful output is a **diff**, not a redundant recommend.
+
+### 5. Score & decide
+
+Apply `references/evaluation-rubric.md` — the six-dimension family rubric
+(stack fit, novelty, leverage, install cost, trust/license, safety) with two
+Axel modifiers: **Trust caps at 2/3 unless independently verified** (the
+account's crypto-shill history and hype style earn a standing discount), and
+**income/performance claims score 0 weight** (evaluate the tool, not the
+pitch). Verdict bands: **≥14 ADOPT · 9–13 WATCH · ≤8 SKIP.**
+
+### 6. Deliver — shortlist + gated memos
+
+Ranked table: `Tool | Repo (claimed vs actual stars, license, last-push) |
+What it does | Bucket | Dedupe | Score | Verdict | 1-line reason`. For each
+**ADOPT**, draft a memo to `~/.claude/yolo-queue/pending-approval/` with what
+it is, why it fits, exact install steps, **cost** (always show — scripts are
+`$0 local`, Exa discovery is metered), risks, and an APPROVE/REVISE/BLOCK line.
+
+## Hard rules
+
+- **Never auto-install.** Cloning, `/plugin install`, `npx` on unfamiliar
+ code, pasting into `~/.claude`, new paid keys — all gated to
+ pending-approval. The deliverable is a decision-ready shortlist.
+- **Crypto bucket never surfaces.** No airdrop/trading content in output,
+ even as "interesting" — it's outside every mandate Steve has.
+- **Every number is a claim until `gh-repo-stats.js` confirms it.** Report
+ claimed-vs-actual deltas; never relay Axel's figures as fact.
+- **A mirror failure ≠ "nothing new"** — fan out before concluding quiet.
+- **Show costs** every run; **log real wins only** (an adopted pick, not a scan).
+
+## Resources
+
+- `scripts/hydrate-tweet.js` — one X post → verbatim text + links, no auth,
+ `$0` (local syndication token). Exit 3 on tombstone.
+- `scripts/gh-repo-stats.js` — repo → stars/license/freshness/Claude-skill
+ detection; the claim-verification backbone.
+- `references/sources.md` — handle profile, mirror map with verified status,
+ noise profile, repost-source ledger, seed-post record.
+- `references/evaluation-rubric.md` — the six dimensions, Axel trust
+ modifiers, dedupe procedure, gating, output shape.
diff --git a/references/evaluation-rubric.md b/references/evaluation-rubric.md
new file mode 100644
index 0000000..fc0def8
--- /dev/null
+++ b/references/evaluation-rubric.md
@@ -0,0 +1,78 @@
+# Evaluation rubric — should Steve actually adopt this?
+
+Same six-dimension family rubric as `gurisingh-scout`, with Axel-specific
+modifiers layered on. Score each candidate 0–3 per dimension, 18 max.
+
+## Dimensions
+
+1. **Stack fit (0–3)** — does it serve something Steve actually runs? High:
+ Claude Code skills/subagents/hooks, MCP servers, catalog/scraper/pricing
+ tooling, cost/observability, marketing/social automation, DW commerce,
+ directory builders, video pipelines. Low: generic boilerplate, crypto,
+ anything with no path into his workflow.
+2. **Novelty vs. existing kit (0–3)** — 3 = fills a real gap; 0 = an
+ equal-or-better skill/agent already exists. Run the dedupe check first.
+3. **Leverage (0–3)** — measurable hours back or revenue unlocked, not
+ "feels productive". Axel's income projections do NOT count as evidence.
+4. **Install/run cost (0–3, higher = cheaper)** — 3 = one paste, local, no
+ new paid API; 0 = heavy infra, new metered API, or a rewrite. Estimate
+ from the repo README, never from the tweet's "2 minutes" framing.
+5. **Trust & license (0–3)** — stars/traction (ACTUAL, from
+ `gh-repo-stats.js`), license present, recently maintained, no security
+ smell. Unlicensed + unmaintained caps at 1.
+6. **Safety/gating exposure (0–3, higher = safer)** — 3 = read-only/local,
+ no secrets; 0 = wants prod creds, sends outbound, or auto-executes. Low
+ scores route to pending-approval, they don't auto-kill.
+
+**Verdict bands:** ≥14 → **ADOPT** (draft the install memo). 9–13 → **WATCH**
+(log, revisit on traction). ≤8 → **SKIP** (one-line why).
+
+## Axel modifiers (applied after base scoring)
+
+- **Trust discount:** dimension 5 caps at **2/3** when the only evidence is
+ Axel's own post. The cap lifts only when an independent source (repo
+ metrics, a second educator, hands-on test) confirms the core claim. Reason:
+ the account's engagement-farming style and crypto-shill history mean its
+ claims systematically overshoot.
+- **Claim-delta flag:** if a verifiable claim (stars, "free", capability)
+ misses reality by >2x, note it in the output row AND subtract 1 from
+ dimension 5. Repeated deltas across sweeps should be recorded in
+ `references/sources.md` under Hype calibration.
+- **Income claims are weightless:** "$X/year side hustle" framing
+ contributes nothing to Leverage. Score leverage from what the tool does
+ for Steve's actual businesses.
+
+## Dedupe procedure (before scoring novelty)
+
+```bash
+ls ~/.claude/skills/ | grep -i "<keyword>"
+grep -ril "<capability keyword>" ~/.claude/skills/*/SKILL.md 2>/dev/null
+```
+
+Also sanity-check the agent cabinet (`~/Projects/agent-cabinet/cabinet.yaml`)
+and CNCP. Known equivalents: video creation → `hyperframes` family; research
+→ `last30`, `deep-research`, `web-extract`, `knowledge-layer`; cost →
+`cost-tracker`; model evaluation → `ollama-model-eval`; browser automation →
+`dev-browser`, `browserbase`, `crawl4ai`. If an equivalent exists, output the
+**diff** ("video-use edits raw footage off a transcript; hyperframes composes
+from scratch — no overlap on ingest"), not a redundant recommend.
+
+## Gating — what the scout may and may NOT do
+
+Discovery, retrieval, enrichment, scoring, and the shortlist run freely
+(reversible, read-only). Everything that changes Steve's machine or spends is
+gated — draft to `~/.claude/yolo-queue/pending-approval/` with an
+APPROVE/REVISE/BLOCK block; never auto-run:
+
+- Installing a skill/plugin (`git clone`, `/plugin install`, paste into `~/.claude`).
+- `npx`/running unfamiliar code that executes or reads `~/.claude`.
+- Anything needing a new paid API key or that spends.
+- Anything the tool itself does that is customer-facing/destructive/outbound.
+
+## Output shape (per run)
+
+Ranked table: `Tool | Repo (claimed vs actual stars, license, last-push) |
+What it does | Bucket | Dedupe (have/gap) | Score | Verdict | 1-line reason`.
+Then per ADOPT: a pending-approval memo — what it is, why it fits, exact
+install steps, cost, risks, APPROVE/REVISE/BLOCK. Log genuine wins (an
+adopted pick), never the scan itself.
diff --git a/references/sources.md b/references/sources.md
new file mode 100644
index 0000000..850f927
--- /dev/null
+++ b/references/sources.md
@@ -0,0 +1,72 @@
+# Sources — Axel Bitblaze retrieval map
+
+## The account
+
+| Field | Value |
+|---|---|
+| Handle | `@Axel_bitblaze69` |
+| Display | Axel Bitblaze 🪓 |
+| Bio | "Low iq idiot. I know nothing. Telegram: @Axelbitblaze" (self-deprecating shtick; the Telegram is a crypto-alpha funnel — ignore it) |
+| Followers | ~128K (2026-07) |
+| Volume | ~46.7K lifetime posts, ~11/day — a firehose; sweep by recency window, never "read everything" |
+| Joined | April 2015 |
+| History | 2015–2025: crypto/airdrop/trading alpha threads. 2026→: heavy pivot to Claude Code, MCP, local AI, agent side-hustles. Both streams still run concurrently. |
+
+## Mirror map (X itself is auth-walled — WebFetch/Exa on x.com fails)
+
+Ordered by usefulness; "verified" = actually returned content on 2026-07-22.
+
+1. **`scripts/hydrate-tweet.js <id-or-url>`** — $0, no auth, computes the
+ syndication token locally. First stop for any specific tweet ID. Exit 3 =
+ tombstone (deleted/suspended) → fall through to mirrors.
+2. **unrollnow** — `https://www.unrollnow.com/status/<tweet-id>` — VERIFIED.
+ Full thread text, works within minutes of posting. Best per-thread mirror.
+3. **rattibha** — `https://en.rattibha.com/Axel_bitblaze69` — VERIFIED.
+ Profile-level thread archive with engagement counts; good for sweeps.
+4. **vanlett** — `https://vanlett.com/Axel_bitblaze69` — VERIFIED. Profile
+ mirror that includes REPOSTS (rattibha mostly doesn't) — the only mirror
+ that shows what he amplifies vs. authors.
+5. **vibepicked** — `https://vibepicked.com/builder/@Axel_bitblaze69/` —
+ VERIFIED. Catalogs projects he built (with tools used, e.g. "Claude Code ·
+ NotebookLM · Obsidian · skill-creator · yt-dlp"). Highest-signal page per
+ byte: these are things he actually shipped, not just promoted.
+6. **Exa search** — `mcp__exa__web_search_exa` with the handle in the query —
+ METERED (~$0.005/search, show cost). Use for discovering new posts when
+ the profile mirrors lag.
+7. ~~threadreaderapp~~ — login-walled as of 2026-07. Skip unless others fail.
+
+## Noise profile (why the classifier exists)
+
+Rough historical mix: crypto/airdrop ≥ 60%, AI/Claude ~30%, misc ~10%. The
+crypto stream is monetized (Telegram funnel, "like & RT" engagement bait) and
+entirely out of scope. Never let a sweep's output mention it.
+
+## Hype calibration
+
+Observed claim patterns to always verify, never relay:
+- Round star counts ("17,000 stars on GitHub") — check `gh-repo-stats.js`.
+- Model-equivalence claims ("a 26B model matching 685B models") — discard;
+ benchmark claims from this account carry zero weight (see
+ `ollama-model-eval` for how Steve actually evaluates models).
+- Income projections ("$8–15k more a year") — strip; evaluate the tool only.
+- "Setup takes 2 minutes" — treat as marketing; estimate install cost from
+ the repo README, not the tweet.
+
+## Repost-source ledger
+
+Accounts Axel amplifies whose original content scored well — candidates for
+their own scout coverage. Append as found:
+
+- (none yet)
+
+## Seed post (the one that created this skill)
+
+- `https://x.com/axel_bitblaze69/status/2078551452201754980` (2026-07-23) —
+ promotes **video-use**: open-source Claude Code video-editing skill;
+ claims 17K GitHub stars, transcript-first editing (cuts filler words /
+ dead space), ffmpeg color-grade chains, editor sub-agents, plan-approval
+ before cutting. Repo link was in a trailing t.co not captured by the
+ mirror. **Claims unverified as of skill creation** — first sweep should
+ resolve the repo and run it through the rubric. Dedupe note: Steve's
+ `hyperframes` family owns video *creation*; transcript-driven *editing of
+ raw footage* is a plausible real gap.
diff --git a/scripts/gh-repo-stats.js b/scripts/gh-repo-stats.js
new file mode 100755
index 0000000..3ca5006
--- /dev/null
+++ b/scripts/gh-repo-stats.js
@@ -0,0 +1,123 @@
+#!/usr/bin/env node
+/**
+ * gh-repo-stats.js — turn a GitHub repo link into hard adoption signals.
+ *
+ * Guri Singh's posts almost always point at an open-source repo. Before scoring
+ * whether it's worth adopting, resolve the objective facts: popularity, license,
+ * how recently it was touched, primary language, archived/stale status, and —
+ * critically for us — whether it is literally a Claude Code skill/plugin
+ * (SKILL.md, .claude/, plugin manifest) versus a general CLI/tool.
+ *
+ * Usage:
+ * node gh-repo-stats.js <github-url-or-owner/repo>
+ *
+ * Auth: unauthenticated works (60 req/hr). Set GITHUB_TOKEN in env to raise the
+ * limit to 5000/hr — the script reads it automatically if present.
+ *
+ * Exit codes: 0 ok, 1 error (bad input / not found / network).
+ * Output: JSON summary on stdout.
+ */
+
+'use strict';
+
+function parseRepo(arg) {
+ if (!arg) return null;
+ const m = String(arg).match(/github\.com\/([A-Za-z0-9._-]+)\/([A-Za-z0-9._-]+)/);
+ if (m) return { owner: m[1], repo: m[2].replace(/\.git$/, '') };
+ const slug = String(arg).match(/^([A-Za-z0-9._-]+)\/([A-Za-z0-9._-]+)$/);
+ if (slug) return { owner: slug[1], repo: slug[2] };
+ return null;
+}
+
+function ghHeaders() {
+ const h = {
+ 'User-Agent': 'gurisingh-scout',
+ Accept: 'application/vnd.github+json',
+ };
+ const tok = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
+ if (tok) h.Authorization = `Bearer ${tok}`;
+ return h;
+}
+
+async function gh(url) {
+ const res = await fetch(url, { headers: ghHeaders() });
+ if (res.status === 404) return { __status: 404 };
+ if (res.status === 403) return { __status: 403, __rate: res.headers.get('x-ratelimit-remaining') };
+ if (!res.ok) throw new Error(`http ${res.status} ${url}`);
+ return res.json();
+}
+
+function daysSince(iso) {
+ if (!iso) return null;
+ return Math.round((Date.now() - new Date(iso).getTime()) / 86400000);
+}
+
+async function main() {
+ const parsed = parseRepo(process.argv[2]);
+ if (!parsed) {
+ console.error('usage: node gh-repo-stats.js <github-url-or-owner/repo>');
+ process.exit(1);
+ }
+ const { owner, repo } = parsed;
+
+ let meta;
+ try {
+ meta = await gh(`https://api.github.com/repos/${owner}/${repo}`);
+ } catch (e) {
+ console.error(`error: ${e.message}`);
+ process.exit(1);
+ }
+ if (meta.__status === 404) {
+ console.error(`not found: ${owner}/${repo}`);
+ process.exit(1);
+ }
+ if (meta.__status === 403) {
+ console.error(`rate-limited (remaining=${meta.__rate}). Set GITHUB_TOKEN to raise the limit.`);
+ process.exit(1);
+ }
+
+ // Root listing → detect "is this a Claude skill/plugin?" (one extra call).
+ let isClaudeSkill = false;
+ let claudeMarkers = [];
+ try {
+ const contents = await gh(`https://api.github.com/repos/${owner}/${repo}/contents`);
+ if (Array.isArray(contents)) {
+ const names = contents.map((c) => c.name.toLowerCase());
+ const markers = ['skill.md', '.claude', 'skills', 'plugin.json', '.claude-plugin', 'commands', 'agents'];
+ claudeMarkers = markers.filter((m) => names.includes(m));
+ isClaudeSkill = names.includes('skill.md') || names.includes('.claude') ||
+ names.includes('.claude-plugin') ||
+ (names.includes('skills') && (names.includes('plugin.json') || names.includes('.claude-plugin')));
+ }
+ } catch {
+ /* non-fatal — leave detection empty */
+ }
+
+ const daysStale = daysSince(meta.pushed_at);
+ const out = {
+ repo: `${owner}/${repo}`,
+ url: meta.html_url,
+ description: meta.description,
+ stars: meta.stargazers_count,
+ forks: meta.forks_count,
+ open_issues: meta.open_issues_count,
+ language: meta.language,
+ license: meta.license ? meta.license.spdx_id : 'NONE',
+ pushed_at: meta.pushed_at,
+ days_since_push: daysStale,
+ archived: meta.archived,
+ is_claude_skill: isClaudeSkill,
+ claude_markers: claudeMarkers,
+ // quick, opinionated flags to feed the adoption rubric
+ flags: {
+ unlicensed: !meta.license,
+ stale: daysStale != null && daysStale > 120,
+ archived: !!meta.archived,
+ low_traction: meta.stargazers_count < 50,
+ },
+ };
+ console.log(JSON.stringify(out, null, 2));
+ process.exit(0);
+}
+
+main();
diff --git a/scripts/hydrate-tweet.js b/scripts/hydrate-tweet.js
new file mode 100755
index 0000000..f119c95
--- /dev/null
+++ b/scripts/hydrate-tweet.js
@@ -0,0 +1,132 @@
+#!/usr/bin/env node
+/**
+ * hydrate-tweet.js — resolve a single X/Twitter post to plain text WITHOUT auth.
+ *
+ * X blocks unauthenticated page reads (WebFetch → HTTP 402), so this uses the
+ * public syndication endpoint that powers embedded tweets. The endpoint needs a
+ * `token` that is a deterministic function of the tweet id — we compute it
+ * locally ($0), so no API key and no login are ever required.
+ *
+ * Usage:
+ * node hydrate-tweet.js <tweet-id-or-url>
+ *
+ * Examples:
+ * node hydrate-tweet.js 2055557527153332556
+ * node hydrate-tweet.js https://x.com/heygurisingh/status/2055557527153332556
+ *
+ * Exit codes:
+ * 0 ok — printed tweet JSON summary
+ * 3 tombstone — tweet/account is suspended, deleted, or age-gated (unreadable)
+ * 1 error — bad input or network/parse failure
+ *
+ * Output: a JSON object on stdout:
+ * { id, url, author, created_at, text, urls[], github[] }
+ * On tombstone: { id, tombstone: "<reason text>" } and exit 3.
+ */
+
+'use strict';
+
+function extractId(arg) {
+ if (!arg) return null;
+ // trailing run of digits handles both bare ids and .../status/<id>[?query]
+ const m = String(arg).match(/(\d{5,25})/g);
+ return m ? m[m.length - 1] : null;
+}
+
+// react-tweet's documented token derivation: (id / 1e15 * PI) in base-36,
+// with zeros and the dot stripped. Verified against live tweets 2026-07.
+function syndicationToken(id) {
+ return ((Number(id) / 1e15) * Math.PI)
+ .toString(36)
+ .replace(/(0+|\.)/g, '');
+}
+
+function findGithub(text, urls) {
+ const found = new Set();
+ const scan = (s) => {
+ if (!s) return;
+ const re = /https?:\/\/(?:www\.)?github\.com\/[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+/g;
+ let m;
+ while ((m = re.exec(s))) found.add(m[0].replace(/[.,)]+$/, ''));
+ };
+ scan(text);
+ (urls || []).forEach(scan);
+ return [...found];
+}
+
+async function main() {
+ const id = extractId(process.argv[2]);
+ if (!id) {
+ console.error('usage: node hydrate-tweet.js <tweet-id-or-url>');
+ process.exit(1);
+ }
+
+ const token = syndicationToken(id);
+ const endpoint =
+ `https://cdn.syndication.twimg.com/tweet-result?id=${id}&lang=en&token=${token}`;
+
+ let res;
+ try {
+ res = await fetch(endpoint, {
+ headers: {
+ // a browser-ish UA avoids the occasional bot 403 on this endpoint
+ 'User-Agent':
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 ' +
+ '(KHTML, like Gecko) Chrome/125.0 Safari/537.36',
+ Accept: 'application/json',
+ },
+ });
+ } catch (e) {
+ console.error(`network error: ${e.message}`);
+ process.exit(1);
+ }
+
+ if (res.status === 404) {
+ console.log(JSON.stringify({ id, tombstone: 'not found (404)' }, null, 2));
+ process.exit(3);
+ }
+ if (!res.ok) {
+ console.error(`http ${res.status} from syndication endpoint`);
+ process.exit(1);
+ }
+
+ let data;
+ try {
+ data = await res.json();
+ } catch (e) {
+ console.error(`parse error: ${e.message}`);
+ process.exit(1);
+ }
+
+ // Tombstone shapes: suspended/deleted/age-gated tweets come back as a
+ // __typename of TweetTombstone (or an object with a `tombstone` field).
+ const tomb =
+ data.__typename === 'TweetTombstone' ||
+ data.tombstone ||
+ (data.text && /suspended account|Post is from a suspended|isn.?t available/i.test(data.text) && !data.user);
+ if (tomb) {
+ const reason =
+ (data.tombstone && (data.tombstone.text?.text || data.tombstone.text)) ||
+ data.text ||
+ 'unavailable (suspended / deleted / age-gated)';
+ console.log(JSON.stringify({ id, tombstone: reason }, null, 2));
+ process.exit(3);
+ }
+
+ const urls = (data.entities?.urls || []).map((u) => u.expanded_url || u.url);
+ const out = {
+ id,
+ url: `https://x.com/${data.user?.screen_name || 'i'}/status/${id}`,
+ author: data.user
+ ? `@${data.user.screen_name} (${data.user.name})`
+ : null,
+ created_at: data.created_at || null,
+ text: data.text || '',
+ urls,
+ github: findGithub(data.text || '', urls),
+ };
+ console.log(JSON.stringify(out, null, 2));
+ process.exit(0);
+}
+
+main();
(oldest)
·
back to Axel Bitblaze Scout
·
resolve seed post repo: browser-use/video-use 17.5k stars MI 17a5b2c →