<?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: Wilhelm Tell</title>
    <description>The latest articles on Forem by Wilhelm Tell (@wilhelm_tell).</description>
    <link>https://forem.com/wilhelm_tell</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%2F2637541%2Fc8a6dc84-8775-4ed4-b7dc-0fb4fea2d61a.jpg</url>
      <title>Forem: Wilhelm Tell</title>
      <link>https://forem.com/wilhelm_tell</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/wilhelm_tell"/>
    <language>en</language>
    <item>
      <title>Worth your time for AI developers (and vibe coders) to learn the basics of LLM integration techniques.</title>
      <dc:creator>Wilhelm Tell</dc:creator>
      <pubDate>Sat, 14 Mar 2026 18:24:33 +0000</pubDate>
      <link>https://forem.com/wilhelm_tell/worth-your-time-for-ai-developers-and-vibe-coders-to-learn-the-basics-of-llm-integration-2dlf</link>
      <guid>https://forem.com/wilhelm_tell/worth-your-time-for-ai-developers-and-vibe-coders-to-learn-the-basics-of-llm-integration-2dlf</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/klement_gunndu/why-your-ai-agent-forgets-everything-and-how-to-fix-it-2gj8" class="crayons-story__hidden-navigation-link"&gt;Why Your AI Agent Forgets Everything (And How to Fix It)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/klement_gunndu" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F3786236%2Fe2629efd-63ba-4d1b-83d8-b55db5d86b58.jpeg" alt="klement_gunndu profile" class="crayons-avatar__image" width="800" height="702"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/klement_gunndu" class="crayons-story__secondary fw-medium m:hidden"&gt;
              klement Gunndu
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                klement Gunndu
                
              
              &lt;div id="story-author-preview-content-3277282" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/klement_gunndu" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F3786236%2Fe2629efd-63ba-4d1b-83d8-b55db5d86b58.jpeg" class="crayons-avatar__image" alt="" width="800" height="702"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;klement Gunndu&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/klement_gunndu/why-your-ai-agent-forgets-everything-and-how-to-fix-it-2gj8" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Feb 23&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/klement_gunndu/why-your-ai-agent-forgets-everything-and-how-to-fix-it-2gj8" id="article-link-3277282"&gt;
          Why Your AI Agent Forgets Everything (And How to Fix It)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/python"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;python&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/langchain"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;langchain&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/tutorial"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;tutorial&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/klement_gunndu/why-your-ai-agent-forgets-everything-and-how-to-fix-it-2gj8" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;3&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/klement_gunndu/why-your-ai-agent-forgets-everything-and-how-to-fix-it-2gj8#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              5&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            11 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ai</category>
      <category>python</category>
      <category>langchain</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I Plugged Gemini Into My 10,000-Line Rental Platform. Here's What Happened.</title>
      <dc:creator>Wilhelm Tell</dc:creator>
      <pubDate>Tue, 03 Mar 2026 00:18:39 +0000</pubDate>
      <link>https://forem.com/wilhelm_tell/i-plugged-gemini-into-my-10000-line-rental-platform-heres-what-happened-2epi</link>
      <guid>https://forem.com/wilhelm_tell/i-plugged-gemini-into-my-10000-line-rental-platform-heres-what-happened-2epi</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/mlh-built-with-google-gemini-02-25-26"&gt;Built with Google Gemini: Writing Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built with Google Gemini
&lt;/h2&gt;

&lt;p&gt;BorrowHood is a neighborhood sharing platform I built from a camper van in Trapani, Sicily. 10,000+ lines of Python. 100+ REST endpoints. 30+ database models. Keycloak authentication. Weighted reputation system where a Legend's review counts 10x more than a Newcomer's. Auctions with anti-snipe protection. CEFR language proficiency matching so expats can find neighbors who speak their language.&lt;/p&gt;

&lt;p&gt;I built the platform with Claude Code. Some demo videos on YouTube. A live instance on Hetzner FOR EXAMPlE: &lt;a href="https://46.62.138.218/demo-login" rel="noopener noreferrer"&gt;https://46.62.138.218/demo-login&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then I saw the Gemini writing challenge and thought: what if I added a brain?&lt;/p&gt;

