<?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>Forem: John A Madrigal</title>
    <description>The latest articles on Forem by John A Madrigal (@trickell).</description>
    <link>https://forem.com/trickell</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%2F1478634%2Fe622e333-1707-49b3-9a3e-e9e978e779c8.jpg</url>
      <title>Forem: John A Madrigal</title>
      <link>https://forem.com/trickell</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/trickell"/>
    <language>en</language>
    <item>
      <title>Sub-Agent Documents Everything in Notion</title>
      <dc:creator>John A Madrigal</dc:creator>
      <pubDate>Thu, 26 Mar 2026 22:46:44 +0000</pubDate>
      <link>https://forem.com/trickell/i-built-an-agent-whose-only-job-is-to-document-everything-in-notion-i64</link>
      <guid>https://forem.com/trickell/i-built-an-agent-whose-only-job-is-to-document-everything-in-notion-i64</guid>
      <description>&lt;p&gt;I have a problem. Not a "my code does not compile" problem. A "I have so many ideas and projects and notes that my brain just gives up and reboots" problem. 😵‍💫&lt;/p&gt;

&lt;p&gt;So I did what any reasonable developer would do: I built an AI agent inside Open Claw whose only job is to document everything beautifully in Notion. His name is Escriber.&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.amazonaws.com%2Fuploads%2Farticles%2Fvu3dnbx8i2kotr72vn5r.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fvu3dnbx8i2kotr72vn5r.png" alt="The Prompt that birthed Escriber"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is my submission for the &lt;strong&gt;Notion MCP Challenge&lt;/strong&gt;.  Let me tell you, building a focused single-purpose agent with 14 Notion tools is exactly as satisfying as it sounds.&lt;/p&gt;



&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Escriber is agent #2 of 5 on my OpenClaw multi-agent team. &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.amazonaws.com%2Fuploads%2Farticles%2F61y61h5u5n5vuxww62lx.png" 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.amazonaws.com%2Fuploads%2Farticles%2F61y61h5u5n5vuxww62lx.png" alt="Escriber telling me about himself"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;His &lt;code&gt;SOUL.md&lt;/code&gt; says exactly this: &lt;em&gt;"I document. Beautifully. In Notion."&lt;/em&gt; And for anyone who has not used OpenClaw, they give these agents Soul.md files that define who the agent is and give them a small personality. &lt;/p&gt;

&lt;p&gt;That is it. Full stop. He cannot debug your code. He cannot give life advice. He has one lane and he stays in it — which, honestly, is more discipline than I have most the time. 😆&lt;/p&gt;

&lt;p&gt;He lives in Discord as a bot or I can use the web chat interface to call on him directly. He can be slightly artisanal. Dry wit is baked in by design, because documentation does not have to be soulless. He makes use of my Synap bot to write summaries for projects and clean them up like I would say them, then he will store what Synap sends back.&lt;/p&gt;

&lt;p&gt;He is not a Swiss Army knife. He is a scalpel. And sometimes that is exactly what you need.&lt;/p&gt;



&lt;h2&gt;
  
  
  Video Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/5Hh9uR4e5eM"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;



&lt;h2&gt;
  
  
  Show Us the Code
&lt;/h2&gt;

&lt;p&gt;Escriber talks to Notion through &lt;strong&gt;mcporter&lt;/strong&gt; — an MCP relay that proxies tool calls to Notion's official MCP server. Every Notion interaction looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mcporter call notion.&amp;lt;tool_name&amp;gt; &lt;span class="nt"&gt;--args&lt;/span&gt; &lt;span class="s1"&gt;'{ ... }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean. Consistent. One pattern to rule them all.&lt;/p&gt;

&lt;p&gt;Here is the full arsenal — 14 tools, one agent, zero excuses for undocumented projects:&lt;/p&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;What It Does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Find existing pages/databases before creating duplicates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.create_page&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Spin up a new page anywhere in the workspace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.retrieve_page&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read a page's metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.update_page&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Update page properties&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.append_block_children&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add content blocks to an existing page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.retrieve_block_children&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read what is already on a page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.retrieve_block&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fetch a specific block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.update_block&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Edit an existing block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.delete_block&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove a block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.create_database&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a new database&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.retrieve_database&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read database structure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.update_database&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modify database schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.query_database&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Filter and search database entries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.create_database_item&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add a row to a database&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Escriber also has workflow rules baked into his instructions. Because tools without discipline are just chaos with an API:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Search first.&lt;/strong&gt; Always check if the page already exists before creating a new one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read before writing.&lt;/strong&gt; Retrieve block children before appending to avoid structural disasters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Right block type.&lt;/strong&gt; Callouts for decisions. Toggles for details. Headings for structure. Not everything is a paragraph.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structure intentionally.&lt;/strong&gt; Measure twice, cut once. 🤣&lt;/li&gt;
&lt;/ul&gt;



&lt;h2&gt;
  
  
  How I Used Notion MCP
&lt;/h2&gt;

&lt;p&gt;Let me tell you how this actually works.&lt;/p&gt;

