<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Leon</title>
    <description>The latest articles on DEV Community by Leon (@leonting1010).</description>
    <link>https://dev.to/leonting1010</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3851369%2F7a1d458f-c463-4b40-8bb1-69e5711e435d.png</url>
      <title>DEV Community: Leon</title>
      <link>https://dev.to/leonting1010</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/leonting1010"/>
    <language>en</language>
    <item>
      <title>We Ran 15,000 Browser Automations. The Failure That Matters Most Is Invisible to Your Monitoring.</title>
      <dc:creator>Leon</dc:creator>
      <pubDate>Mon, 20 Apr 2026 01:37:47 +0000</pubDate>
      <link>https://dev.to/leonting1010/we-ran-15000-browser-automations-the-failure-that-matters-most-is-invisible-to-your-monitoring-34jo</link>
      <guid>https://dev.to/leonting1010/we-ran-15000-browser-automations-the-failure-that-matters-most-is-invisible-to-your-monitoring-34jo</guid>
      <description>&lt;p&gt;Half of our YouTube automation runs return 0 rows. Status: &lt;code&gt;ok&lt;/code&gt;. No exception thrown. No error logged. The program finishes in about 20 seconds and hands back an empty array, silently.&lt;/p&gt;

&lt;p&gt;We didn't know this until we looked at the traces.&lt;/p&gt;

&lt;p&gt;Over the past few months, Tap has executed 15,455 automation programs across real websites — Reddit, GitHub, Bilibili, Xiaohongshu, YouTube, Twitter, and more. The traces are structured JSON: site, tap name, status, rows returned, duration, error message if any. We analyzed all of them. What we found disagrees with the conventional mental model of how browser automations break.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Reliability Table Nobody Publishes
&lt;/h2&gt;

&lt;p&gt;Here are the actual numbers. Each row is a real platform. &lt;strong&gt;Hard error rate&lt;/strong&gt; is the fraction of runs that threw an exception. &lt;strong&gt;Silent empty rate&lt;/strong&gt; is the fraction of &lt;em&gt;successful&lt;/em&gt; runs (status: ok) that returned zero rows.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Total runs&lt;/th&gt;
&lt;th&gt;Hard error %&lt;/th&gt;
&lt;th&gt;Silent empty %&lt;/th&gt;
&lt;th&gt;Effective failure %&lt;/th&gt;
&lt;th&gt;Avg duration&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Twitter / X&lt;/td&gt;
&lt;td&gt;128&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;154 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub&lt;/td&gt;
&lt;td&gt;437&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;0.2%&lt;/td&gt;
&lt;td&gt;0.2%&lt;/td&gt;
&lt;td&gt;3,644 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reddit&lt;/td&gt;
&lt;td&gt;688&lt;/td&gt;
&lt;td&gt;13.8%&lt;/td&gt;
&lt;td&gt;6.4%&lt;/td&gt;
&lt;td&gt;19.4%&lt;/td&gt;
&lt;td&gt;4,075 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Xiaohongshu&lt;/td&gt;
&lt;td&gt;361&lt;/td&gt;
&lt;td&gt;15.8%&lt;/td&gt;
&lt;td&gt;6.6%&lt;/td&gt;
&lt;td&gt;21.5%&lt;/td&gt;
&lt;td&gt;9,054 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bilibili&lt;/td&gt;
&lt;td&gt;259&lt;/td&gt;
&lt;td&gt;30.1%&lt;/td&gt;
&lt;td&gt;18.2%&lt;/td&gt;
&lt;td&gt;43.1%&lt;/td&gt;
&lt;td&gt;2,666 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weibo&lt;/td&gt;
&lt;td&gt;38&lt;/td&gt;
&lt;td&gt;36.8%&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;36.8%&lt;/td&gt;
&lt;td&gt;4,644 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YouTube&lt;/td&gt;
&lt;td&gt;49&lt;/td&gt;
&lt;td&gt;30.6%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;50.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;65.3%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;20,273 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;GitHub and Twitter are near-zero failure. YouTube is the opposite: two out of three runs either throw an error or return nothing. The 50% silent empty rate is more alarming than the 30.6% hard error rate — at least hard errors are visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Failure Mode You're Not Tracking
&lt;/h2&gt;

&lt;p&gt;Here's the part that surprised us most. We expected "element not found" to be the dominant failure. The conventional model: selector breaks, automation throws, you fix the selector. Obvious, visible, actionable.&lt;/p&gt;

&lt;p&gt;The actual numbers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Element not found&lt;/strong&gt; (explicit selector failure): &lt;strong&gt;5 occurrences&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cannot read properties of undefined (reading 'url')&lt;/strong&gt; (implicit structural failure): &lt;strong&gt;176 occurrences&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The ratio is 35:1 in favor of the failure mode your monitoring doesn't catch.&lt;/p&gt;

&lt;p&gt;What does &lt;code&gt;Cannot read properties of undefined (reading 'url')&lt;/code&gt; actually mean? The selector found something. The extraction ran. The automation didn't crash during navigation. It returned data — a list of objects — but the objects no longer have a &lt;code&gt;url&lt;/code&gt; field. The downstream code hits undefined and throws.&lt;/p&gt;

&lt;p&gt;This is a &lt;strong&gt;structural drift failure&lt;/strong&gt;, not a selector failure. The DOM element is there. The page loaded. The program traversed the right nodes. But the shape of the data those nodes return has changed — a field that was always present quietly stopped being present.&lt;/p&gt;

&lt;p&gt;The sites affected, in order of frequency:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bilibili (videos, articles, analytics, benchmark, content-ideas, stats, trending)&lt;/li&gt;
&lt;li&gt;Algora bounties&lt;/li&gt;
&lt;li&gt;IssueHunt bounties&lt;/li&gt;
&lt;li&gt;Douyin (search, hot)&lt;/li&gt;
&lt;li&gt;Zhihu search&lt;/li&gt;
&lt;li&gt;X/Twitter (notifications, trending)&lt;/li&gt;
&lt;li&gt;Xiaohongshu search&lt;/li&gt;
&lt;li&gt;Weibo search&lt;/li&gt;
&lt;li&gt;Baidu hot&lt;/li&gt;
&lt;li&gt;Hacker News hot&lt;/li&gt;
&lt;li&gt;ProductHunt forum comments&lt;/li&gt;
&lt;li&gt;TechCrunch latest&lt;/li&gt;
&lt;li&gt;Ars Technica news&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That list spans Chinese platforms, Western platforms, social networks, news sites, and developer bounty boards. The failure mode is not platform-specific. It's inherent to how browser automation interacts with any site that changes its rendering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Your Monitoring Doesn't See This
&lt;/h2&gt;

&lt;p&gt;Consider what's happening at the infrastructure layer when this failure occurs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP response: 200&lt;/li&gt;
&lt;li&gt;Page loaded successfully: yes&lt;/li&gt;
&lt;li&gt;Navigation completed: yes&lt;/li&gt;
&lt;li&gt;Automation process exited: 0&lt;/li&gt;
&lt;li&gt;Exception thrown: eventually — but only after the extraction, when downstream code accesses the malformed object&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most monitoring stacks see a successful process exit followed by an application exception. But the harder version is when the object &lt;em&gt;does&lt;/em&gt; have a &lt;code&gt;url&lt;/code&gt; field — it just points to something different. A related item section. A sponsored result. A pagination link that got included in the data array.&lt;/p&gt;

&lt;p&gt;In those cases: status &lt;code&gt;ok&lt;/code&gt;, rows returned, no exception, wrong data. Pydantic passes. Row count checks pass. Prometheus reports a healthy process. OTel has nothing to report. The only signal is semantic: &lt;em&gt;these URLs aren't the URLs you wanted.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Platform Reliability Pattern
&lt;/h2&gt;

&lt;p&gt;GitHub and Twitter have published APIs that their web UIs reflect. A GitHub repository page structure is stable because it's owned by the same team that maintains the underlying data model.&lt;/p&gt;