&lt;p&gt;Not replacing anything. Adding an intelligence layer on top of what already exists. &lt;strong&gt;Three AI agents powered by Google Gemini&lt;/strong&gt;, using Google's Agent Development Kit (ADK), talking to my production API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent 1: Smart Listing Assistant
&lt;/h3&gt;

&lt;p&gt;User says "I want to list a Bosch power drill." Gemini searches existing items on the platform for price comparison, checks the 31 valid categories, and generates a complete listing:&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;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bosch GSB 18V Cordless Impact Drill"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"My trusty Bosch GSB 18V cordless impact drill is looking
    for a new adventure! It's been with me for about two years and is still
    in good working condition, perfect for all your home improvement projects."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"power_tools"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"subcategory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"drills"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"good"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"suggested_price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;8.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"price_unit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"per_day"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"deposit_suggestion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;24.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tags"&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;"power drill"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bosch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cordless drill"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"story_suggestion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This drill has helped me hang countless shelves and
    assemble quite a few IKEA nightmares -- it's a real workhorse!"&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;That story suggestion? The agent came up with "IKEA nightmares" on its own. I call this the Grandma Test: if an 83-year-old in a wheelchair can understand your listing description, it passes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent 2: Review Sentiment Analyzer
&lt;/h3&gt;

&lt;p&gt;Ask "Analyze Sally Thompson's reviews" and Gemini pulls all her reviews from the API, checks the reviewer's badge tier (because a review from a PILLAR member carries 8x the weight of a NEWCOMER), and returns:&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;"user_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sally Thompson"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"badge_tier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"trusted"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sentiment"&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;"positive"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"neutral"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"negative"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&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;"average_rating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"weighted_average"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fake_review_flags"&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;"No fake review indicators detected"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"top_keywords"&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;"positive"&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;"immaculate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"changed my life"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"focaccia"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pro"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"negative"&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="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sally Thompson, a TRUSTED tier member, has an excellent
    reputation on BorrowHood. Her single review, from a highly influential
    PILLAR member, praises her KitchenAid stand mixer as 'immaculate'."&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;The agent understood the weighted reputation system without me hardcoding any analysis logic. It figured out that one review from a PILLAR member means more than five reviews from newcomers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent 3: AI Concierge
&lt;/h3&gt;

&lt;p&gt;Natural language search. "I need something to cut tree branches" becomes an API search for garden tools, power tools, and saws. When nothing matches, the concierge responds like a neighbor, not a search engine:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I'm sorry, I couldn't find any listings for tree-cutting tools right now. Would you like to try searching for 'garden tools' or 'power tools'? Or perhaps you have a different type of cutting tool in mind?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The Root Orchestrator
&lt;/h3&gt;

