<?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: An Pham</title>
    <description>The latest articles on DEV Community by An Pham (@ancs21).</description>
    <link>https://dev.to/ancs21</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%2F84939%2F612159f1-14ac-4a49-9ea1-c79708e85fed.png</url>
      <title>DEV Community: An Pham</title>
      <link>https://dev.to/ancs21</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ancs21"/>
    <language>en</language>
    <item>
      <title>I built an open-source Trello where a custom Pi agent harness does the cards</title>
      <dc:creator>An Pham</dc:creator>
      <pubDate>Sat, 10 Oct 2026 11:44:08 +0000</pubDate>
      <link>https://dev.to/ancs21/i-built-an-open-source-trello-where-a-custom-pi-agent-harness-does-the-cards-a16</link>
      <guid>https://dev.to/ancs21/i-built-an-open-source-trello-where-a-custom-pi-agent-harness-does-the-cards-a16</guid>
      <description>&lt;p&gt;My to-do list kept growing faster than I could clear it, and most of it wasn't hard work. "Compare three suppliers." "Draft the follow-up email." "Check the site still loads." Any decent AI agent could do these. The annoying part was everything around them: open a chat, paste the context, wait, copy the answer somewhere, then forget what I'd asked two days later.&lt;/p&gt;

&lt;p&gt;I wanted the cards to just get done. So I built &lt;a href="https://github.com/ancs21/openleo" rel="noopener noreferrer"&gt;OpenLeo&lt;/a&gt;, a to-do board where agents, running on my own harness built on &lt;a href="https://github.com/earendil-works/pi" rel="noopener noreferrer"&gt;Pi&lt;/a&gt;, pick up the cards. It's free and open source under AGPL-3.0.&lt;/p&gt;

&lt;p&gt;Here's the 30-second version:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://leooi.com" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpnu3p432l76dsx7o2wg1.gif" alt="OpenLeo in 30 seconds: Leo turns a to-do list into a board, agents pick up the cards and work on their own computers" width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;It looks and feels like Trello: lists, with cards in them. The one difference is that a list can have an agent.&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%2Fpzll5omvdfcklrbvchw2.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%2Fpzll5omvdfcklrbvchw2.jpg" alt="A board with five lists: Inbox, Research, Writing, Checks and Done. Some cards are being worked on, others are done" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the board above, a card dropped into Research goes to the researcher agent and a card in Writing goes to the writer. The Checks list has a monitor that looks at my site every weekday at 9:00. Inbox has no agent, so those cards wait for me.&lt;/p&gt;

&lt;p&gt;When an agent finishes, the answer stays on the card. Here's a real one. I asked for the price of a Hario V60 at three shops, and the researcher came back with a little table and links:&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%2Fsw1u8rcvj7waekzuskmg.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%2Fsw1u8rcvj7waekzuskmg.jpg" alt="A card showing the agent's result: a price table from three shops" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A card can start because I pressed run, because its schedule came round, or because it landed in a list with an agent. Each run gets noted on the card, so when I look the next morning I can see what happened and when.&lt;/p&gt;

&lt;p&gt;The same board also works as a table, with whatever fields you add (I used priority, due date and budget):&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%2F4k7yuid94lxo4w3ikkag.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%2F4k7yuid94lxo4w3ikkag.jpg" alt="The same board as a table with Priority, Due and Budget columns" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Every board gets its own computer
&lt;/h2&gt;

&lt;p&gt;I didn't want agents poking around my real laptop. In OpenLeo each board has its own Linux computer, a &lt;a href="https://github.com/trycua/cua" rel="noopener noreferrer"&gt;cua&lt;/a&gt; sandbox, and the agents do their work in there. They open a browser, click around, fill in forms and save files. If I'm curious I open the computer and watch, and if an agent gets stuck I can take over the mouse.&lt;/p&gt;