&lt;p&gt;mcporter connects Escriber to Notion's official MCP server at &lt;code&gt;https://mcp.notion.com/mcp&lt;/code&gt;. Every tool call gets proxied through that relay — no direct API wrangling, no custom request builders. The MCP layer handles it. Escriber just speaks tool.&lt;/p&gt;

&lt;p&gt;Here is what that looks like day-to-day:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New project starts?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;create_page&lt;/code&gt; to spin up the project hub. &lt;code&gt;create_database_item&lt;/code&gt; to log it in the master projects database. Done in seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wrapping up a build session?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;append_block_children&lt;/code&gt; to the existing project page. Build notes, decisions made, what broke, what did not. Structured. Timestamped. Actually findable later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JB's Job Listings&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;create_page&lt;/code&gt; My recruiter agent stored a list of jobs using Esciber every morning. Future-me will be grateful. Past-me was not doing this. These are stored in Notion daily, and sortable ☠️&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.amazonaws.com%2Fuploads%2Farticles%2Fovb6o0k3zyg65x5m1diu.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fovb6o0k3zyg65x5m1diu.png" alt="Notion Job Notes"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Let me tell you about the shame moment that made this real.&lt;/p&gt;

&lt;p&gt;I went back through my own Notion workspace a few weeks ago. Pages with titles like "ideas v3 FINAL" and "project notes DO NOT DELETE" containing exactly… three bullet points and a YouTube link. That is it. That is the legacy. A graveyard of good intentions. ☠️&lt;/p&gt;

&lt;p&gt;Escriber exists because I needed someone with more documentation discipline than me. Turns out that someone is a focused AI agent with a soul file and 14 Notion tools.&lt;/p&gt;

&lt;p&gt;One job. One lane. Real personality. And the docs actually get written now.&lt;/p&gt;

&lt;p&gt;"Optimization starts with a single point of failure—or a single point of success. Own the lane."&lt;/p&gt;

&lt;p&gt;Also, thanks to Bloggy, for taking the time to help with this post. &lt;/p&gt;




&lt;p&gt;&lt;em&gt;Escriber is part of my OpenClaw agent team. If you are curious about building multi-agent setups in openclaw, drop a comment — I am writing more about this whole stack as it comes together.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>openclaw</category>
      <category>ai</category>
      <category>notion</category>
      <category>mcp</category>
    </item>
    <item>
      <title>I Built an Agent Whose Only Job Is to Document Everything in Notion (So My Brain Does Not Have To)</title>
      <dc:creator>John A Madrigal</dc:creator>
      <pubDate>Wed, 25 Mar 2026 02:46:46 +0000</pubDate>
      <link>https://forem.com/trickell/i-built-an-agent-whose-only-job-is-to-document-everything-in-notion-so-my-brain-does-not-have-to-1h4j</link>
      <guid>https://forem.com/trickell/i-built-an-agent-whose-only-job-is-to-document-everything-in-notion-so-my-brain-does-not-have-to-1h4j</guid>
      <description>&lt;p&gt;I have a problem. Not a "my code does not compile" problem. A "I have so many ideas, projects and notes that my brain just about explodes and reboots" problem. 😵‍💫&lt;/p&gt;

&lt;p&gt;So... I did what any reasonable developer would do, right? I built an AI agent inside Open Claw whose only job is to document everything beautifully in Notion. His name is Escriber and he's my new documenter. &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.amazonaws.com%2Fuploads%2Farticles%2Fvu3dnbx8i2kotr72vn5r.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fvu3dnbx8i2kotr72vn5r.png" alt="The Prompt that birthed Escriber"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is my submission for the &lt;strong&gt;Notion MCP Challenge&lt;/strong&gt;.  Let me tell you, building a focused single-purpose agent with 14 Notion tools is exactly as satisfying as it sounds.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Escriber is agent #2 of 5 on my OpenClaw multi-agent team. &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.amazonaws.com%2Fuploads%2Farticles%2F61y61h5u5n5vuxww62lx.png" 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.amazonaws.com%2Fuploads%2Farticles%2F61y61h5u5n5vuxww62lx.png" alt="Escriber telling me about himself"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;His &lt;code&gt;SOUL.md&lt;/code&gt; says exactly this: &lt;em&gt;"I document. Beautifully. In Notion."&lt;/em&gt; And for anyone who has not used OpenClaw, they give these agents Soul.md files that define who the agent is and give them a small personality. &lt;/p&gt;

&lt;p&gt;That is it. Full stop. He cannot debug your code. He cannot give life advice. He has one lane and he stays in it — which, honestly, is more discipline than I have most the time. 😆&lt;/p&gt;

&lt;p&gt;He lives in Discord as a bot or I can use the web chat interface to call on him directly. He can be slightly artisanal. Dry wit is baked in by design, because documentation does not have to be soulless. He makes use of my Synap bot to write summaries for projects and clean them up like I would say them, then he will store what Synap sends back.&lt;/p&gt;

&lt;p&gt;He is not a Swiss Army knife. He is a scalpel. And sometimes that is exactly what you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Video Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/5Hh9uR4e5eM"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Show Us the Code
&lt;/h2&gt;