&lt;p&gt;One agent routes everything. Listing questions go to the Listing Assistant. Reputation questions go to the Review Analyzer. Search queries go to the Concierge. General BorrowHood questions, it answers directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;root_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-2.5-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;borrowhood_agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;sub_agents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;listing_assistant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;review_analyzer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;concierge&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;Four lines of code to wire three specialists into one brain.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/akenel/borrowhood" rel="noopener noreferrer"&gt;github.com/akenel/borrowhood&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://46.62.138.218/demo-login" rel="noopener noreferrer"&gt;BorrowHood Demo Login&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;YouTube playlist:&lt;/strong&gt; &lt;a href="https://youtube.com/playlist?list=PLxrmR3LJOIZ7cgPBMZjIRrKJPXHrCbR0b" rel="noopener noreferrer"&gt;BorrowHood: The Garage Sessions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The agents sit in the &lt;code&gt;agents/&lt;/code&gt; directory of the repo and call the same REST API that the web frontend uses. No special database access. No coupling. The intelligence layer sits on top of the platform, not inside it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BorrowHood (FastAPI, 100+ endpoints)
    |
    +-- agents/
    |   +-- agent.py             (root orchestrator)
    |   +-- listing_assistant.py
    |   +-- review_analyzer.py
    |   +-- concierge.py
    |   +-- tools/
    |       +-- items.py         (search_items, get_categories)
    |       +-- reviews.py       (get_user_reviews, get_review_summary)
    |       +-- users.py         (search_members, get_user_profile)
    |       +-- common.py        (auth, HTTP helpers)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tools are plain Python functions that wrap &lt;code&gt;httpx&lt;/code&gt; calls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;search_items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Search BorrowHood items by keyword and optional category.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;q&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;limit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;category&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;bh_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/api/v1/items&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ADK automatically introspects the function signature and docstring, presenting them as tool descriptions to Gemini. The model decides when to call which tool based on the user's query. Zero prompt engineering for tool selection.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;1. The ADK is genuinely good.&lt;/strong&gt; I expected boilerplate. I got four lines to wire three agents. The &lt;code&gt;Agent&lt;/code&gt; class, &lt;code&gt;sub_agents&lt;/code&gt; for delegation, automatic tool introspection from function docstrings. This is how agent frameworks should work: code-first, no YAML, no visual builders.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;listing_assistant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-2.5-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;listing_assistant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;instruction&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You are a listing assistant for BorrowHood...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;search_items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get_categories&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;That is the entire agent definition. The instruction tells it what to do. The tools tell it what it can access. Done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Gemini understands context it was not trained on.&lt;/strong&gt; I told the Review Analyzer about BorrowHood's weighted reputation system: "NEWCOMER = 1x, ACTIVE = 2x, TRUSTED = 5x, PILLAR = 8x, LEGEND = 10x." In its analysis of Sally, it correctly noted that her single review from a PILLAR member "carries significant weight." It applied the weighting concept to the actual data and drew a conclusion. That is comprehension, not pattern matching.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Existing APIs are the perfect tool layer.&lt;/strong&gt; I did not need to write any new backend code. BorrowHood already had 100+ endpoints covering items, reviews, users, listings, and badges. The agents just needed thin wrapper functions that translate ADK tool calls into REST API requests. The entire tools layer is 150 lines of Python. If your app already has an API, you are 80% of the way to having an AI agent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Agent delegation beats one mega-agent.&lt;/strong&gt; My first instinct was one agent with all tools. Wrong. The root orchestrator with three specialists is cleaner, faster, and produces better results. Each specialist has a focused instruction and a small tool set. The root agent's only job is routing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Google Gemini Feedback
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Good
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;gemini-2.5-flash is fast and smart.&lt;/strong&gt; The Listing Assistant generated a complete, valid JSON listing in under 3 seconds. It picked the right category from 31 options. It suggested a fair rental price (EUR 8/day for a power drill) by checking similar items on the platform. It even wrote a story about "IKEA nightmares."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The ADK is excellent.&lt;/strong&gt; Minimal boilerplate. Python-native. Tool introspection from docstrings is a killer feature. Multi-agent delegation with &lt;code&gt;sub_agents&lt;/code&gt; just works. I went from zero to three working agents in under an hour.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tool use is reliable.&lt;/strong&gt; Gemini consistently called the right tools with the right parameters. When the Review Analyzer needed Sally's reviews, it first searched for "Sally Thompson" via &lt;code&gt;search_members&lt;/code&gt;, got her ID, then called &lt;code&gt;get_user_reviews&lt;/code&gt; and &lt;code&gt;get_review_summary&lt;/code&gt; with that ID. Multi-step tool chains work without babysitting.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Bad
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Free tier rate limits are punishing.&lt;/strong&gt; &lt;code&gt;gemini-2.5-flash&lt;/code&gt; free tier: 5 requests per minute, 20 requests per day. A single multi-agent query can burn 4-6 requests (root agent + sub-agent + tool calls + follow-up). I ran exactly 3 test queries before hitting the daily limit. For a developer evaluating whether to build on Gemini, 20 requests per day is not enough to finish a single testing session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New API key propagation is confusing.&lt;/strong&gt; I created a fresh project and API key. The first 5 minutes: every model returned &lt;code&gt;limit: 0&lt;/code&gt; errors. No requests allowed. No warning in the console. I had to wait blindly for quotas to propagate. A "your key is provisioning, try again in 5 minutes" message would save developers real confusion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Model naming is a moving target.&lt;/strong&gt; &lt;code&gt;gemini-1.5-flash&lt;/code&gt; returned 404. &lt;code&gt;gemini-2.0-flash&lt;/code&gt; hit rate limits. &lt;code&gt;gemini-2.5-flash&lt;/code&gt; worked. The API lists 16+ model variants including &lt;code&gt;gemini-3-flash-preview&lt;/code&gt; and &lt;code&gt;gemini-2.5-flash-lite&lt;/code&gt;. Which one should I use? The docs say &lt;code&gt;gemini-2.0-flash&lt;/code&gt; but the API disagreed. Clearer "use THIS model" guidance would help.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Ugly
&lt;/h3&gt;