&lt;p&gt;Bilibili, Douyin, Xiaohongshu, and Weibo run aggressive A/B experiments on their rendering layer — sometimes multiple experiments simultaneously for different user cohorts. The same page, loaded twice in the same session, can return different DOM structures. The &lt;code&gt;url&lt;/code&gt; field on a video card might be in &lt;code&gt;item.url&lt;/code&gt; in one experiment variant and &lt;code&gt;item.jumpUrl&lt;/code&gt; in another.&lt;/p&gt;

&lt;p&gt;YouTube lands in between for a different reason: aggressive anti-bot measures that return empty results instead of blocking requests. A request that would return a 429 or CAPTCHA on a naive scraper returns 200 with an empty content container on a logged-out browser session. Status: ok. Rows: 0. Duration: 20 seconds of wasted compute.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Catches This, and What Doesn't
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Catches hard error?&lt;/th&gt;
&lt;th&gt;Catches silent empty?&lt;/th&gt;
&lt;th&gt;Catches wrong data (right shape)?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Process monitoring&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pydantic / type validation&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;Sometimes&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Row count threshold&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Health contracts (range + pattern + drift)&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Structural fingerprinting&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;Signals change, not interpretation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The only layer that catches all three failure classes is a contract that validates semantics — not just shape. A &lt;code&gt;min_rows&lt;/code&gt; check catches silent empties. A &lt;code&gt;pattern&lt;/code&gt; check on URLs catches wrong-source data. A &lt;code&gt;drift&lt;/code&gt; check catches distribution shifts that look valid but represent changed behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We'd Do Differently
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Treat silent empties as first-class failures.&lt;/strong&gt; A run returning zero rows should be suspicious by default. Most automations that legitimately return zero rows are edge cases. Most that return zero rows unexpectedly are broken. The difference is detectable with a &lt;code&gt;min_rows&lt;/code&gt; contract.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fingerprint before running, not after.&lt;/strong&gt; The structural drift that causes &lt;code&gt;Cannot read properties of undefined&lt;/code&gt; is detectable in the DOM before you run your extraction logic. A fingerprint check is cheaper than a full tap execution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Treat Chinese platforms as a separate reliability tier.&lt;/strong&gt; The A/B experiment cadence is genuinely different. A tap targeting Bilibili needs shorter contract drift windows and more frequent health checks than one targeting GitHub.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Duration is a signal.&lt;/strong&gt; Our YouTube taps average 20 seconds per run and fail 65% of the time. That's not slow extraction — that's waiting for content that's not coming. A timeout contract that fires at 8 seconds would catch most of these early.&lt;/p&gt;




&lt;p&gt;The trace data from 15,455 runs is the most honest answer we have to "what actually breaks in browser automation?"&lt;/p&gt;

&lt;p&gt;The answer: silent structural drift, not explicit selector failure. The sites that change fastest break most. The failures that matter most are the ones that look like success.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with &lt;a href="https://taprun.dev" rel="noopener noreferrer"&gt;Tap&lt;/a&gt; — browser automation programs that run forever.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Search arXiv in One Command — No API Key, No Tokens</title>
      <dc:creator>Leon</dc:creator>
      <pubDate>Tue, 07 Apr 2026 09:46:59 +0000</pubDate>
      <link>https://dev.to/leonting1010/search-arxiv-in-one-command-no-api-key-no-tokens-54ib</link>
      <guid>https://dev.to/leonting1010/search-arxiv-in-one-command-no-api-key-no-tokens-54ib</guid>
      <description>&lt;p&gt;Keeping up with AI research is exhausting. New papers drop daily. Most "paper discovery" tools require an account, burn API tokens on every search, or give you a bloated UI when all you wanted was a list.&lt;/p&gt;

&lt;p&gt;Here's what I use instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;-y&lt;/span&gt; @taprun/cli arxiv search &lt;span class="nt"&gt;--keyword&lt;/span&gt; &lt;span class="s2"&gt;"LLM"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | npx &lt;span class="nt"&gt;-y&lt;/span&gt; @taprun/cli &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;--field&lt;/span&gt; published &lt;span class="se"&gt;\&lt;/span&gt;
  | npx &lt;span class="nt"&gt;-y&lt;/span&gt; @taprun/cli table
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output: 20 papers sorted newest-first, with title, authors, published date, abstract, and URL — in under 2 seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No account. No API key. No AI tokens consumed.&lt;/strong&gt; First run downloads a ~30MB binary and caches it; every subsequent call is instant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Works
&lt;/h2&gt;

&lt;p&gt;The arXiv Atom API has been public and stable for 15 years. &lt;code&gt;arxiv/search&lt;/code&gt; is a &lt;a href="https://github.com/LeonTing1010/tap-skills" rel="noopener noreferrer"&gt;Tap skill&lt;/a&gt; — a 20-line deterministic program that calls it directly. AI wrote it once. It runs forever at $0.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Unix Pipeline Model
&lt;/h2&gt;

&lt;p&gt;Every Tap skill is a composable Unix filter. Data flows as JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Search only&lt;/span&gt;
npx &lt;span class="nt"&gt;-y&lt;/span&gt; @taprun/cli arxiv search &lt;span class="nt"&gt;--keyword&lt;/span&gt; &lt;span class="s2"&gt;"RAG"&lt;/span&gt;

&lt;span class="c"&gt;# Search → sort by date → filter recent → display&lt;/span&gt;
npx &lt;span class="nt"&gt;-y&lt;/span&gt; @taprun/cli arxiv search &lt;span class="nt"&gt;--keyword&lt;/span&gt; &lt;span class="s2"&gt;"RAG"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | npx &lt;span class="nt"&gt;-y&lt;/span&gt; @taprun/cli &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;--field&lt;/span&gt; published &lt;span class="se"&gt;\&lt;/span&gt;
  | npx &lt;span class="nt"&gt;-y&lt;/span&gt; @taprun/cli filter &lt;span class="nt"&gt;--field&lt;/span&gt; published &lt;span class="nt"&gt;--gt&lt;/span&gt; &lt;span class="s2"&gt;"2025-01-01"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | npx &lt;span class="nt"&gt;-y&lt;/span&gt; @taprun/cli table
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each command reads JSON from stdin, writes JSON to stdout. Exactly how Unix tools work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use It in CI
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# GitHub Actions — daily paper digest&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Paper digest&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;npx -y @taprun/cli arxiv search --keyword "LLM agents" \&lt;/span&gt;
      &lt;span class="s"&gt;| npx -y @taprun/cli sort --field published \&lt;/span&gt;
      &lt;span class="s"&gt;| npx -y @taprun/cli limit --n 5 \&lt;/span&gt;
      &lt;span class="s"&gt;&amp;gt; papers.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  200+ Skills, Same Pattern
&lt;/h2&gt;

&lt;p&gt;arXiv is one of 200+ community skills that follow the same pattern: call an API, return structured rows, compose with any other skill.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Skill&lt;/th&gt;
&lt;th&gt;Returns&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;arxiv/search --keyword X&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Papers matching keyword&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;github/trending&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Trending repos today&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reddit/search --keyword X&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Posts matching keyword&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;stackoverflow/hot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hot questions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Browse and contribute: &lt;a href="https://github.com/LeonTing1010/tap-skills" rel="noopener noreferrer"&gt;github.com/LeonTing1010/tap-skills&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Try it now — no install required, works on any machine with Node.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;-y&lt;/span&gt; @taprun/cli arxiv search &lt;span class="nt"&gt;--keyword&lt;/span&gt; &lt;span class="s2"&gt;"your topic"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | npx &lt;span class="nt"&gt;-y&lt;/span&gt; @taprun/cli &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;--field&lt;/span&gt; published &lt;span class="se"&gt;\&lt;/span&gt;
  | npx &lt;span class="nt"&gt;-y&lt;/span&gt; @taprun/cli table
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;→ &lt;a href="https://taprun.dev" rel="noopener noreferrer"&gt;taprun.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>cli</category>
      <category>showdev</category>
      <category>tooling</category>
    </item>
    <item>
      <title>16 Comments, 6 Insights: Using HN and Reddit as a Positioning Lab</title>
      <dc:creator>Leon</dc:creator>
      <pubDate>Mon, 06 Apr 2026 05:18:09 +0000</pubDate>
      <link>https://dev.to/leonting1010/16-comments-6-insights-using-hn-and-reddit-as-a-positioning-lab-46oo</link>
      <guid>https://dev.to/leonting1010/16-comments-6-insights-using-hn-and-reddit-as-a-positioning-lab-46oo</guid>
      <description>&lt;p&gt;I spent an afternoon writing 16 comments across Hacker News and Reddit. Not to promote anything — to &lt;strong&gt;test which pain points actually resonate with developers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The result: 6 content principles I now use to decide what to build, what to write about, and how to position my product. Here's the method.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Method: Comments as Micro-Experiments