&lt;p&gt;Escriber talks to Notion through &lt;strong&gt;mcporter&lt;/strong&gt; — an MCP relay that proxies tool calls to Notion's official MCP server. Every Notion interaction looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mcporter call notion.&amp;lt;tool_name&amp;gt; &lt;span class="nt"&gt;--args&lt;/span&gt; &lt;span class="s1"&gt;'{ ... }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean. Consistent. One pattern to rule them all.&lt;/p&gt;

&lt;p&gt;Here is the full arsenal — 14 tools, one agent, zero excuses for undocumented projects:&lt;/p&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;What It Does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Find existing pages/databases before creating duplicates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.create_page&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Spin up a new page anywhere in the workspace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.retrieve_page&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read a page's metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.update_page&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Update page properties&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.append_block_children&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add content blocks to an existing page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.retrieve_block_children&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read what is already on a page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.retrieve_block&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fetch a specific block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.update_block&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Edit an existing block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.delete_block&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove a block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.create_database&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a new database&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.retrieve_database&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read database structure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.update_database&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modify database schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.query_database&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Filter and search database entries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion.create_database_item&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add a row to a database&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Escriber also has workflow rules baked into his instructions. Because tools without discipline are just chaos with an API:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Search first.&lt;/strong&gt; Always check if the page already exists before creating a new one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read before writing.&lt;/strong&gt; Retrieve block children before appending to avoid structural disasters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Right block type.&lt;/strong&gt; Callouts for decisions. Toggles for details. Headings for structure. Not everything is a paragraph.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structure intentionally.&lt;/strong&gt; Measure twice, cut once. 🤣&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How I Used Notion MCP
&lt;/h2&gt;

&lt;p&gt;Let me tell you how this actually works.&lt;/p&gt;

&lt;p&gt;mcporter connects Escriber to Notion's official MCP server at &lt;code&gt;https://mcp.notion.com/mcp&lt;/code&gt;. Every tool call gets proxied through that relay — no direct API wrangling, no custom request builders. The MCP layer handles it. Escriber just speaks tool.&lt;/p&gt;

&lt;p&gt;Here is what that looks like day-to-day:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New project starts?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;create_page&lt;/code&gt; to spin up the project hub. &lt;code&gt;create_database_item&lt;/code&gt; to log it in the master projects database. Done in seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wrapping up a build session?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;append_block_children&lt;/code&gt; to the existing project page. Build notes, decisions made, what broke, what did not. Structured. Timestamped. Actually findable later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JB's Job Listings&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;create_page&lt;/code&gt; My recruiter agent stored a list of jobs using Esciber every morning. Future-me will be grateful. Past-me was not doing this. These are stored in Notion daily, and sortable ☠️&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.amazonaws.com%2Fuploads%2Farticles%2Fovb6o0k3zyg65x5m1diu.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fovb6o0k3zyg65x5m1diu.png" alt="Notion Job Notes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let me tell you about the shame moment that made this real.&lt;/p&gt;

&lt;p&gt;I went back through my own Notion workspace a few weeks ago. Pages with titles like "ideas v3 FINAL" and "project notes DO NOT DELETE" containing exactly… three bullet points and a YouTube link. That is it. That is the legacy. A graveyard of good intentions. ☠️&lt;/p&gt;

&lt;p&gt;Escriber exists because I needed someone with more documentation discipline than me. Turns out that someone is a focused AI agent with a soul file and 14 Notion tools.&lt;/p&gt;

&lt;p&gt;One job. One lane. Real personality. And the docs actually get written now.&lt;/p&gt;

&lt;p&gt;"Optimization starts with a single point of failure—or a single point of success. Own the lane."&lt;/p&gt;

&lt;p&gt;Also, thanks to Bloggy, for taking the time to help with this post. &lt;/p&gt;




&lt;p&gt;&lt;em&gt;Escriber is part of my OpenClaw agent team. If you are curious about building multi-agent setups in openclaw, drop a comment — I am writing more about this whole stack as it comes together.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>notionchallenge</category>
      <category>mcp</category>
      <category>ai</category>
    </item>
    <item>
      <title>🤑 TCG: Price for Everyone 🤑</title>
      <dc:creator>John A Madrigal</dc:creator>
      <pubDate>Sun, 01 Mar 2026 21:25:33 +0000</pubDate>
      <link>https://forem.com/trickell/a-price-for-everyone-123k</link>
      <guid>https://forem.com/trickell/a-price-for-everyone-123k</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/weekend-2026-02-28"&gt;DEV Weekend Challenge: Community&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Community 👥
&lt;/h2&gt;

&lt;p&gt;I'm an avid card player. You know, the kind that used to play once a week, and now maybe 5 times a year 🤭 I started playing Magic the Gathering back in High School when Invasion was dropping. We would go to the top of the gym, and use gymnastic stacked mats to play Magic all the time, crack new packs, and have the thrill of getting a foil. Cracking packs of Magic used to be so fun, knowing you might get a rare foil, or some interesting mythic. Recently Magic has kind have let my friends and I down. With them releasing IP's like TMNT, SpiderMan, and others, and with foils being in every pack, cracking a pack does not feel special anymore.&lt;/p&gt;