&lt;p&gt;On a Mac it uses Apple's &lt;a href="https://github.com/apple/container" rel="noopener noreferrer"&gt;&lt;code&gt;container&lt;/code&gt;&lt;/a&gt; runtime when it can and falls back to &lt;a href="https://www.docker.com" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; otherwise, and on Windows and Linux it uses Docker. You can also run the computers in cua's cloud. On first launch OpenLeo walks you through setting one up.&lt;/p&gt;

&lt;p&gt;The board's notes, its memory and the skills you teach an agent (how you file receipts, say) live on that computer too, right next to the work.&lt;/p&gt;

&lt;h2&gt;
  
  
  It runs on your ChatGPT plan
&lt;/h2&gt;

&lt;p&gt;I really didn't want people fiddling with API keys. OpenLeo uses OpenAI's &lt;a href="https://developers.openai.com/siwc/token-sharing-open-source/sign-in" rel="noopener noreferrer"&gt;Sign in with ChatGPT for open-source apps&lt;/a&gt;, the same kind of login &lt;a href="https://openai.com/codex/" rel="noopener noreferrer"&gt;Codex&lt;/a&gt; uses. You sign in with your ChatGPT account and the agents use the plan you already pay for. The tokens sit in a local vault file with owner-only permissions and never get sent to the web page.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it isn't
&lt;/h2&gt;

&lt;p&gt;It's for one person and their agents. I'm deliberately not turning it into a team project-management tool. It's also early. Expect rough edges, and back up your data before updating.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;The site is &lt;a href="https://leooi.com" rel="noopener noreferrer"&gt;leooi.com&lt;/a&gt; and the code is at &lt;a href="https://github.com/ancs21/openleo" rel="noopener noreferrer"&gt;github.com/ancs21/openleo&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/ancs21/openleo
&lt;span class="nb"&gt;cd &lt;/span&gt;openleo
bun &lt;span class="nb"&gt;install
&lt;/span&gt;bun run dev   &lt;span class="c"&gt;# http://127.0.0.1:3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or skip the terminal and get the desktop app. There are builds for macOS (Apple Silicon), Windows (x64) and Linux (x64 and arm64) on &lt;a href="https://leooi.com/download" rel="noopener noreferrer"&gt;leooi.com/download&lt;/a&gt; and the &lt;a href="https://github.com/ancs21/openleo/releases/latest" rel="noopener noreferrer"&gt;releases page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So here's my question for you: if a to-do card could do itself, which one would you hand off first? And which one would you never trust an agent with? I'll read every answer, and if something breaks, open an issue.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>opensource</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Your AI agent can't fetch behind logins. I built a &lt;400kb fix in Zig.</title>
      <dc:creator>An Pham</dc:creator>
      <pubDate>Sun, 29 Mar 2026 02:34:36 +0000</pubDate>
      <link>https://dev.to/ancs21/your-ai-agent-cant-fetch-behind-logins-i-built-a-400kb-fix-in-zig-4d31</link>
      <guid>https://dev.to/ancs21/your-ai-agent-cant-fetch-behind-logins-i-built-a-400kb-fix-in-zig-4d31</guid>
      <description>&lt;p&gt;Claude Code has WebFetch. Every AI coding agent has some way to grab a webpage.&lt;/p&gt;

&lt;p&gt;They all hit the same wall: auth.&lt;/p&gt;

&lt;p&gt;Try fetching a Medium article. A Facebook post. A private Substack. Anything behind Cloudflare. The agent gets a login page, a CAPTCHA, or nothing — and makes up the rest.&lt;/p&gt;

&lt;h2&gt;
  
  
  What playpanda does
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;playpanda https://medium.com/@someone/private-post
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You log in once. Cookies get saved. After that, fetching just works — from an agent, a script, or the terminal.&lt;/p&gt;

&lt;p&gt;The output is markdown with the junk stripped out. No nav bars, no cookie banners, no ads, no image CDN URLs. Just the content.&lt;/p&gt;

&lt;h2&gt;
  
  
  How agents can use it
&lt;/h2&gt;

&lt;p&gt;Anything that can shell out can use it:&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;# Replace WebFetch in Claude Code&lt;/span&gt;
playpanda https://docs.example.com/private-api