&lt;/h2&gt;

&lt;p&gt;The premise is simple: &lt;strong&gt;a comment is the cheapest possible A/B test.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Writing a blog post takes hours. A landing page rewrite takes days. A comment takes 2 minutes. If it gets upvoted, the angle works. If it's ignored, you saved yourself a blog post nobody would read.&lt;/p&gt;

&lt;p&gt;The process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find hot posts in your domain (automation, scraping, developer tools, AI)&lt;/li&gt;
&lt;li&gt;Write a comment that tests a specific angle — one pain point, one insight&lt;/li&gt;
&lt;li&gt;Track which angles get traction&lt;/li&gt;
&lt;li&gt;Turn validated angles into blog posts and landing page copy&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I posted across 10 subreddits and HN front-page posts spanning AI, infrastructure, open source, and developer tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 6 Insights
&lt;/h2&gt;

&lt;h3&gt;
  
  
  #1 Silent failure is the universal pain
&lt;/h3&gt;

&lt;p&gt;I commented on Gallery-dl's DMCA move (HN front page) and r/webscraping's "endgame for scraping" (104 upvotes). Both times, the angle that resonated was: &lt;strong&gt;the hard part isn't writing a scraper — it's knowing when it breaks.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Most scrapers fail silently — they return empty arrays for days before anyone notices."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Principle:&lt;/strong&gt; Lead with the maintenance problem, not the creation problem. Everyone can build a scraper. Nobody can keep it running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Health contracts. Every program defines what "working" means: minimum rows, required fields. &lt;code&gt;tap doctor&lt;/code&gt; checks all programs in one command. When something breaks, you know in seconds — not weeks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;health&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;min_rows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;5&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;non_empty&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;

&lt;span class="s"&gt;$ tap doctor&lt;/span&gt;
&lt;span class="s"&gt;hackernews/hot    ✔ ok     30 rows&lt;/span&gt;
&lt;span class="s"&gt;reddit/hot        ✘ fail   0 rows — selector changed&lt;/span&gt;
  &lt;span class="s"&gt;↳ auto-healing...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #2 Cost anxiety is real and specific
&lt;/h3&gt;

&lt;p&gt;Caveman hit 727 points — a post about reducing LLM token usage. Nanocode (177 points) was about self-hosting Claude Code to understand the real cost. Developers aren't just curious about AI costs — they're &lt;strong&gt;anxious&lt;/strong&gt; about them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Principle:&lt;/strong&gt; Use exact numbers. "$1.05 per run" and "300x cheaper" land. "More affordable" doesn't. Developers think in math, not adjectives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; The compiler model. AI runs once at authoring time (~$0.15), produces a deterministic program, and every subsequent execution is $0. Fifty daily automations: $18,000/year with AI agents vs ~$60/year with compiled programs.&lt;/p&gt;

&lt;h3&gt;
  
  
  #3 "Open-source alternative" is not a value prop
&lt;/h3&gt;

&lt;p&gt;The Modo post ("open-source alternative to Cursor and Windsurf") had only 2 comments despite being on the front page. My feedback: &lt;strong&gt;users don't switch tools for ideology — they switch for workflow improvements.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The README should lead with a concrete before/after: 'In Cursor you do X in 5 steps, in Modo you do it in 1.' That's what converts users."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Principle:&lt;/strong&gt; Show the delta, not the category. "I'm like X but open source" tells users nothing about why they should switch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Concrete comparison. Browser Use: $0.50–$2.00/run, 60–95% reliability, 30–120s. Tap: $0/run, 100% deterministic, 1–5s. Same task, measurable difference.&lt;/p&gt;

&lt;h3&gt;
  
  
  #4 Local-first is having a moment
&lt;/h3&gt;

&lt;p&gt;Three unrelated posts all trended around the same theme:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gemma 4 on iPhone&lt;/strong&gt; (496 points) — on-device AI inference&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-dependency browser IDE&lt;/strong&gt; (r/opensource) — works offline, no npm&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nomad offline media server&lt;/strong&gt; (r/selfhosted) — works without internet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Developers are increasingly allergic to tools that phone home.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Principle:&lt;/strong&gt; "Runs on your machine, works offline" is a feature worth highlighting, not an implementation detail to bury.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Tap programs are plain &lt;code&gt;.tap.js&lt;/code&gt; files that execute locally. No API calls at runtime, no data leaving your device, no cloud dependency. They work on a plane, in a cabin, wherever your laptop goes.&lt;/p&gt;

&lt;h3&gt;
  
  
  #5 Legal pressure on scraping is accelerating
&lt;/h3&gt;

&lt;p&gt;Gallery-dl's DMCA notice trended on &lt;em&gt;both&lt;/em&gt; HN and r/programming simultaneously. The pattern: &lt;strong&gt;open-source scraping tools face increasing legal pressure.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Principle:&lt;/strong&gt; API-first data access is both technically superior and legally safer. Position accordingly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; &lt;code&gt;tap.fetch()&lt;/code&gt; calls site APIs directly — structured JSON, stable endpoints, no DOM parsing. Only falls back to browser rendering when no API exists. Less breakage, less legal surface area.&lt;/p&gt;

&lt;h3&gt;
  
  
  #6 Infrastructure beats features
&lt;/h3&gt;

&lt;p&gt;Switzerland's 25 Gbit internet (315 points, 249 comments) wasn't about speed — it was about &lt;strong&gt;structural fairness&lt;/strong&gt;. Open fiber access vs. local monopolies.&lt;/p&gt;

&lt;p&gt;The parallel to automation tooling: AI agents at $1/run create a cost barrier. Deterministic programs at $0 are infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Principle:&lt;/strong&gt; Frame your tool as infrastructure people own, not a service they rent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Every &lt;code&gt;.tap.js&lt;/code&gt; is a file you own. Git-versionable, diffable, composable. Cancel your subscription and your programs keep running. No vendor lock-in, no API keys required at runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Playbook
&lt;/h2&gt;

&lt;p&gt;If you're building a developer tool and struggling with positioning:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Don't start with a landing page.&lt;/strong&gt; Start with 10 comments on relevant posts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Each comment tests one angle.&lt;/strong&gt; One pain point, one insight, one framing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upvotes = validation.&lt;/strong&gt; High-scoring posts where your comment resonates = confirmed pain point.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Silence = signal too.&lt;/strong&gt; If nobody engages with your angle, it's not a pain point.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Turn validated angles into content.&lt;/strong&gt; Blog post from the best angle. Landing page copy from the specific phrases that worked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never link your product in comments.&lt;/strong&gt; Share expertise. Build credibility. The product link lives on your profile.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Comments are conversations. Conversations reveal what people actually care about. That's worth more than any amount of competitor analysis.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The tool I used to validate these insights: &lt;a href="https://taprun.dev" rel="noopener noreferrer"&gt;Tap&lt;/a&gt; turns AI into a compiler for browser automation. AI writes a program once, then it runs forever at $0. The positioning came from the comments. The product came from the pain.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>marketing</category>
      <category>product</category>
      <category>startup</category>
      <category>writing</category>
    </item>
    <item>
      <title>Programs Beat Prompts: Why AI Should Write Code, Not Run It</title>
      <dc:creator>Leon</dc:creator>
      <pubDate>Mon, 06 Apr 2026 05:04:19 +0000</pubDate>
      <link>https://dev.to/leonting1010/programs-beat-prompts-why-ai-should-write-code-not-run-it-3gde</link>
      <guid>https://dev.to/leonting1010/programs-beat-prompts-why-ai-should-write-code-not-run-it-3gde</guid>
      <description>&lt;p&gt;Every AI browser agent works the same way: send a prompt, burn tokens, get a result. Next time you need the same result? Send the prompt again. Burn more tokens.&lt;/p&gt;