&lt;p&gt;I have history with Gemini. 11 months ago, before I met Claude, I was learning AI with Gemini. It made mistakes that felt almost deliberate. Hallucinations in code that compiled but did the wrong thing. I had to stop using it entirely. That experience taught me what to look for in an AI coding partner, and ultimately led me to Claude Code by Anthropic which I use to build BorrowHood.&lt;/p&gt;

&lt;p&gt;Coming back to Gemini now through the ADK, I see real improvement. &lt;code&gt;gemini-2.5-flash&lt;/code&gt; is a different animal. It follows structured output instructions, calls tools correctly, and understands domain context from instructions alone. The 11-month gap shows.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Is Next
&lt;/h3&gt;

&lt;p&gt;BorrowHood has four more agents designed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cross-Language Matchmaker&lt;/strong&gt; -- Luna's 3D design files say "Needs: 3D printer." Jake's listing says "Compatible with: STL." The agent finds these matches across language barriers using CEFR proficiency data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Onboarding Wizard Agent&lt;/strong&gt; -- Walk new users through setting up their workshop via conversation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dispute Resolution Assistant&lt;/strong&gt; -- When a rental goes wrong, the agent reviews both sides and suggests fair resolution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Community Pulse Agent&lt;/strong&gt; -- Weekly digest of neighborhood activity.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The data model already supports all of this. The agents just need to be wired up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/akenel/borrowhood" rel="noopener noreferrer"&gt;BorrowHood&lt;/a&gt; is open source. Free as in freedom. No platform fees. Your data is yours.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Built from a camper van in Trapani, Sicily. Every neighborhood has a garage like his.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Tech stack: FastAPI, SQLAlchemy, Keycloak OIDC, PostgreSQL, Redis, Docker, Tailwind CSS, Alpine.js&lt;/em&gt;&lt;br&gt;
&lt;em&gt;AI: Google Gemini 2.5 Flash via ADK (agents), Claude Code by Anthropic (platform development)&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Hosting: Hetzner Cloud (EUR ~15/month)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>geminireflections</category>
      <category>gemini</category>
    </item>
    <item>
      <title>BorrowHood: Every Garage Becomes a Rental Shop</title>
      <dc:creator>Wilhelm Tell</dc:creator>
      <pubDate>Sun, 01 Mar 2026 21:37:01 +0000</pubDate>
      <link>https://forem.com/wilhelm_tell/borrowhood-every-garage-becomes-a-rental-shop-p70</link>
      <guid>https://forem.com/wilhelm_tell/borrowhood-every-garage-becomes-a-rental-shop-p70</guid>
      <description>&lt;h2&gt;
  
  
  The Community
&lt;/h2&gt;

&lt;p&gt;My father Albert was a hand-shovel landscaper in Switzerland from 1960 to 2020. His garage had 500 tools. When he passed, they sat there collecting dust. His neighbors still needed shovels, rakes, and chainsaws -- they just didn't know where to look.&lt;/p&gt;

&lt;p&gt;Craigslist is a wasteland. Facebook Marketplace is a data farm. Neither cares about your neighborhood.&lt;/p&gt;

&lt;p&gt;BorrowHood is for &lt;strong&gt;real neighborhoods&lt;/strong&gt; -- the people on your street who own a drill you need once, a stand mixer sitting idle, a welder gathering dust. Every user is a workshop. Every garage becomes a rental shop. Every kitchen becomes a bakery.&lt;/p&gt;