&lt;p&gt;Come Sorcery: Contested Realm, a card game that has that exact same thrill of opening packs and getting a foil maybe 1 out of 6 packs. What makes cracking packs so fun, is getting that single rare card, or a curiosa, that could have HUGE value. This game is in it's early stages too, but it has cards valued at over $1,000~ 🤑 (Curiousas, Rare Foils) in the game already!&lt;/p&gt;

&lt;p&gt;Most people who collect TCG cards of value, often know about TCGPlayer.com. This site holds the standard when it comes to priced TCG cards on the market.  Sorcery: Contested Realm price data is already on this website. Sorcery also has it's own website for card information, deck building, and collection management. So what's the issue?&lt;/p&gt;

&lt;p&gt;Let's go with S:CR (Sorcery: Contested Realm) for the rest of this entry. S:CR's website Curiosa.io is an incredible website. But some friends and I have always wanted to be able to price our collection and decks. I mean how cool would that be?! To be able to check our collection and see how "rich" 😆 we are. But in all honesty, I always thought it would be cool if curiousa.io built a way to check the price of each deck and keep up with your collection value.&lt;/p&gt;



&lt;h2&gt;
  
  
  What I Built 👾
&lt;/h2&gt;



&lt;p&gt;Big brain thought. Why not just do exactly this ourselves?! The ability to have price information and total value information on the website would be absolutely incredible. This site has been out 2+ years and no one has created anything to allow this. &lt;/p&gt;

&lt;p&gt;So, let's go through the "app" I built (😵‍💫,😤,😂). I've been trying to think of ways I could implement this into our community of Sorcery card players and wanted this tool for everyone. Since TCGPlayer and Curiousa.io both run on react / virtual DOM's, the way it loads information makes it almost impossible to scrape. So how can we scrape price data information on TCGPlayer?&lt;/p&gt;

&lt;p&gt;In comes &lt;strong&gt;MutationObserver&lt;/strong&gt;. I had never thought to use this. After an several attempts on my own trying to figure out how to scrape the data, I had CoPilot help me understand the process of how TCGPlayer loads it's data and how I could grab that information. With &lt;strong&gt;MutationObserver&lt;/strong&gt;, it observes the DOM and waits for certain data to appear before starting itself.&lt;/p&gt;

&lt;p&gt;Now that we got how we're going to scrape the data, how are we going to create this as something that will scrape the data, match data on a page, and inject data into that page? A Chrome Extension!! And my very first time creating an extension in Chrome. &lt;/p&gt;

&lt;p&gt;In building the Chrome Extension, I learned how to create a manifest for Chrome Extension environments, and how a file structure works for Extensions. I think one of the coolest things about Extensions, is how you can just refresh the extension and it grab the newest bit of code with new versions. So let's break down the versions.&lt;/p&gt;




&lt;p&gt;1.0.1 - Users have to scrape TCGPlayer for data, built inside the extension, link for scraping and all. Can see price data only for decks on Curiousa.io, card names are matching and price injection is happening. But at the moment, it's not accurate. We are just pulling the first card Name we see, not considering foils and Alpha/Beta same cards. &lt;/p&gt;




&lt;p&gt;1.0.2-5 - Can see price data now accurate for versions "Alpha/Beta". Let me tell you, and excuse my french, but that was a bitch to handle. So the way Curiousa.io works is by tRPC Batch Requests. With the extension I had to intercept the fetch request, create the same exact request for card information, and match the data for the set it's under. The set is shown when you click on a card, so I also had to setup the code to automate the clicks, give a loading screen, then inject the price data correctly.&lt;/p&gt;




&lt;p&gt;1.0.6 - Now we have foils pulling in, very nicely as well. They have this nice yellow badge on the card name along with the price and all cards are now injecting correct set pricing. &lt;/p&gt;




&lt;p&gt;1.0.7 - Added Total cards and Total value of each deck to the top of the deck.&lt;/p&gt;




&lt;p&gt;1.0.8 - Created a collection value and used the same name match and price injection to show correct information within the collection.&lt;/p&gt;




&lt;p&gt;1.0.9 - Created a link to TCGPlayer.com on the price badge someone can click on to go to the card price information on TCGPlayer.com&lt;/p&gt;




&lt;p&gt;1.0.10 - Finessed the wording for the plugin, tested to make sure all price data was matching correctly in both decks and collection, and optimized the code some.&lt;/p&gt;




&lt;p&gt;1.1.0 - Created a .crx file extension for testing. &lt;/p&gt;

&lt;p&gt;Note: So each user has to scrape the data manually each time to get updated prices and card information from TCGPlayer. I was afraid to hit TCG with tons of scrape data daily from each extension being loaded in Chrome, so I made the scraping happen manually.&lt;/p&gt;



&lt;h2&gt;
  
  
  Demo 🎥
&lt;/h2&gt;



&lt;p&gt;This is a video demo of the Sorcery Extension being live used.&lt;br&gt;


  &lt;iframe src="https://www.youtube.com/embed/NCxqKleLHp0"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;