&lt;span class="c"&gt;# Fetch multiple pages at once&lt;/span&gt;
playpanda https://url1.com,https://url2.com,https://url3.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How fetching works
&lt;/h2&gt;

&lt;p&gt;It tries the fastest method first and escalates when something gets in the way:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Speed&lt;/th&gt;
&lt;th&gt;When it kicks in&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;HTTP fetch&lt;/td&gt;
&lt;td&gt;~200ms&lt;/td&gt;
&lt;td&gt;Default, works for most pages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JS rendering&lt;/td&gt;
&lt;td&gt;~1.5s&lt;/td&gt;
&lt;td&gt;Page needs JavaScript to load&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real browser + anti-detection&lt;/td&gt;
&lt;td&gt;~6s&lt;/td&gt;
&lt;td&gt;Site actively blocks bots&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The agent doesn't need to know which tier ran. It just gets markdown back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Size
&lt;/h2&gt;

&lt;p&gt;Single Zig binary, under 400kb.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;

&lt;p&gt;One-liner:&lt;br&gt;
&lt;/p&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/ancs21/playpanda/main/scripts/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As an agent skill:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add ancs21/playpanda
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From source (requires Zig 0.15+):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/ancs21/playpanda.git
&lt;span class="nb"&gt;cd &lt;/span&gt;playpanda
zig build &lt;span class="nt"&gt;-Doptimize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.ReleaseFast
&lt;span class="nb"&gt;cp &lt;/span&gt;zig-out/bin/playpanda ~/.local/bin/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub: &lt;a href="https://github.com/ancs21/playpanda" rel="noopener noreferrer"&gt;https://github.com/ancs21/playpanda&lt;/a&gt; (Apache 2.0 license)&lt;/p&gt;

</description>
      <category>zig</category>
      <category>opensource</category>
      <category>cli</category>
      <category>ai</category>
    </item>
    <item>
      <title>TIL: Croc - Securely transfer files via CLI</title>
      <dc:creator>An Pham</dc:creator>
      <pubDate>Tue, 21 Dec 2021 15:09:31 +0000</pubDate>
      <link>https://dev.to/ancs21/til-croc-securely-transfer-files-via-cli-1ihm</link>
      <guid>https://dev.to/ancs21/til-croc-securely-transfer-files-via-cli-1ihm</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/schollz/croc"&gt;croc&lt;/a&gt; is a tool that allows any two computers to simply and securely transfer files and folders.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;macOS
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install croc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Ubuntu
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://getcroc.schollz.com | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Window
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scoop install croc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Send file or folder
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;croc send [file(s)-or-folder]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Receive the file
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;croc [code from output]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More feature, please visit to &lt;a href="https://github.com/schollz/croc"&gt;https://github.com/schollz/croc&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>TLDR: Database Naming</title>
      <dc:creator>An Pham</dc:creator>
      <pubDate>Mon, 16 Aug 2021 15:16:27 +0000</pubDate>
      <link>https://dev.to/ancs21/tldr-database-naming-36fa</link>
      <guid>https://dev.to/ancs21/tldr-database-naming-36fa</guid>
      <description>&lt;p&gt;&lt;em&gt;Credit: Photo by Tobias Fischer on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Table names should be plural (ex: &lt;code&gt;users&lt;/code&gt;, &lt;code&gt;customers&lt;/code&gt;,...)&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;underscore_names&lt;/code&gt; (ex: &lt;code&gt;user_id&lt;/code&gt;, &lt;code&gt;user_role&lt;/code&gt;,...)&lt;/li&gt;
&lt;li&gt;Don't name primary key column &lt;code&gt;id&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Don't make column names unclear (ex: &lt;code&gt;u_role&lt;/code&gt;,...)&lt;/li&gt;
&lt;li&gt;Name foreign key columns the same as the columns they refer to&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>database</category>
      <category>naming</category>
    </item>
  </channel>
</rss>