&lt;p&gt;The community I built for: &lt;strong&gt;neighbors who share things instead of buying things they'll use once.&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;A full-stack community rental and sharing platform where people list their underused tools, kitchen gear, equipment, and skills -- and neighbors borrow, rent, or trade. No middlemen. No fees. No algorithm deciding who sees what.&lt;/p&gt;

&lt;p&gt;Demo&lt;br&gt;
GitHub: github.com/akenel/borrowhood&lt;br&gt;
Live demo: BorrowHood Demo Login &amp;gt; &lt;a href="https://LaPiazza.app/demo-login" rel="noopener noreferrer"&gt;https://LaPiazza.app/demo-login&lt;/a&gt;&lt;br&gt;
YouTube playlist: BorrowHood: The Garage Sessions &amp;gt; &lt;a href="https://www.youtube.com/playlist?list=PLrRlgzUrqK1_hZPY_6xyogQxCVbEAQBKp" rel="noopener noreferrer"&gt;https://www.youtube.com/playlist?list=PLrRlgzUrqK1_hZPY_6xyogQxCVbEAQBKp&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Your browser will show a certificate warning on first visit -- the server uses a self-signed TLS certificate (no domain, just an IP). Click &lt;strong&gt;Advanced&lt;/strong&gt; &amp;gt; &lt;strong&gt;Proceed to site&lt;/strong&gt;. It only happens once.&lt;/p&gt;
&lt;/blockquote&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%2Fie4dlwtgiazvu5r32n47.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%2Fie4dlwtgiazvu5r32n47.png" alt="BorrowHood Home" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What it does
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Eight ways to share:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rent&lt;/strong&gt; -- borrow a drill for the weekend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sell&lt;/strong&gt; -- offload gear you don't need&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Give Away&lt;/strong&gt; -- free items, simplified claim flow, earns Generous Neighbor badge&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auction&lt;/strong&gt; -- competitive bidding with reserve prices and anti-snipe protection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commission&lt;/strong&gt; -- custom made-to-order items&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service&lt;/strong&gt; -- plumbing, tutoring, bike repair&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Training&lt;/strong&gt; -- teach a neighbor your skill&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offer&lt;/strong&gt; -- name your price / make an offer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Full rental lifecycle:&lt;/strong&gt;&lt;br&gt;
Request &amp;gt; Approve &amp;gt; Pickup (lockbox code) &amp;gt; Return (lockbox code) &amp;gt; Review &amp;gt; Complete. With security deposits, dispute resolution, and PayPal payments at every step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security deposits -- peer-to-peer insurance:&lt;/strong&gt;&lt;br&gt;
You lend your neighbor a EUR 2,000 drone. How do you know you get it back in one piece? The deposit. The owner sets the amount. The renter pays it at pickup. Bring it back in one piece -- deposit returned. Break it -- owner keeps the deposit. No insurance company. No paperwork. Just neighbors handling it themselves. If they disagree, the 3-step dispute resolution kicks in and the deposit follows the outcome automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reputation that means something:&lt;/strong&gt;&lt;br&gt;
15 badges across 5 tiers (Newcomer to Legend). Reviews are weighted by the reviewer's badge tier -- a Legend's 5-star review counts 10x more than a Newcomer's. Your reputation is earned, not gamed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bilingual from day one:&lt;/strong&gt;&lt;br&gt;
One click switches the entire app between English and Italian. Navigation, forms, badges, categories, filters, error messages -- 500+ translated strings, nothing left behind.&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%2Fzd1uylf46wzqxpbprzyn.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%2Fzd1uylf46wzqxpbprzyn.png" alt="Browse Items" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Feature highlights
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&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;Workshop profiles&lt;/td&gt;
&lt;td&gt;Every user is a shop with skills, CEFR language levels, social links&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auction system&lt;/td&gt;
&lt;td&gt;Timed bidding, auto-outbid notifications, reserve prices, bid increments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Giveaway flow&lt;/td&gt;
&lt;td&gt;Free items, simplified claim, no return dates, Generous Neighbor badge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lockbox codes&lt;/td&gt;
&lt;td&gt;One-time 8-character codes for contactless pickup and return&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security deposits&lt;/td&gt;
&lt;td&gt;Owner sets amount, hold at pickup, auto-release on return, forfeit on damage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dispute resolution&lt;/td&gt;
&lt;td&gt;3-step flow: file, respond, resolve (8 reasons, 7 resolutions, deposit auto-wired)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Community helpboard&lt;/td&gt;
&lt;td&gt;Post requests ("Need a ladder this Saturday"), get replies, track status&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI-assisted listings&lt;/td&gt;
&lt;td&gt;Generate descriptions and images via Pollinations API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Notification bell&lt;/td&gt;
&lt;td&gt;15 event types with optional Telegram bot forwarding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub OAuth&lt;/td&gt;
&lt;td&gt;Sign in with GitHub via Keycloak identity provider&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Onboarding wizard&lt;/td&gt;
&lt;td&gt;3-step profile setup for new users&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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%2F7d5hbkrsx8g5od3x4m9l.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%2F7d5hbkrsx8g5od3x4m9l.png" alt="Workshop Profile" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;6-part video series showing every feature live on a production server:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://youtu.be/ML1aPJqHDuc" rel="noopener noreferrer"&gt;EP1 -- Giveaway Flow&lt;/a&gt; -- free items, simplified claim&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://youtu.be/DRju5RuojeA" rel="noopener noreferrer"&gt;EP2 -- Rental Flow&lt;/a&gt; -- full lifecycle from request to review&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://youtu.be/T2WqnM457LI" rel="noopener noreferrer"&gt;EP3 -- Auction System&lt;/a&gt; -- competitive bidding with anti-snipe&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://youtu.be/MxlZX1yHoYc" rel="noopener noreferrer"&gt;EP4 -- Badge System&lt;/a&gt; -- 15 badges, 5 reputation tiers&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://youtu.be/SLB3-0vIlaI" rel="noopener noreferrer"&gt;EP5 -- Multilingual Live Switch&lt;/a&gt; -- one click, every label, instant&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://youtu.be/MJWlWsiJHCY" rel="noopener noreferrer"&gt;EP6 -- Deposit System&lt;/a&gt; -- hold, release, forfeit, dispute resolution&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://46.62.138.218" rel="noopener noreferrer"&gt;https://46.62.138.218&lt;/a&gt;&lt;br&gt;
Log in as &lt;code&gt;angel&lt;/code&gt; / &lt;code&gt;helix_pass&lt;/code&gt; or use &lt;strong&gt;Sign in with GitHub&lt;/strong&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.amazonaws.com%2Fuploads%2Farticles%2F3zmwkqe99t0ogp28lpor.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%2F3zmwkqe99t0ogp28lpor.png" alt="Dashboard" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

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

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