&lt;h2&gt;
  
  
  Code 🧬
&lt;/h2&gt;



&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/trickell" rel="noopener noreferrer"&gt;
        trickell
      &lt;/a&gt; / &lt;a href="https://github.com/trickell/sorcery_data_scraper" rel="noopener noreferrer"&gt;
        sorcery_data_scraper
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🔮 Sorcery Price Tracker — Chrome Extension&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Automatically displays TCGPlayer market prices for &lt;strong&gt;Sorcery: Contested Realm&lt;/strong&gt; cards on &lt;a href="https://curiosa.io" rel="nofollow noopener noreferrer"&gt;Curiosa.io&lt;/a&gt;, including deck totals.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;File Structure&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;sorcery-price-tracker/
├── manifest.json          # Extension config + permissions
├── background.js          # Service worker: storage, canonical names, messaging
├── content_tcgplayer.js   # Scraper: runs on TCGPlayer, collects card prices
├── content_curiosa.js     # Injector: runs on Curiosa.io, displays prices
├── popup.html             # Extension popup UI
├── popup.js               # Popup logic
└── icons/                 # Add icon16.png, icon48.png, icon128.png here
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Setup&lt;/h2&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Open Chrome and go to &lt;code&gt;chrome://extensions&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;Developer Mode&lt;/strong&gt; (top right toggle)&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Load unpacked&lt;/strong&gt; and select this folder&lt;/li&gt;
&lt;li&gt;The extension icon will appear in your toolbar&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How to Use&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Step 1 — Scrape Prices from TCGPlayer&lt;/h3&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Click the extension icon → &lt;strong&gt;"Open TCGPlayer to Scrape"&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The TCGPlayer Sorcery listings page will open&lt;/li&gt;
&lt;li&gt;Scroll through the results — prices are saved automatically as cards load&lt;/li&gt;
&lt;li&gt;Navigate to page 2…&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/trickell/sorcery_data_scraper" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;




