<?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: Wesley van der Stoep</title>
    <description>The latest articles on DEV Community by Wesley van der Stoep (@wvdstoep).</description>
    <link>https://dev.to/wvdstoep</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4122078%2F512563c3-3f93-4cc0-83c3-70827d5b1bdb.png</url>
      <title>DEV Community: Wesley van der Stoep</title>
      <link>https://dev.to/wvdstoep</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wvdstoep"/>
    <language>en</language>
    <item>
      <title>Your AI agent can plan anything. It still can't click "Post".</title>
      <dc:creator>Wesley van der Stoep</dc:creator>
      <pubDate>Sat, 12 Sep 2026 11:31:03 +0000</pubDate>
      <link>https://dev.to/wvdstoep/your-ai-agent-can-plan-anything-it-still-cant-click-post-2bpb</link>
      <guid>https://dev.to/wvdstoep/your-ai-agent-can-plan-anything-it-still-cant-click-post-2bpb</guid>
      <description>&lt;p&gt;Half the posts on my feed this week are some version of "what even &lt;em&gt;is&lt;/em&gt; an AI agent." If-statements in a trench coat. Memory vs. RAG. Verification bottlenecks. All good debates — and all about the agent's &lt;em&gt;brain&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Nobody's talking about its &lt;strong&gt;hands&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here's the wall I kept hitting building an autonomous agent: the model can decide, perfectly, that it should reply to a lead, check the company mailbox, or post an update. Then it just... can't. It has no way to actually do it. An LLM emits text; it doesn't click "Post" on a logged-in account.&lt;/p&gt;

&lt;p&gt;The usual answer is a scraper or a Playwright script with CSS selectors. Two problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Selectors shatter.&lt;/strong&gt; The site ships a redesign, &lt;code&gt;.btn-primary-v2&lt;/code&gt; becomes &lt;code&gt;.button__cta&lt;/code&gt;, and every script breaks silently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;They can't hold a real session.&lt;/strong&gt; The interesting actions all require being logged in &lt;em&gt;as someone&lt;/em&gt;, and a brittle script re-authing every run is a great way to get an account locked.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So I built the missing piece and open-sourced it: &lt;a href="https://github.com/Wvdstoep/ghost-browser" rel="noopener noreferrer"&gt;&lt;strong&gt;Ghost Browser&lt;/strong&gt;&lt;/a&gt; — a real Chromium an agent operates the way a person does.&lt;/p&gt;

&lt;h2&gt;
  
  
  It sees the page, it doesn't parse it
&lt;/h2&gt;

&lt;p&gt;The core trick is &lt;strong&gt;Set-of-Mark&lt;/strong&gt;. Before any decision, every interactive element on screen gets a numbered box painted over it &lt;em&gt;in the live DOM&lt;/em&gt;, the page is screenshotted, the boxes are stripped off again, and the agent gets the annotated picture plus a numbered list. Then it just says &lt;code&gt;click 12&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqt9qy45fxesq0dh17pb4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqt9qy45fxesq0dh17pb4.jpg" alt="Set-of-Mark: numbered boxes over a live page" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's the whole reason it survives redesigns where selectors don't: a numbered screenshot is redrawn from whatever is on screen &lt;em&gt;right now&lt;/em&gt;, and a language model is far better at looking at a picture than at parsing a DOM tree. No selector to get subtly wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  You log in once. It drives forever.
&lt;/h2&gt;

&lt;p&gt;You sign into a site &lt;strong&gt;by hand, once&lt;/strong&gt;, in a console. That session lives in a profile — isolated cookies and storage — and from then on the agent operates that real, logged-in session. No credentials in scripts, no re-auth loop. One profile per account, each labelled with the site it's signed into.&lt;/p&gt;

&lt;h2&gt;
  
  
  The line that matters: it asks before it acts
&lt;/h2&gt;

&lt;p&gt;Reading is free. Posting, messaging, following, joining are not — they happen under a real name and the notification has already reached a person. So those go through an &lt;strong&gt;act-gate&lt;/strong&gt;: the agent shows you the exact text and &lt;em&gt;waits&lt;/em&gt;. Approve, edit, or reject.&lt;/p&gt;

&lt;p&gt;It's enforced twice — the prompt says so, and a guard inspects the label of anything it's about to click and turns a "Post" or "Join" into a proposal anyway. "Let it act without asking" exists, it's off by default, and it should stay off until you've read a few of its drafts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it exists
&lt;/h2&gt;

&lt;p&gt;This is the tool a fully autonomous agent on my own platform uses for &lt;em&gt;anything&lt;/em&gt; that needs a real browser — a master agent plans the work, specialised organs handle research/outreach/publishing, and every time one needs to touch the real web as a real account, it calls Ghost Browser. Without it, the whole thing is a planner with no way to act.&lt;/p&gt;

&lt;p&gt;A few things fall out of that design for free:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A per-profile Tailscale exit&lt;/strong&gt; — route a session out through a device you own at home, so sites see a residential IP instead of a datacentre.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An SSRF guard&lt;/strong&gt; — a browser anyone can point at any URL is a server-side-request-forgery engine; it resolves and re-checks every hop, including redirects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A workflow engine + route cards&lt;/strong&gt; — compose deterministic flows, or record a site's own traffic once and replay it (no model calls on the second run).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  It's MIT, and I need a designer
&lt;/h2&gt;

&lt;p&gt;The engine is solid and production-tested. The console UI... was built by an engineer, not a designer, and it shows. If UI/UX is your thing, this is a project where your help lands immediately — there are issues tagged &lt;code&gt;ui&lt;/code&gt; and &lt;code&gt;good first issue&lt;/code&gt; waiting.&lt;/p&gt;

&lt;p&gt;Repo, setup guide (any VPS in ten minutes), and runnable examples: &lt;strong&gt;&lt;a href="https://github.com/Wvdstoep/ghost-browser" rel="noopener noreferrer"&gt;https://github.com/Wvdstoep/ghost-browser&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What's your take — is "hands" the missing layer in the agent stack, or am I solving a problem you'd solve a different way? Genuinely curious.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