&lt;h3&gt;
  
  
  By the numbers
&lt;/h3&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;Count&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Python source lines&lt;/td&gt;
&lt;td&gt;10,625&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTML template lines&lt;/td&gt;
&lt;td&gt;6,244&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test lines&lt;/td&gt;
&lt;td&gt;2,220&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQLAlchemy models&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typed enums&lt;/td&gt;
&lt;td&gt;37&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;REST API endpoints&lt;/td&gt;
&lt;td&gt;109&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automated tests&lt;/td&gt;
&lt;td&gt;250 (201 without DB)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Puppeteer screen tests&lt;/td&gt;
&lt;td&gt;52 edge-case checks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;i18n strings&lt;/td&gt;
&lt;td&gt;476 (EN + IT)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Seed data items&lt;/td&gt;
&lt;td&gt;119 across 21 categories&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;250 automated tests across 23 test files (201 pass without any database). Rental state machine alone has 26 tests covering every valid and invalid transition. Plus 52 Puppeteer edge-case screen tests covering XSS probes, pagination boundaries, mobile viewport, gallery behaviour, and API boundary conditions. The i18n completeness test ensures every English key has an Italian translation -- add a key to &lt;code&gt;en.json&lt;/code&gt; without adding it to &lt;code&gt;it.json&lt;/code&gt; and the test suite fails.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Tech stack
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;FastAPI&lt;/strong&gt; + SQLAlchemy 2.0 async + asyncpg&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Keycloak&lt;/strong&gt; OIDC (RS256 JWT, 6 roles, GitHub IDP)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;PostgreSQL 17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache&lt;/td&gt;
&lt;td&gt;Redis 7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Queue&lt;/td&gt;
&lt;td&gt;RabbitMQ 3.13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Jinja2&lt;/strong&gt; SSR + &lt;strong&gt;Tailwind CSS&lt;/strong&gt; (CDN) + &lt;strong&gt;Alpine.js&lt;/strong&gt; (CDN)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payments&lt;/td&gt;
&lt;td&gt;PayPal REST API v2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI&lt;/td&gt;
&lt;td&gt;Pollinations API (image + text generation)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bot&lt;/td&gt;
&lt;td&gt;Telegram Bot API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tests&lt;/td&gt;
&lt;td&gt;pytest + pytest-asyncio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hosting&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Hetzner CX32&lt;/strong&gt; -- 4 vCPU, 8 GB RAM, EUR 7.59/month&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser --&amp;gt; Caddy (TLS) --&amp;gt; FastAPI (uvicorn)
                              |
                              +-- 18 Jinja2 templates (i18n: EN/IT)
                              +-- 109 API endpoints (JSON)
                              +-- Keycloak OIDC (6 roles, GitHub OAuth)
                              +-- PostgreSQL (32 models, UUID PKs)
                              +-- Redis + RabbitMQ + MinIO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How Claude Code helped