&lt;p&gt;Here is a sample of the code I used to scrape TCGPlayer.com website for card data.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;content_tcgplayer.js&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function observeDOM() {
    const observer = new MutationObserver(() =&amp;gt; {
      clearTimeout(debounceTimer);
      debounceTimer = setTimeout(tryScrape, DEBOUNCE_MS);
    });
    observer.observe(document.body, { childList: true, subtree: true });
  }

  function tryScrape() {
    const results = scrapeCurrentPage();
    const count = Object.keys(results).length;
    if (count === 0) return;

    scrapedOnThisPage = true;
    const slug = getSetSlugFromUrl();
    updateBanner(`Scraped ${count} entries from ${getSetDisplayName(slug)} — saving...`);

    chrome.runtime.sendMessage(
      { type: 'SAVE_PRICES', payload: results },
      (response) =&amp;gt; {
        if (response?.success) {
          updateBanner(`${getSetDisplayName(slug)}: ${count} entries saved (${response.count} total). Open another set's price guide to continue.`);
        }
      }
    );
  }

  // ─────────────────────────────────────────────
  // Scrape the price guide table.
  // Captures card name, price, AND the TCGPlayer
  // url from the card.
  // ─────────────────────────────────────────────
  function scrapeCurrentPage() {
    const prices = {};
    const slug = getSetSlugFromUrl();
    const setDisplayName = getSetDisplayName(slug);

    const rows = document.querySelectorAll('.tcg-table-body tr');
    if (rows.length === 0) return prices;

    rows.forEach((row) =&amp;gt; {
      const nameEl = row.querySelector('.pdp-url');
      const cells  = row.querySelectorAll('.tcg-table-body__cell');

      if (!nameEl || cells.length &amp;lt;= PRICE_COLUMN_INDEX) return;

      const rawName  = nameEl.innerText?.trim();
      const rawPrice = cells[PRICE_COLUMN_INDEX]?.innerText?.trim();

      if (!rawName || !rawPrice) return;
      if (rawPrice === '-' || rawPrice === '' || rawPrice === 'N/A') return;

      const priceFloat = parseFloat(rawPrice.replace(/[^0-9.]/g, ''));
      if (isNaN(priceFloat) || priceFloat === 0) return;

      // Capture the TCGPlayer PDP URL from the anchor tag
      const href = nameEl.href || nameEl.closest('a')?.href || null;
      const pdpUrl = href &amp;amp;&amp;amp; href.startsWith('http') ? href : null;

      const foil = isFoilName(rawName);
      const baseName = foil ? stripFoilSuffix(rawName) : rawName;

      const priceObj = {
        display:   rawPrice,
        value:     priceFloat,
        set:       setDisplayName,
        setSlug:   slug,
        foil:      foil,
        url:       pdpUrl,
        source:    'tcgplayer',
        scrapedAt: Date.now(),
      };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;observeDOM() - This will open a new MutationObserver to watch the body of the page.&lt;/li&gt;
&lt;li&gt;tryScrape() - This will create a small banner modal on the bottom of the screen, updating it's value, show the data being scraped, and showing the exact amount of entries stored.&lt;/li&gt;
&lt;li&gt;scrapeCurrentPage() - When on TCGPlayer.com it will attempt to scrape the data base on this method and if the classes begin to match it'll auto-scrape the page if the extension is on.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So there's a better understanding of the file structure here is how I created the file structure for this extension:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;manifest.json = Loads the extension data for Chrome&lt;/li&gt;
&lt;li&gt;background.js = Runs in background, using SorceryAPI, to pull card data.&lt;/li&gt;
&lt;li&gt;content_curiosa.js = Runs when on Curiosa.io website&lt;/li&gt;
&lt;li&gt;content_tcgplayer.js = Runs when on TCGPlayer.com&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How I Built It 🛠️
&lt;/h2&gt;

&lt;p&gt;The way I created the extension was simply with Javascript. It's the only thing it needed. I also used Claude Sonnet in browser to help me understand the way TCGPlayer loaded it's data and the way Curiousa.io was fetching it's card information through tRCP requests.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Coding Challenges in the Modern Time</title>
      <dc:creator>John A Madrigal</dc:creator>
      <pubDate>Thu, 12 Feb 2026 18:41:26 +0000</pubDate>
      <link>https://forem.com/trickell/coding-challenges-in-the-modern-time-1mi9</link>
      <guid>https://forem.com/trickell/coding-challenges-in-the-modern-time-1mi9</guid>
      <description>&lt;h2&gt;
  
  
  Next challenge in 3... 2... 1...
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;John, you have 6 hours to complete this challenge.&lt;/strong&gt; Give us a typescript / react.js shopfront using Shopify's GraphQL api, using motion.js library, and building off our next.js framework.&lt;/p&gt;

&lt;p&gt;Let me tell you, writing foo bar challenges in interviews has moved up to next level code structure, popping designs, and structured deployment. If you think this is going to be a bashing post on interview structures, your wrong.... but your also right 🫨&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.amazonaws.com%2Fuploads%2Farticles%2Fa3ivzitrpwemwb8htij1.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fa3ivzitrpwemwb8htij1.png" alt="Coding Challenge Hell" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The game has definitely stepped up for what companies now expect from senior level and even junior level developers. 👨‍🎓 Junior level devs are now expected to know as much as a senior level developer. &lt;/p&gt;




&lt;p&gt;I think this is both good and bad. 🫩 Let's start with the "bad". I wouldn't consider it bad per say, as much as creating a difficult environment for the end user. It makes it more difficult for programmers that are used to using older technologies and languages to move into what most front end stacks are now on, and schools really don't prep you for the AI war when it comes to finding a job and getting your resume past AI.&lt;/p&gt;

&lt;p&gt;There is a lot of good in the challenge though. 😃 I've always enjoyed learning and keeping up to date with modern tech. So let's talk about how this coding challenges help push us, show us where we fall short in languages, frameworks, and tools, and give us a reason to learn more about the modern tools being used among teams.&lt;/p&gt;




&lt;p&gt;When your a self taught learner and working on small projects, it's more common to use tools that are made for smaller projects and to KISS (Keep it simple stupid) 😵‍💫. If it wasn't for this last coding challenge I would have never looked into GraphQL and found use for a good tool to use on API's. I've used motion.js in a single project, but never as much as I did in this last coding challenge. And I'm starting to see types more clearly in type script and how the restrictions in JavaScript start to become better for deployment and for code catching in VSCode. &lt;/p&gt;

&lt;p&gt;It's also these code challenges that force us to try new tools when we other wise wouldn't have touched. Because of &lt;strong&gt;DEV Challenges&lt;/strong&gt;, I've now messed with &lt;strong&gt;Antigravity, Github CLI, N8N,&lt;/strong&gt; and other interesting tools that I would have not touched if so. I like the journey each challenge brings and I find them quite rewarding when completed. &lt;/p&gt;



&lt;h2&gt;
  
  
  The Future and What It Holds
&lt;/h2&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.amazonaws.com%2Fuploads%2Farticles%2Fajcvs9nbmwaom6ojtt4l.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fajcvs9nbmwaom6ojtt4l.png" alt="Future Challenges" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These coding challenges help prep you for the next challenge to come and it helps keep us pushing past and against the current into something hopefully pretty incredible. 👽 I've been coding now since 2003, my senior year in high school. And even if the tide has changed, and the languages have shifted, I will fight the waves, steady the ship, and keep sailing into the sea looking for a land, a spot, to settle at. &lt;/p&gt;

&lt;p&gt;Don't give in to the challenge and the difficulty it might bring. &lt;strong&gt;Keep moving forward&lt;/strong&gt; and know that with each challenge, each project, and each action to produce more code, &lt;strong&gt;you will make it&lt;/strong&gt;! And prompt boy, don't settle on AI. Dig deep into the structure and figure out how the engine works. &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>ai</category>
    </item>
    <item>
      <title>The Deployment From Hades</title>
      <dc:creator>John A Madrigal</dc:creator>
      <pubDate>Sat, 10 Jan 2026 22:34:05 +0000</pubDate>
      <link>https://forem.com/trickell/the-deployment-from-hades-3064</link>
      <guid>https://forem.com/trickell/the-deployment-from-hades-3064</guid>
      <description>&lt;p&gt;_&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/new-year-new-you-google-ai-2025-12-31"&gt;New Year, New You Portfolio Challenge Presented by Google AI&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About Me
&lt;/h2&gt;

&lt;p&gt;My name is John and I come from the era when everyone used stackoverflow 😆. This is my journey of not only building version 2 of my portfolio, but also the hell that came later when deploying to google cloud for the first time. Btw, Google Cloud is a great tool, this is user issue. &lt;/p&gt;

&lt;p&gt;Receiving this error after creating a docker file for my google cloud project: &lt;br&gt;
&lt;code&gt;ERROR: (gcloud.run.services.update) The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable within the allocated timeout. This can happen when the container port is misconfigured or if the timeout is too short. The health check timeout can be extended. Logs for this revision might contain more information.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This error pretty much defines 5 hours of my life and how I missed simple logging that could have saved my ass! &lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;



&lt;p&gt;I'm always getting nudged by my significant other to do these dev challenges and I've been wanting to rebuild my website in react with a three.js background. This being an Google AI challenge, I figured I would go head deep into this stack. I started by downloading Antigravity, a glorified VSCode with Google AI Studio built in. After downloading, with 0 thought, I crafted a simple prompt to make this happen:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Download my website from &lt;a href="https://www.madrigal.design" rel="noopener noreferrer"&gt;https://www.madrigal.design&lt;/a&gt;, and redesign the website into a react.js stack. Clean up the website and modernize the code. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's just say it did an absolute abominable job in recreating the code. I really wish I had the screenshots from this. Move past how bad it did, I ended up deciding to try it again, but inside my folder with all the code I had originally created.&lt;/p&gt;

&lt;p&gt;This time, Antigravity had actually generated something very useable almost right off the top. Using Antigravity and it's built in AI, it first built the project in vanilla Javascript and CSS, which looked nice but I personally wanted it in react. I reprompted it to be built in react and it did a pretty incredible job. This saved me a lot of time, but definitely added a little bit of bloat, all which I'd return to the code to slash out. &lt;/p&gt;

&lt;p&gt;I haven't had the time to really learn Three.js, which I absolutely would love to spend some time in at some point. I knew I wanted my background redone in Three.js and I think this is where AI and learning can shine. I prompted the AI to create a particle wave background showing rippling patterns of color and to make it minimal.&lt;/p&gt;

&lt;p&gt;After about 3 more prompts updating the colors to fit my website, I was actually pretty amazed at how well it did and was quite impressed at how little code it took to make a background like this happen. I did this also with my creations and projects section, going back in the code and redoing it to make a carousel I wanted to see my projects on. It was nice to have studio, not as a crutch, but as a way to speed things up and learn how Three.js is implemented. &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.amazonaws.com%2Fuploads%2Farticles%2Fdti70dlo22we4bv8jjmb.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fdti70dlo22we4bv8jjmb.png" alt="Three.js Backkground"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wanted something different for my site as well. Maybe there's a little bit of chaos hidden within the website. THIS IS A WARNING! Be sure to press the Stop Chaos! button when the time comes.&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment from Hell ☠️
&lt;/h2&gt;

&lt;p&gt;Fast forward to the finished portfolio, it's now time to deploy it. I got my google cloud set up was tapping at my desk like the happiest kid on earth, excited to get my website up and deployed ☺️. I opted to do the GitHub Repository continuous deployment where when the server see's a new commit pushed, it'll auto deploy the most current and up to date code on the repository. &lt;/p&gt;

&lt;p&gt;This is the first time I encountered an error that would be the bane of my existence.&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.amazonaws.com%2Fuploads%2Farticles%2Fygenr29og3q5tklulls8.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fygenr29og3q5tklulls8.png" alt=" "&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Receiving this error after creating a docker file for my Google Cloud project: ERROR: (gcloud.run.services.update) The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable within the allocated timeout. This can happen when the container port is misconfigured or if the timeout is too short. The health check timeout can be extended. Logs for this revision might contain more information.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is where it started to become annoyingly nasty and where trusting AI instead of logs, failed me. Bad habits can form quick, so I used Google Gemini to try and help me with this error. Why not? Antigravity did such a great job, this IS Google Cloud we are using, so it should be able to fix a product of they're own very quickly. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/TJawtKM6OCKkvwCIqX/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img width="100%" src="https://i.giphy.com/media/TJawtKM6OCKkvwCIqX/giphy.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Prompt after prompt, deployment after deployment, I was continuing to still get same error. Why? I've done what you've told me! I've followed your every command google, so why am I still receiving this?! 🤣😵‍💫&lt;/p&gt;

&lt;p&gt;I'm usually not this trusting in AI, but some how I got a little out of control. 🤪 After about 13 failed deployments, I decided to give it 24 hours and to come back to the code.&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.amazonaws.com%2Fuploads%2Farticles%2Faoglmc6lms74x7dfz35a.png" 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.amazonaws.com%2Fuploads%2Farticles%2Faoglmc6lms74x7dfz35a.png" alt="Failed Attempts"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  48 Hours Later
&lt;/h2&gt;

&lt;p&gt;48 hours later (yes, i needed some time) I hopped back in and this time, my significant other nudged me this time to check the logs and we looked at them together. She noticed something wrong when it came to Vite being built, so we dropped this into Google Gemini to see if we could get an answer.&lt;/p&gt;

&lt;p&gt;At first I saw and thought, SAME error! 😱 But because we are now checking the logs, we can tell it is truly a different error. The Vite issue was fixed and the way serve was being called was incorrect. After fighting with it a few more deploys later, SUCCESS. Finally! I can breathe. And let me tell you, I gave off the hugest sigh of relief. &lt;/p&gt;

&lt;p&gt;Serve Error&lt;br&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.amazonaws.com%2Fuploads%2Farticles%2F5ae25pn71fbi881okap5.png" 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.amazonaws.com%2Fuploads%2Farticles%2F5ae25pn71fbi881okap5.png" alt="Serve Error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Succession!!!&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.amazonaws.com%2Fuploads%2Farticles%2Fidd66448d7zzkv7xwxav.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fidd66448d7zzkv7xwxav.png" alt="Build Success!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Honestly, I wasn't even sure that it was real, haha 🫣. After all the fighting, I was just waiting for something else to break or be wrong. But it was running, and correctly at that.&lt;/p&gt;

&lt;p&gt;After finally resolving the issue, I then created and pointed a subdomain  to google cloud using there domain mapping. After giving it time to process, my new domain and new site was finally live on cloud. &lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Portfolio
&lt;/h2&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag__cloud-run"&gt;
  &lt;iframe height="600px" src="https://v2-madrigaldesign-101268853896.europe-west1.run.app"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;





&lt;p&gt;Let this be a lesson to use and debug with logs to start, and to also understand that AI can be a useful tool for learning and quick coding when done in a proper manner.&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm Most Proud Of
&lt;/h2&gt;



&lt;p&gt;I needed this update for myself and it was enjoyable to play with new tools, new stacks, and do something different. Antigravity was a fun, juiced up version, of vscode to play with and being able to produce a website with Three.js inside my editor in the stack I wanted was nice to try, see, and learn. I think the Three.js background is what really stood out to me in this rebuild. Thanks to the DEV community and there competitions for this.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>googleaichallenge</category>
      <category>portfolio</category>
      <category>gemini</category>
    </item>
    <item>
      <title>Spooky Halloween!</title>
      <dc:creator>John A Madrigal</dc:creator>
      <pubDate>Sun, 26 Oct 2025 15:15:27 +0000</pubDate>
      <link>https://forem.com/trickell/spooky-halloween-2je7</link>
      <guid>https://forem.com/trickell/spooky-halloween-2je7</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/frontend-2025-10-15"&gt;Frontend Challenge - Halloween Edition, CSS Art&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspiration
&lt;/h2&gt;

&lt;p&gt;Inspiration? The "inspiration" for this project came mostly from my girlfriend being like "CSS CHALLENGE! LET'S DO!". My thought process is sure, coding with the girlfriend, why not. But on a deeper note, in the back of my head I knew I hadn't really done any pure CSS drawings with animations and this challenge would be a perfect bridge to have some fun with css code and bring some artistic skills out. I already enjoy learning GLSL, so why not play with a language we already know! &lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;

&lt;iframe height="600" src="https://codepen.io/trickell-trickell/embed/NPxMboq?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;


&lt;/p&gt;

&lt;h2&gt;
  
  
  Journey
&lt;/h2&gt;

&lt;p&gt;As much as I would have loved to document every step with images for everyone to see, I'm just gonna summarize the entire experience. This will be a small first post from me! &lt;/p&gt;

&lt;p&gt;First off, this is the first time I've ever used the -webkit-box-reflect and I found it surprisingly useful, especially for drawing. I found myself  wishing at times i would use js for looping some stuff, but wanted to push myself to see what I could do in pure css. I found it pretty amazing what css has grown into and how much it has been updating.&lt;/p&gt;

&lt;p&gt;This entire submission started honestly as a simple ghost that kept growing into this animated simplistic art piece. Here is how it started, without animation:&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.amazonaws.com%2Fuploads%2Farticles%2Ft4kyo0w5rjjch9fburbc.png" 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.amazonaws.com%2Fuploads%2Farticles%2Ft4kyo0w5rjjch9fburbc.png" alt="Starting Point"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Projects like these are such a great tool for learning and diving deeper into what code like this can really make happen. So many great submissions already, here's just another one for the pool of great artists on here already!&lt;/p&gt;

&lt;p&gt;This wasn't a team post but I wanna thank &lt;a href="https://dev.to/annavi11arrea1"&gt;Anna Villarreal&lt;/a&gt; for giving me a nudge to make this. Btw, go check her css art submission out, it's really amazing!&lt;/p&gt;

</description>
      <category>frontendchallenge</category>
      <category>devchallenge</category>
      <category>css</category>
    </item>
  </channel>
</rss>