&lt;p&gt;This is the &lt;strong&gt;prompt loop&lt;/strong&gt;, and it's why AI automation is expensive, unreliable, and slow.&lt;/p&gt;

&lt;p&gt;There's a better model: &lt;strong&gt;AI writes a program once, then the program runs forever at zero cost.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Prompt Loop Problem
&lt;/h2&gt;

&lt;p&gt;AI browser agents like Browser Use, Stagehand, and computer-use tools are impressive demos. Point an LLM at a website, tell it what to do, watch it click around. Magic.&lt;/p&gt;

&lt;p&gt;Until you need it to work reliably. At scale. Every day.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The program cost $1.05 to run. So doing it at any scale quickly becomes a little bit silly."&lt;br&gt;
— rozap, Hacker News&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The math is brutal. An AI agent that scrapes one site costs ~$1 per run. Run it daily across 50 sites and you're spending &lt;strong&gt;$1,500/month&lt;/strong&gt; on data collection that a deterministic script would do for free.&lt;/p&gt;

&lt;p&gt;But cost isn't even the worst part. &lt;strong&gt;Reliability is.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"If each step has a .95 chance of completing successfully, after not very many steps you have a pretty small overall probability of success."&lt;br&gt;
— rozap, Hacker News&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;95% per step sounds good. A 10-step workflow? 60% overall. Twenty steps? 36%. Every AI call is a coin flip weighted slightly in your favor — but over enough steps, the house always wins.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Compiler Model
&lt;/h2&gt;

&lt;p&gt;There's a pattern from 60 years of computer science that solves this: &lt;strong&gt;compilation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A compiler reads high-level code once, produces optimized machine code, and that machine code runs billions of times at zero marginal cost. The compiler is expensive. The output is free.&lt;/p&gt;

&lt;p&gt;Apply this to browser automation:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Prompt model (interpreter)&lt;/th&gt;
&lt;th&gt;Program model (compiler)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AI cost per run&lt;/td&gt;
&lt;td&gt;$0.50 – $2.00&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0.00&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reliability per run&lt;/td&gt;
&lt;td&gt;60 – 95%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100% deterministic&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speed&lt;/td&gt;
&lt;td&gt;30 – 120s (LLM thinking)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1 – 5s (direct execution)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI usage&lt;/td&gt;
&lt;td&gt;Every run&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Only at authoring time&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The insight: &lt;strong&gt;AI is the compiler, not the runtime.&lt;/strong&gt; Use AI to understand the interface, write a deterministic program, and then execute that program forever without AI.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Looks Like
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Step 1: AI observes the interface (the "compile" step)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;tap forge &lt;span class="s2"&gt;"get trending repos from GitHub"&lt;/span&gt;
Inspecting github.com...
Found API: api.github.com/search/repositories
Verifying: 25 rows, all fields present
✔ Saved: github/trending.tap.js

&lt;span class="c"&gt;# Step 2: Program runs forever at $0 (the "execute" step)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;tap github trending
25 rows &lt;span class="o"&gt;(&lt;/span&gt;890ms&lt;span class="o"&gt;)&lt;/span&gt; Cost: &lt;span class="nv"&gt;$0&lt;/span&gt;.00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first command uses AI. Every subsequent run is pure code — no LLM, no tokens, no variability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Programs Win
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Deterministic means debuggable
&lt;/h3&gt;

&lt;p&gt;When a prompt fails, you get "the AI didn't understand the page." When a program fails, you get a stack trace, a line number, and a selector that changed. One is a mystery. The other is a bug you can fix.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Programs compose
&lt;/h3&gt;

&lt;p&gt;Prompts are isolated. Each one starts fresh, with no memory of what came before. Programs call other programs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This tap calls two other taps and combines the results&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;repos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;github&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;trending&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;github&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stars&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;me&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Composition is free. No extra tokens. No prompt engineering to maintain context across steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Programs have contracts
&lt;/h3&gt;

&lt;p&gt;A prompt returns whatever the AI decides. A program has a health contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;health&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;min_rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;// must return at least 10 results&lt;/span&gt;
  &lt;span class="nx"&gt;non_empty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="c1"&gt;// title field can't be empty&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the site changes and the program breaks, the contract catches it immediately. No silent failure. No stale data for days.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Programs version naturally
&lt;/h3&gt;

&lt;p&gt;A .tap.js file is just JavaScript. It goes in Git. You get diffs, blame, history, rollback. Try doing that with a prompt chain stored in a vector database.&lt;/p&gt;

&lt;h2&gt;
  
  
  When You Do Need AI Again
&lt;/h2&gt;

&lt;p&gt;Programs aren't magic. Websites change. When they do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;tap doctor
github/trending   ✔ ok     25 rows
reddit/hot        ✘ fail   0 rows  — selector changed