&lt;/h3&gt;

&lt;p&gt;Claude Code (Opus 4.6) was my co-pilot throughout. Not a code generator I copied from -- a pair programmer I worked with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What worked well:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scaffolding models and routers&lt;/strong&gt; -- describing a feature like "auction system with reserve prices and anti-snipe" and getting a working first draft with the right SQLAlchemy relationships&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test generation&lt;/strong&gt; -- 250 pytest tests + 52 Puppeteer edge-case screen tests, most written by describing the behavior I wanted tested&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edge-case testing&lt;/strong&gt; -- Puppeteer tests that probe XSS, pagination boundaries, invalid enums, mobile viewport, broken images -- found a real 500 error on invalid listing type filter&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deposit system wiring&lt;/strong&gt; -- the deposit auto-release on rental completion and dispute-to-deposit wiring were Claude Code fixes applied hours before deadline. Described the gap, got working code in minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;i18n coverage&lt;/strong&gt; -- translating 476 strings to Italian with context-appropriate translations (not Google Translate quality)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging production issues&lt;/strong&gt; -- tracing an OAuth redirect loop to a missing port number in an env var, across 4 different config files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What I still did myself:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architecture decisions (Keycloak over simple JWT, server-rendered over SPA)&lt;/li&gt;
&lt;li&gt;UI/UX design (every page layout, color choices, the workshop-as-identity concept)&lt;/li&gt;
&lt;li&gt;The deposit-as-insurance concept (no third-party insurer -- neighbors handle it themselves)&lt;/li&gt;
&lt;li&gt;Production deployment and ops (Docker Compose, Caddy config, Hetzner setup)&lt;/li&gt;
&lt;li&gt;Manual testing on a real server with real users&lt;/li&gt;
&lt;li&gt;All 6 demo videos (Puppeteer + OBS, recorded and edited same day)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The commit history tells the story. Every feature was built iteratively -- scaffold, test, deploy, fix, repeat.&lt;/p&gt;

&lt;h3&gt;
  
  
  The origin story
&lt;/h3&gt;

&lt;p&gt;Built from a camper van in Trapani, Sicily. The idea came from my father's garage -- 500 tools, no neighbors who knew they existed. BorrowHood is the platform I wish he'd had.&lt;/p&gt;

&lt;p&gt;Open source. No platform fees. Forever.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Every neighborhood has a garage like his."&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>python</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