&lt;span class="c"&gt;# Doctor detected the break. Re-forge just that one:&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;tap doctor &lt;span class="nt"&gt;--auto&lt;/span&gt;
Re-forging reddit/hot...
✔ Fixed: reddit/hot.tap.js &lt;span class="o"&gt;(&lt;/span&gt;new selectors&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AI is called once to fix the program. Then it runs at $0 again until the next change. You pay for intelligence only when the world changes — which is 1% of the time, not 100%.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Numbers
&lt;/h2&gt;

&lt;p&gt;For a real workload of 50 automations running daily:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Prompt-per-run&lt;/th&gt;
&lt;th&gt;Programs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Daily AI cost&lt;/td&gt;
&lt;td&gt;$50&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monthly AI cost&lt;/td&gt;
&lt;td&gt;$1,500&lt;/td&gt;
&lt;td&gt;~$5 (occasional re-forge)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Annual AI cost&lt;/td&gt;
&lt;td&gt;$18,000&lt;/td&gt;
&lt;td&gt;~$60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reliability&lt;/td&gt;
&lt;td&gt;60 – 95%&lt;/td&gt;
&lt;td&gt;100% (until site changes)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speed per run&lt;/td&gt;
&lt;td&gt;30 – 120s&lt;/td&gt;
&lt;td&gt;1 – 5s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;300x cost reduction. 20x faster. Deterministic. The math doesn't require a sales pitch.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Try it:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install (macOS / Linux)&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://taprun.dev/install.sh | sh

&lt;span class="c"&gt;# Forge your first program&lt;/span&gt;
tap forge &lt;span class="s2"&gt;"get top stories from Hacker News"&lt;/span&gt;

&lt;span class="c"&gt;# Run it forever at $0&lt;/span&gt;
tap hackernews hot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://taprun.dev/getting-started.html" rel="noopener noreferrer"&gt;Getting started&lt;/a&gt; · &lt;a href="https://github.com/LeonTing1010/tap" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · 200+ community taps included&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>automation</category>
      <category>programming</category>
    </item>
    <item>
      <title>Your AI Browser Agent Costs $3,600/month. Here's How to Make It $0</title>
      <dc:creator>Leon</dc:creator>
      <pubDate>Sun, 05 Apr 2026 15:08:47 +0000</pubDate>
      <link>https://dev.to/leonting1010/your-ai-browser-agent-costs-3600month-heres-how-to-make-it-0-4228</link>
      <guid>https://dev.to/leonting1010/your-ai-browser-agent-costs-3600month-heres-how-to-make-it-0-4228</guid>
      <description>&lt;p&gt;A developer recently documented burning through &lt;strong&gt;180 million tokens per month&lt;/strong&gt; — $3,600 — running AI browser agents. That's not a typo.&lt;/p&gt;

&lt;p&gt;The browser-use community (78K GitHub stars) is full of users asking the same question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I have a recurring task meant for webscraping to be done every 5 min. I do not want to use too many tokens. Is it possible to repeat the tasks?" — &lt;a href="https://github.com/browser-use/browser-use/discussions/494" rel="noopener noreferrer"&gt;browser-use #494&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;"My business scenario requires solidifying the agent's execution process into a tool. I noticed &lt;code&gt;save_as_playwright_script&lt;/code&gt; is commented out." — &lt;a href="https://github.com/browser-use/browser-use/discussions/4519" rel="noopener noreferrer"&gt;browser-use #4519&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;"Running the default task took &lt;strong&gt;12 minutes&lt;/strong&gt; on M3 Max, 36GB RAM" — &lt;a href="https://github.com/browser-use/browser-use/discussions/957" rel="noopener noreferrer"&gt;browser-use #957&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The problem is architectural: &lt;strong&gt;every run uses AI tokens&lt;/strong&gt;, even when you're doing the exact same thing for the 1,000th time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Interpreter vs. Compiler Model
&lt;/h2&gt;

&lt;p&gt;Today's browser agents work like interpreters — AI reasons about every click, every scroll, every form fill, every single time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Interpreter (browser-use, Stagehand, Operator):
  Run 1:    AI reads page → decides action → executes    ($0.01)
  Run 2:    AI reads page → decides action → executes    ($0.01)
  Run 100:  AI reads page → decides action → executes    ($0.01)
  Run 1000: AI reads page → decides action → executes    ($0.01)
  Total: $10.00 (and growing)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But what if AI could &lt;strong&gt;compile&lt;/strong&gt; the workflow once, then replay it forever?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Compiler approach:
  Run 1:    AI inspects page → generates program          ($0.04, one-time)
  Run 2:    Program runs deterministically                 ($0.00)
  Run 100:  Program runs deterministically                 ($0.00)
  Run 1000: Program runs deterministically                 ($0.00)
  Total: $0.04 (forever)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't hypothetical. &lt;a href="https://github.com/LeonTing1010/tap" rel="noopener noreferrer"&gt;Tap&lt;/a&gt; implements this exact pattern:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;forge inspect&lt;/code&gt;&lt;/strong&gt; — Analyzes the page (framework, SSR state, APIs, DOM structure). Zero AI tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI generates a &lt;code&gt;.tap.js&lt;/code&gt; program&lt;/strong&gt; — One-time cost (~$0.04).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;tap run&lt;/code&gt;&lt;/strong&gt; — Executes the program forever. $0.00 per run.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why API-First Beats DOM Replay
&lt;/h2&gt;

&lt;p&gt;Most record-and-replay tools (including browser-use's &lt;a href="https://github.com/browser-use/workflow-use" rel="noopener noreferrer"&gt;workflow-use&lt;/a&gt;) capture DOM interactions — clicks, typing, scrolling. This breaks when the UI changes.&lt;/p&gt;

&lt;p&gt;The better approach: &lt;strong&gt;extract via API when possible, DOM only as fallback.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most modern websites have internal APIs (Next.js &lt;code&gt;__NEXT_DATA__&lt;/code&gt;, Nuxt SSR state, REST endpoints). Calling the API directly is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;100x more reliable than simulating clicks&lt;/li&gt;
&lt;li&gt;Immune to UI redesigns&lt;/li&gt;
&lt;li&gt;Faster (no rendering needed)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, getting Hacker News front page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// DOM approach (fragile):&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.athing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// API approach (robust):&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://hacker-news.firebaseio.com/v0/topstories.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real Numbers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;AI Agent (per run)&lt;/th&gt;
&lt;th&gt;Compiled Program (per run)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;$0.003–0.01&lt;/td&gt;
&lt;td&gt;$0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speed&lt;/td&gt;
&lt;td&gt;12 min (reported)&lt;/td&gt;
&lt;td&gt;5 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reliability&lt;/td&gt;
&lt;td&gt;Varies (AI hallucinations)&lt;/td&gt;
&lt;td&gt;Deterministic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tokens&lt;/td&gt;
&lt;td&gt;1K–10K per action&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At 100 runs/day:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI agent: &lt;strong&gt;$30–300/month&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Compiled program: &lt;strong&gt;$0.04 total&lt;/strong&gt; (one-time forge cost)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;If you're running the same browser task more than once, you're overpaying by 100–1000x. The future isn't smarter agents — it's agents that are &lt;strong&gt;smart once&lt;/strong&gt; and produce deterministic programs.&lt;/p&gt;

&lt;p&gt;Token prices are falling 10x/year. But $0 will always beat any price.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://github.com/LeonTing1010/tap" rel="noopener noreferrer"&gt;Tap&lt;/a&gt; is open source. 208 pre-built programs across 77 sites. One binary, zero dependencies.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Try it: &lt;a href="https://taprun.dev" rel="noopener noreferrer"&gt;taprun.dev&lt;/a&gt; | &lt;a href="https://github.com/LeonTing1010/tap" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Your Scraper Is Broken Right Now. You Just Don't Know It Yet.</title>
      <dc:creator>Leon</dc:creator>
      <pubDate>Sat, 04 Apr 2026 13:18:29 +0000</pubDate>
      <link>https://dev.to/leonting1010/your-scraper-is-broken-right-now-you-just-dont-know-it-yet-38f5</link>
      <guid>https://dev.to/leonting1010/your-scraper-is-broken-right-now-you-just-dont-know-it-yet-38f5</guid>
      <description>&lt;p&gt;Somewhere in your infrastructure, a scraper is returning empty arrays. Your dashboard shows stale numbers. A report your team relies on has been wrong since Tuesday.&lt;/p&gt;

&lt;p&gt;You won't find out until someone complains.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Silent Failure Problem
&lt;/h2&gt;

&lt;p&gt;Most scrapers don't crash loudly. They fail quietly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Instead of throwing an error when a page structure changes, they return empty arrays... A scraper that fails silently poisons your data for days or weeks before anyone notices."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This happens because scrapers have no &lt;strong&gt;health contract&lt;/strong&gt;. They extract whatever they find — and when the site changes, "whatever they find" is nothing. No error. No alert. Just empty data flowing downstream.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Maintenance Tax
&lt;/h2&gt;

&lt;p&gt;When you do notice, you're back to fixing selectors. Again.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Every time a website redesigns or updates their layout, I'm manually fixing selectors and rewriting parts of the workflow. It's eating up hours every month."&lt;/p&gt;

&lt;p&gt;"Maintaining tests can take up to 50% of the time for QA test automation engineers."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The loop is always the same: build automation → site changes → selectors break → spend hours fixing → repeat.&lt;/p&gt;

&lt;h2&gt;
  
  
  The AI Agent Tax
&lt;/h2&gt;

&lt;p&gt;AI browser agents promise to solve this by re-interpreting the page every run. But they introduce two new problems:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Cost compounds.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The program cost $1.05 to run. So doing it at any scale quickly becomes a little bit silly."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;2. Reliability degrades at each step.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"If each step has a .95 chance of completing successfully, after not very many steps you have a pretty small overall probability of success."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;95% per step sounds great. But a 10-step workflow is 60% overall. AI agents trade one problem (brittle selectors) for another (probabilistic failure).&lt;/p&gt;

&lt;h2&gt;
  
  
  A Different Approach: Health Contracts
&lt;/h2&gt;

&lt;p&gt;What if your automation had a &lt;strong&gt;contract&lt;/strong&gt; that defined what "healthy" looks like?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Built into every program&lt;/span&gt;
&lt;span class="nx"&gt;health&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;min_rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;// must return at least 5 results&lt;/span&gt;
  &lt;span class="nx"&gt;non_empty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="c1"&gt;// "title" field must never be empty&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now instead of silently returning empty arrays, the system &lt;em&gt;knows&lt;/em&gt; when something is wrong:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tap doctor
&lt;span class="go"&gt;hackernews/hot    ✓ ok     30 rows  (245ms)
google/trends     ✗ fail   0 rows   min_rows: expected ≥5, got 0
github/trending   ✓ ok     25 rows  (1.2s)
bbc/news          ✗ fail   3 rows   min_rows: expected ≥5, got 3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two failures caught. Before your data went bad. Before anyone complained.&lt;/p&gt;

&lt;h2&gt;
  
  
  Watch: Real-Time Change Detection
&lt;/h2&gt;

&lt;p&gt;Health checks catch breakage. But what about legitimate changes?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I built Site Spy after missing a visa appointment slot because a government page changed and I didn't notice for two weeks."&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tap watch hackernews hot &lt;span class="nt"&gt;--every&lt;/span&gt; 10m
&lt;span class="go"&gt;2026-04-04T10:00  +added   "Show HN: Tap"  score=342
2026-04-04T10:10  +added   "Rust 2.0 announced"  score=128
2026-04-04T10:10  -removed "Old post fell off"  score=12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run your program on an interval, diff the results, output only what changed. Pipe it to a file, Slack webhook, or another program.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Self-Healing Loop
&lt;/h2&gt;

&lt;p&gt;Put it all together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. AI writes a deterministic program once&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;tap forge &lt;span class="s2"&gt;"scrape Hacker News top stories"&lt;/span&gt;
✓ Saved: hackernews/hot.tap.js

&lt;span class="c"&gt;# 2. Run forever at $0&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;tap hackernews hot
30 rows &lt;span class="o"&gt;(&lt;/span&gt;245ms&lt;span class="o"&gt;)&lt;/span&gt; Cost: &lt;span class="nv"&gt;$0&lt;/span&gt;.00

&lt;span class="c"&gt;# 3. Watch for data changes&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;tap watch hackernews hot &lt;span class="nt"&gt;--every&lt;/span&gt; 1h

&lt;span class="c"&gt;# 4. Daily health check&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;tap doctor &lt;span class="nt"&gt;--schedule&lt;/span&gt; &lt;span class="s2"&gt;"0 6 * * *"&lt;/span&gt;

&lt;span class="c"&gt;# 5. Auto-heal when something breaks&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;tap doctor &lt;span class="nt"&gt;--auto&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The loop: &lt;strong&gt;forge → run → watch → doctor → heal → run&lt;/strong&gt;. You sleep. Your automations don't stop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Works
&lt;/h2&gt;

&lt;p&gt;The key insight: &lt;strong&gt;AI should run at authoring time, not at runtime.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Forge&lt;/strong&gt; uses AI once to write a deterministic program&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run&lt;/strong&gt; executes it with zero AI — $0 per execution, 100% deterministic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Doctor&lt;/strong&gt; detects breakage via health contracts — no AI needed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Heal&lt;/strong&gt; re-invokes AI only when the site actually changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;99% of runs need zero AI. You only pay for intelligence when the world changes.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://github.com/LeonTing1010/tap" rel="noopener noreferrer"&gt;Tap&lt;/a&gt; is open source. 195+ pre-built automations included. &lt;a href="https://taprun.dev/getting-started.html" rel="noopener noreferrer"&gt;Getting started takes 2 minutes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://taprun.dev/blog/your-scraper-is-broken.html" rel="noopener noreferrer"&gt;taprun.dev/blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>automation</category>
      <category>ai</category>
      <category>scraping</category>
    </item>
    <item>
      <title>Programs Beat Prompts: How Tap Turns AI into a Compiler for Browser Automation</title>
      <dc:creator>Leon</dc:creator>
      <pubDate>Thu, 02 Apr 2026 07:06:51 +0000</pubDate>
      <link>https://dev.to/leonting1010/programs-beat-prompts-how-tap-turns-ai-into-a-compiler-for-browser-automation-oab</link>
      <guid>https://dev.to/leonting1010/programs-beat-prompts-how-tap-turns-ai-into-a-compiler-for-browser-automation-oab</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Every time you ask an AI agent to do something in a browser, it costs money and time. Click here, type there, extract that — the AI figures it out from scratch every single time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if AI only had to figure it out once?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tap: The Compiler Approach
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://leonting1010.github.io/tap/" rel="noopener noreferrer"&gt;Tap&lt;/a&gt; is a protocol + toolchain that turns AI's interface operations into deterministic programs (&lt;code&gt;.tap.js&lt;/code&gt; files):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Forge&lt;/strong&gt; — AI observes the page (network, DOM, a11y tree) and writes a tap program&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify&lt;/strong&gt; — Test the tap with different inputs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run forever&lt;/strong&gt; — The tap replays deterministically. Zero AI cost.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;First run:  AI inspects → writes .tap.js     ($0.50)
Every run:  .tap.js replays deterministically ($0.00)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;8 core operations + 17 built-in operations = complete browser control protocol.&lt;/p&gt;

&lt;p&gt;A tap program is plain JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;site&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;github&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;trending&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://github.com/trending&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;article.Box-row&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h2 a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.octicon-star&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nx"&gt;parentElement&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;}))&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Multi-Runtime
&lt;/h2&gt;

&lt;p&gt;The same tap runs on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chrome Extension&lt;/strong&gt; — Uses &lt;code&gt;chrome.scripting&lt;/code&gt; (undetectable)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Playwright&lt;/strong&gt; — Headless capable, CI/CD friendly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;macOS&lt;/strong&gt; — Native apps via Accessibility API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A new runtime implements 8 methods, gets 17 built-in operations for free.&lt;/p&gt;

&lt;h2&gt;
  
  
  Community Skills
&lt;/h2&gt;

&lt;p&gt;119 community skills across 55 sites — &lt;a href="https://github.com/LeonTing1010/tap-skills" rel="noopener noreferrer"&gt;tap-skills&lt;/a&gt; (open source).&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Not Just Use Playwright?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Playwright&lt;/th&gt;
&lt;th&gt;Tap&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Who writes scripts?&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;td&gt;AI forges them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost per run&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;$0.00 (deterministic)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtimes&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;3+ (Chrome, Playwright, macOS)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Community scripts&lt;/td&gt;
&lt;td&gt;No ecosystem&lt;/td&gt;
&lt;td&gt;119 skills&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://leonting1010.github.io/tap/install.sh | sh
tap github trending
tap hackernews hot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Homepage: &lt;a href="https://leonting1010.github.io/tap/" rel="noopener noreferrer"&gt;leonting1010.github.io/tap&lt;/a&gt;&lt;br&gt;
Skills (open source): &lt;a href="https://github.com/LeonTing1010/tap-skills" rel="noopener noreferrer"&gt;github.com/LeonTing1010/tap-skills&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Programs beat prompts. AI forges once, programs run forever.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Try it: &lt;a href="https://taprun.dev" rel="noopener noreferrer"&gt;taprun.dev&lt;/a&gt; | &lt;a href="https://github.com/LeonTing1010/tap" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
    </item>
    <item>
      <title>Programs Beat Prompts: AI Forges Deterministic Interface Programs That Run Forever</title>
      <dc:creator>Leon</dc:creator>
      <pubDate>Wed, 01 Apr 2026 08:20:35 +0000</pubDate>
      <link>https://dev.to/leonting1010/programs-beat-prompts-ai-forges-deterministic-interface-programs-that-run-forever-j9e</link>
      <guid>https://dev.to/leonting1010/programs-beat-prompts-ai-forges-deterministic-interface-programs-that-run-forever-j9e</guid>
      <description>&lt;p&gt;Every time my AI agent automated a website interaction, it was burning tokens to solve the same problem it had already solved last run. Find the API. Locate the selector. Compose the steps. Re-solved, re-paid, every single time.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;Tap&lt;/strong&gt; to fix this. The core idea: &lt;strong&gt;operating an interface is a solved problem the moment you figure out how.&lt;/strong&gt; So separate the figuring-out (AI's job, done once) from the executing (a deterministic program's job, done forever).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Paradigm: Forging
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;forge_inspect → forge_verify → forge_save → tap.run
    AI analyzes    AI tests      AI saves     runs forever, zero AI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AI analyzes the live site, creates a &lt;code&gt;.tap.js&lt;/code&gt; file, and that file runs forever — no LLM calls, no prompts, no API keys. Runs in &amp;lt;1s. Returns structured data. Same result every time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost model: ~$0.50 in tokens to forge. Then $0.00 at runtime, forever.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Protocol
&lt;/h2&gt;

&lt;p&gt;Tap defines a minimal, complete contract for interface automation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8 core operations&lt;/strong&gt; (irreducible atoms):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eval · pointer · keyboard · nav · wait · screenshot · run · capabilities
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;17 built-in operations&lt;/strong&gt; (composed from core):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;click · type · fill · hover · scroll · pressKey · select · upload · dialog
fetch · find · cookies · download · waitFor · waitForNetwork · ssrState · storage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;8 + 17 = every interaction a human can perform on any interface.&lt;/p&gt;

&lt;p&gt;A new runtime implements 8 methods → gets 17 built-ins free. Write a tap once, run it on Chrome, Playwright, macOS native apps — same protocol.&lt;/p&gt;

&lt;h2&gt;
  
  
  106 Ready-to-Use Skills
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/LeonTing1010/tap/master/install.sh | sh
tap update  &lt;span class="c"&gt;# Pulls 106 skills across 50 sites&lt;/span&gt;

&lt;span class="c"&gt;# Use&lt;/span&gt;
tap github trending &lt;span class="nt"&gt;--limit&lt;/span&gt; 5
tap hackernews hot
tap xiaohongshu hot

&lt;span class="c"&gt;# Compose with Unix pipes&lt;/span&gt;
tap github trending | tap tap/filter &lt;span class="nt"&gt;--field&lt;/span&gt; stars &lt;span class="nt"&gt;--gt&lt;/span&gt; 1000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Skills cover GitHub, Reddit, YouTube, Hacker News, X/Twitter, Medium, arXiv, Bilibili, Zhihu, Xiaohongshu, Weibo, and 40+ more sites.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a .tap.js looks like
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// API-first: fetch data directly&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;site&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hackernews&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hacker News top stories&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;health&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;min_rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;non_empty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="na"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://hacker-news.firebaseio.com/v0/topstories.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://hacker-news.firebaseio.com/v0/item/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.json`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;by&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pure JavaScript. Zero AI at runtime. The &lt;code&gt;health&lt;/code&gt; contract means &lt;code&gt;tap doctor&lt;/code&gt; can self-verify this tap automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  MCP Native
&lt;/h2&gt;

&lt;p&gt;Works with Claude Code, Cursor, Windsurf, and any MCP-compatible agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tap"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"mcp"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;43 tools across 6 categories — run taps, forge new ones, inspect pages, intercept network traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;p&gt;Community taps are untrusted code. Three layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Sandbox&lt;/strong&gt; — Deno Worker, zero permissions (no filesystem, network, env)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static analysis&lt;/strong&gt; — 7 CI checks on every PR to tap-skills&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data isolation&lt;/strong&gt; — secrets and sessions never leave your machine&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How It Compares
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Tap&lt;/th&gt;
&lt;th&gt;Browser-Use / Stagehand&lt;/th&gt;
&lt;th&gt;Playwright&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AI at runtime&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No (forge once)&lt;/td&gt;
&lt;td&gt;Yes (every step)&lt;/td&gt;
&lt;td&gt;No (manual scripts)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Detection risk&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Undetectable&lt;/td&gt;
&lt;td&gt;Detectable (CDP)&lt;/td&gt;
&lt;td&gt;Detectable (headless)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~$0.50 once, then $0&lt;/td&gt;
&lt;td&gt;Tokens per session&lt;/td&gt;
&lt;td&gt;Free (manual)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reusable artifacts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;.tap.js (shareable)&lt;/td&gt;
&lt;td&gt;None (ephemeral)&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Skills ecosystem&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;106 across 50 sites&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  GitHub
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/LeonTing1010/tap" rel="noopener noreferrer"&gt;https://github.com/LeonTing1010/tap&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;106 skills, 3 runtimes, ~2,000 lines of Deno, zero dependencies.&lt;/p&gt;




&lt;p&gt;Try it: &lt;a href="https://taprun.dev" rel="noopener noreferrer"&gt;taprun.dev&lt;/a&gt; | &lt;a href="https://github.com/LeonTing1010/tap" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
    </item>
    <item>
      <title>Programs Beat Prompts: Tap Turns AI Into a Compiler for Interface Automation</title>
      <dc:creator>Leon</dc:creator>
      <pubDate>Wed, 01 Apr 2026 07:51:33 +0000</pubDate>
      <link>https://dev.to/leonting1010/programs-beat-prompts-tap-turns-ai-into-a-compiler-for-interface-automation-51d8</link>
      <guid>https://dev.to/leonting1010/programs-beat-prompts-tap-turns-ai-into-a-compiler-for-interface-automation-51d8</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;AI agents operate interfaces at $0.10/call, 2-5s latency. Every. Single. Time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Insight
&lt;/h2&gt;

&lt;p&gt;Operating an interface is a &lt;strong&gt;solved problem the moment you figure out how.&lt;/strong&gt; AI understands the page once. Execution doesn't need AI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tap: Forge Once, Run Forever
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;forge_inspect → forge_verify → forge_save → tap.run
   AI analyzes     AI tests      AI saves    $0 forever
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;8 core operations + 17 built-in. 3 runtimes (Chrome, Playwright, macOS). Unix pipes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tap github trending | tap tap/filter &lt;span class="nt"&gt;--field&lt;/span&gt; stars &lt;span class="nt"&gt;--gt&lt;/span&gt; 1000
tap watch github trending &lt;span class="nt"&gt;--every&lt;/span&gt; 5m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;106 skills across 50+ sites. Self-healing via &lt;code&gt;tap doctor&lt;/code&gt;. Sandbox + CI security.&lt;/p&gt;

&lt;p&gt;199 constraint tests define the product — no spec docs, code is the spec.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/LeonTing1010/tap" rel="noopener noreferrer"&gt;https://github.com/LeonTing1010/tap&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post was published using Tap itself (devto/post tap).&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Try it: &lt;a href="https://taprun.dev" rel="noopener noreferrer"&gt;taprun.dev&lt;/a&gt; | &lt;a href="https://github.com/LeonTing1010/tap" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
    </item>
    <item>
      <title>Programs Beat Prompts: How Tap Turns AI Understanding Into Deterministic Programs</title>
      <dc:creator>Leon</dc:creator>
      <pubDate>Wed, 01 Apr 2026 07:48:19 +0000</pubDate>
      <link>https://dev.to/leonting1010/programs-beat-prompts-how-tap-turns-ai-understanding-into-deterministic-programs-208b</link>
      <guid>https://dev.to/leonting1010/programs-beat-prompts-how-tap-turns-ai-understanding-into-deterministic-programs-208b</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;AI agents need to operate interfaces — read data, click buttons, fill forms. But AI is too slow ($0.10/call, 2-5s latency) and too unreliable to drive every interaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Insight
&lt;/h2&gt;

&lt;p&gt;Operating an interface is a &lt;strong&gt;solved problem the moment you figure out how.&lt;/strong&gt; The hard part is understanding the page. That's what AI is good at. The easy part is executing the same steps again. That doesn't need AI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tap: Forge Once, Run Forever
&lt;/h2&gt;

&lt;p&gt;Tap separates understanding (AI, once) from execution (deterministic, forever):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;forge_inspect → forge_verify → forge_save → tap.run
   AI analyzes     AI tests      AI saves    runs forever, $0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Protocol
&lt;/h3&gt;

&lt;p&gt;8 core operations — the irreducible atoms of interface interaction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eval · pointer · keyboard · nav · wait · screenshot · run · capabilities
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;17 built-in operations composed from core. One program runs on Chrome Extension, Playwright, and macOS native apps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unix Pipes
&lt;/h3&gt;

&lt;p&gt;Taps compose like Unix commands — auto TTY detection, no flags needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tap github trending | tap tap/filter &lt;span class="nt"&gt;--field&lt;/span&gt; stars &lt;span class="nt"&gt;--gt&lt;/span&gt; 1000
tap watch github trending &lt;span class="nt"&gt;--every&lt;/span&gt; 5m | tap tap/filter &lt;span class="nt"&gt;--field&lt;/span&gt; stars &lt;span class="nt"&gt;--gt&lt;/span&gt; 500
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Self-Healing
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tap doctor
  ✔ github/trending     &lt;span class="nv"&gt;score&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.0  25 rows &lt;span class="o"&gt;(&lt;/span&gt;180ms&lt;span class="o"&gt;)&lt;/span&gt;
  ✘ douyin/hot           &lt;span class="nv"&gt;score&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.0  0 rows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Health contracts + declared examples = taps verify themselves.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security: 3 Layers
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Sandbox&lt;/strong&gt; — Deno Worker with zero permissions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static analysis&lt;/strong&gt; — 7 CI checks on every community PR&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data isolation&lt;/strong&gt; — .gitignore blocks secrets, no git remote on user taps&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  v0.5.0 Highlights
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;199 constraint tests (safety + quality + principle)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tap doctor&lt;/code&gt; — self-healing health checks&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tap contribute&lt;/code&gt; — PR workflow to community skills&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tap watch&lt;/code&gt; — outputs changes only, time dimension&lt;/li&gt;
&lt;li&gt;Forge captures real API traffic for accurate strategy&lt;/li&gt;
&lt;li&gt;Sandbox for untrusted community taps&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  106 skills across 50+ sites
&lt;/h3&gt;

&lt;p&gt;GitHub, Reddit, HN, X/Twitter, YouTube, Bilibili, Zhihu, Xiaohongshu, Weibo, Medium, arXiv, and more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/LeonTing1010/tap" rel="noopener noreferrer"&gt;github.com/LeonTing1010/tap&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Skills:&lt;/strong&gt; &lt;a href="https://github.com/LeonTing1010/tap-skills" rel="noopener noreferrer"&gt;github.com/LeonTing1010/tap-skills&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post was published using Tap itself (&lt;code&gt;devto/post&lt;/code&gt; tap).&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Try it: &lt;a href="https://taprun.dev" rel="noopener noreferrer"&gt;taprun.dev&lt;/a&gt; | &lt;a href="https://github.com/LeonTing1010/tap" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>browserautomation</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Tap: Forge Once, Run Forever — Why AI Browser Automation Needs a Protocol</title>
      <dc:creator>Leon</dc:creator>
      <pubDate>Mon, 30 Mar 2026 12:22:00 +0000</pubDate>
      <link>https://dev.to/leonting1010/tap-forge-once-run-forever-why-ai-browser-automation-needs-a-protocol-3cee</link>
      <guid>https://dev.to/leonting1010/tap-forge-once-run-forever-why-ai-browser-automation-needs-a-protocol-3cee</guid>
      <description>&lt;p&gt;Every AI agent that interacts with the web faces the same problem: &lt;strong&gt;AI is too slow, too expensive, and too unreliable to drive a browser in real-time.&lt;/strong&gt;Tools like Browser-Use and Stagehand burn tokens on every click. A simple "get GitHub trending" costs ~$0.15 and takes 30+ seconds. Every operation can hallucinate.## A Different Approach: ForgingWhat if AI only did the hard work once?T&lt;/p&gt;




&lt;p&gt;Try it: &lt;a href="https://taprun.dev" rel="noopener noreferrer"&gt;taprun.dev&lt;/a&gt; | &lt;a href="https://github.com/LeonTing1010/tap" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>browserautomation</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Tap: Forge Once, Run Forever — Why AI Browser Automation Needs a Protocol</title>
      <dc:creator>Leon</dc:creator>
      <pubDate>Mon, 30 Mar 2026 12:02:54 +0000</pubDate>
      <link>https://dev.to/leonting1010/tap-forge-once-run-forever-why-ai-browser-automation-needs-a-protocol-7pe</link>
      <guid>https://dev.to/leonting1010/tap-forge-once-run-forever-why-ai-browser-automation-needs-a-protocol-7pe</guid>
      <description>&lt;p&gt;Every AI agent that interacts with the web faces the same problem: &lt;strong&gt;AI is too slow, too expensive, and too unreliable to drive a browser in real-time.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tools like Browser-Use and Stagehand burn tokens on every click. A simple "get GitHub trending" costs ~$0.15 and takes 30+ seconds. Every operation can hallucinate.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Different Approach: Forging
&lt;/h2&gt;

&lt;p&gt;What if AI only did the hard work once?&lt;/p&gt;

&lt;p&gt;That's &lt;a href="https://github.com/LeonTing1010/tap" rel="noopener noreferrer"&gt;Tap&lt;/a&gt;. Instead of AI controlling the browser at runtime, AI creates a deterministic script — and that script runs forever.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;forge.inspect(url)     → AI analyzes the page
forge.verify(expr)     → AI tests the extraction
forge.save(site, name) → Script saved

tap.run(site, name)    → Runs forever. Zero AI. Zero tokens.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Protocol
&lt;/h2&gt;

&lt;p&gt;Tap defines &lt;strong&gt;8 kernel primitives&lt;/strong&gt; — the irreducible atoms of all human-interface interaction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eval · pointer · keyboard · nav · wait · screenshot · tap · capabilities
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And &lt;strong&gt;16 stdlib operations&lt;/strong&gt; built from the kernel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;click · type · hover · scroll · pressKey · select · upload · dialog
fetch · find · cookies · download · waitFor · waitForNetwork · ssrState · storage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A new runtime implements 8 methods — instantly gains 16 operations and every existing script.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Numbers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;AI-per-step&lt;/th&gt;
&lt;th&gt;Tap&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cost per run&lt;/td&gt;
&lt;td&gt;~$0.15&lt;/td&gt;
&lt;td&gt;$0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency&lt;/td&gt;
&lt;td&gt;30+ seconds&lt;/td&gt;
&lt;td&gt;&amp;lt; 1 second&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reliability&lt;/td&gt;
&lt;td&gt;LLM may hallucinate&lt;/td&gt;
&lt;td&gt;Deterministic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Composability&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Taps call other taps&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  81 Skills, Ready to Use
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tap &lt;span class="nb"&gt;install&lt;/span&gt;              &lt;span class="c"&gt;# Install 81 community skills&lt;/span&gt;
tap github trending      &lt;span class="c"&gt;# GitHub trending repos&lt;/span&gt;
tap hackernews hot       &lt;span class="c"&gt;# Top HN stories&lt;/span&gt;
tap zhihu hot            &lt;span class="c"&gt;# Zhihu trending&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;41 sites including X/Twitter, Reddit, GitHub, YouTube, Bilibili, Zhihu, Xiaohongshu, Weibo, Medium, arXiv. All using your real Chrome session. No API keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  MCP Native
&lt;/h2&gt;

&lt;p&gt;38 tools as an MCP server — works with Claude Code, Cursor, Windsurf, OpenClaw:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tap"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"mcp"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ~1,800 Lines, Zero Dependencies
&lt;/h2&gt;

&lt;p&gt;CLI + MCP server + executor + daemon + two runtimes — under 2,000 lines of Deno. No frameworks, no build step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/LeonTing1010/tap/master/install.sh | sh
tap &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; tap github trending
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/LeonTing1010/tap" rel="noopener noreferrer"&gt;github.com/LeonTing1010/tap&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Skills: &lt;a href="https://github.com/LeonTing1010/tap-skills" rel="noopener noreferrer"&gt;github.com/LeonTing1010/tap-skills&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What sites would you forge a tap for?&lt;/p&gt;




&lt;p&gt;Try it: &lt;a href="https://taprun.dev" rel="noopener noreferrer"&gt;taprun.dev&lt;/a&gt; | &lt;a href="https://github.com/LeonTing1010/tap" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>browserautomation</category>
      <category>mcp</category>
    </item>
  </channel>
</rss>
