<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Luis Fernando Richter</title>
    <description>The latest articles on DEV Community by Luis Fernando Richter (@lfrichter).</description>
    <link>https://dev.to/lfrichter</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F178221%2F6e87080e-a729-4ec9-bfd1-4d0c0e6fbf91.png</url>
      <title>DEV Community: Luis Fernando Richter</title>
      <link>https://dev.to/lfrichter</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lfrichter"/>
    <language>en</language>
    <item>
      <title>Ask Richter: Building a Grounded AI Career Agent on Sanity's Structured Content Lake</title>
      <dc:creator>Luis Fernando Richter</dc:creator>
      <pubDate>Sat, 03 Oct 2026 20:00:00 +0000</pubDate>
      <link>https://dev.to/lfrichter/ask-richter-building-a-grounded-ai-career-agent-on-sanitys-structured-content-lake-2hd</link>
      <guid>https://dev.to/lfrichter/ask-richter-building-a-grounded-ai-career-agent-on-sanitys-structured-content-lake-2hd</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/sanity-2026-09-16"&gt;Sanity Challenge, Path One: Ship an Agent That Queries Real Content&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Ask Richter turns a static software-engineering resume into an interactive, multilingual AI Career Agent.&lt;/p&gt;

&lt;p&gt;Instead of treating my career history as a large block of text, I modeled it as structured, interconnected content covering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Professional experiences&lt;/li&gt;
&lt;li&gt;Projects&lt;/li&gt;
&lt;li&gt;Skills&lt;/li&gt;
&lt;li&gt;Education&lt;/li&gt;
&lt;li&gt;Achievements&lt;/li&gt;
&lt;li&gt;Architectural decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application allows recruiters, engineering leaders, and developers to ask natural-language questions about my professional background in &lt;strong&gt;English, Portuguese, and Spanish&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The core design principle is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Retrieve evidence first. Generate second.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent is designed to answer from retrieved evidence. When the required information is not present or cannot be verified, it abstains instead of inventing a fact.&lt;/p&gt;

&lt;p&gt;For example, asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“Which projects use React?”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;is handled differently from:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“What were the architectural challenges in building Ask Richter's RAG architecture?”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first is a precise structured retrieval problem. The second is a semantic retrieval problem.&lt;/p&gt;

&lt;p&gt;Relational questions can also use bounded knowledge-graph traversal across references between entities.&lt;/p&gt;

&lt;p&gt;The result is a career agent where the underlying content model is part of the reasoning system, rather than simply a CMS sitting behind a chatbot.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Live application:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://ask-richter-frontend.vercel.app/" rel="noopener noreferrer"&gt;https://ask-richter-frontend.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The deployed application provides the conversational interface for exploring the structured career knowledge base.&lt;/p&gt;

&lt;p&gt;Example queries:&lt;/p&gt;
&lt;h3&gt;
  
  
  Structured retrieval
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Which projects use React?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The system identifies the technology relationship and retrieves the matching projects using deterministic structured retrieval.&lt;/p&gt;
&lt;h3&gt;
  
  
  Semantic retrieval
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What were the architectural challenges in building Ask Richter's RAG architecture?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The system performs semantic retrieval over the architectural knowledge and generates an answer from the retrieved evidence.&lt;/p&gt;
&lt;h3&gt;
  
  
  Relational retrieval
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Which technologies connect the Ask Richter project to Richter's professional experiences?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The system routes the query to the agentic retrieval path and attempts bounded traversal across the relationships modeled in Sanity.&lt;/p&gt;
&lt;h3&gt;
  
  
  Factual abstention
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What was Richter's experience developing production systems in Rust?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When the required evidence is not available in the knowledge base, the system abstains rather than fabricating an experience.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitHub repository:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/lfrichter/ask-richter" rel="noopener noreferrer"&gt;https://github.com/lfrichter/ask-richter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The repository contains the complete Turborepo monorepo, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next.js application&lt;/li&gt;
&lt;li&gt;Sanity Studio&lt;/li&gt;
&lt;li&gt;Sanity schemas and migrations&lt;/li&gt;
&lt;li&gt;Retrieval and orchestration code&lt;/li&gt;
&lt;li&gt;Knowledge graph traversal&lt;/li&gt;
&lt;li&gt;AI provider integration&lt;/li&gt;
&lt;li&gt;Automated tests&lt;/li&gt;
&lt;li&gt;Architecture Decision Records&lt;/li&gt;
&lt;li&gt;Submission and regression evidence&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  How I Used Sanity
&lt;/h2&gt;

&lt;p&gt;Sanity is the canonical knowledge layer for Ask Richter.&lt;/p&gt;

&lt;p&gt;Rather than storing a traditional resume as one document, I modeled the career domain as interconnected typed entities in the Sanity Content Lake.&lt;/p&gt;

&lt;p&gt;The current model contains six main schemas:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;skill&lt;/code&gt; · &lt;code&gt;experience&lt;/code&gt; · &lt;code&gt;project&lt;/code&gt; · &lt;code&gt;education&lt;/code&gt; · &lt;code&gt;achievement&lt;/code&gt; · &lt;code&gt;architectureDecision&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The captured dataset contains &lt;strong&gt;101 documents and 121 references&lt;/strong&gt; at the time of the submission snapshot.&lt;/p&gt;

&lt;p&gt;These references are important because the agent can reason about relationships between entities instead of relying exclusively on text similarity.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Project
   ├── uses → Skills
   ├── belongs to → Experience
   ├── documents → Architecture Decisions
   └── demonstrates → Achievements
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sanity MCP in the AI Engineering Workflow
&lt;/h3&gt;

&lt;p&gt;The project also uses the official Sanity MCP server as part of the &lt;strong&gt;AI Engineering Agent (AGY)&lt;/strong&gt; environment.&lt;/p&gt;

&lt;p&gt;The MCP configuration points directly to the production Sanity project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sanity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"@sanity/mcp-server@latest"&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;"env"&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;"SANITY_PROJECT_ID"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"q19ey6yx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"SANITY_DATASET"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"production"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;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;This gives the engineering agent direct, schema-aware access to the same Sanity Content Lake used by the application.&lt;/p&gt;

&lt;p&gt;During the final verification, the AGY used Sanity MCP tools including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;query_documents&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;list_workspace_schemas&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get_schema&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;semantic_search&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a live MCP query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;count(*[_type == "project"])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;returned &lt;strong&gt;18 projects&lt;/strong&gt; from the production dataset.&lt;/p&gt;

&lt;p&gt;The MCP schema inspection also identified the deployed &lt;strong&gt;Ask Richter&lt;/strong&gt; workspace.&lt;/p&gt;

&lt;p&gt;This was particularly useful during development because the agent could inspect the actual content model and production data instead of relying on assumptions about the CMS.&lt;/p&gt;

&lt;p&gt;The Sanity MCP server is designed specifically to let AI assistants interact with Sanity projects, including schema exploration, GROQ queries, and semantic search.&lt;/p&gt;

&lt;h3&gt;
  
  
  Structured Retrieval — M2
&lt;/h3&gt;

&lt;p&gt;For deterministic questions, Ask Richter uses GROQ-based structured retrieval.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Which projects use React?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;does not require vector similarity search.&lt;/p&gt;

&lt;p&gt;The system can query the structured relationship between projects and technologies directly.&lt;/p&gt;

&lt;p&gt;This provides deterministic retrieval for questions involving:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Technology filters&lt;/li&gt;
&lt;li&gt;Project catalogs&lt;/li&gt;
&lt;li&gt;Entity lists&lt;/li&gt;
&lt;li&gt;Cardinality&lt;/li&gt;
&lt;li&gt;Chronological information&lt;/li&gt;
&lt;li&gt;Explicit relationships&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Semantic Retrieval — M3
&lt;/h3&gt;

&lt;p&gt;Open-ended questions require a different strategy.&lt;/p&gt;

&lt;p&gt;Ask Richter uses &lt;strong&gt;Sanity Dataset Embeddings&lt;/strong&gt; with &lt;code&gt;text::semanticSimilarity()&lt;/code&gt; to retrieve semantically relevant content.&lt;/p&gt;

&lt;p&gt;This is useful for questions where the user does not necessarily use the exact terminology present in the source material.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What were the architectural challenges in building Ask Richter's RAG architecture?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;requires finding related architectural evidence rather than simply matching a specific project or technology field.&lt;/p&gt;

&lt;p&gt;The retrieved evidence is then passed to the language model for grounded response generation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agentic Knowledge Graph Retrieval — M4
&lt;/h3&gt;

&lt;p&gt;Some questions are relational rather than purely semantic.&lt;/p&gt;

&lt;p&gt;For those cases, Ask Richter uses a bounded agentic retrieval layer built around the references in the structured content model.&lt;/p&gt;

&lt;p&gt;The retrieval process has explicit execution limits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Maximum 2 hops&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maximum 4 tool calls&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;4-second global timeout&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Cycle detection&lt;/li&gt;
&lt;li&gt;Read-only retrieval&lt;/li&gt;
&lt;li&gt;No content mutation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The purpose of these limits is to prevent an open-ended agent loop while keeping relational questions useful.&lt;/p&gt;

&lt;p&gt;The current implementation verifies first-order traversal scenarios such as project → skill relationships. More complex reverse multi-hop traversal remains intentionally bounded by the current execution budget.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resilient Fallback
&lt;/h3&gt;

&lt;p&gt;The application also maintains a pure TypeScript &lt;code&gt;TSVectorStore&lt;/code&gt; as a deterministic fallback.&lt;/p&gt;

&lt;p&gt;This replaced an earlier native FAISS dependency and helped move the application toward a fully serverless architecture.&lt;/p&gt;

&lt;p&gt;The fallback uses in-memory vector calculations over the same 768-dimensional embedding space and is designed to preserve safe abstention when the primary retrieval path is unavailable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Grounding and Abstention
&lt;/h3&gt;

&lt;p&gt;Retrieval is separated from generation.&lt;/p&gt;

&lt;p&gt;The application first determines the appropriate retrieval strategy, obtains evidence, and only then asks the language model to formulate the response.&lt;/p&gt;

&lt;p&gt;If the retrieval layer cannot provide sufficient evidence, the agent does not attempt to fill the gap with general model knowledge.&lt;/p&gt;

&lt;p&gt;This distinction is particularly important for a career agent.&lt;/p&gt;

&lt;p&gt;A fabricated professional experience may sound plausible while still being completely false.&lt;/p&gt;

&lt;p&gt;For Ask Richter, &lt;strong&gt;“I don't have enough evidence to answer that” is a valid system outcome.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sanity Project Details
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sanity Project ID:&lt;/strong&gt; &lt;code&gt;q19ey6yx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dataset:&lt;/strong&gt; &lt;code&gt;production&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The Sanity Studio lives in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apps/studio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The content model currently contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;skill
experience
project
education
achievement
architectureDecision
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Sanity Content Lake is the canonical source for the career knowledge represented by the application.&lt;/p&gt;

&lt;p&gt;The project uses structured references to preserve relationships between the entities rather than flattening everything into independent text documents.&lt;/p&gt;

&lt;p&gt;The production snapshot used for this submission contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;101 documents&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;121 references&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;18 projects&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These values were verified against the production dataset during final validation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent Session
&lt;/h2&gt;

&lt;p&gt;The Ask Richter engineering workflow was developed and verified with an AI Engineering Agent (AGY) connected to Sanity through the official MCP server.&lt;/p&gt;

&lt;p&gt;The session demonstrates how the agent can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inspect the Sanity schema&lt;/li&gt;
&lt;li&gt;Query real production content&lt;/li&gt;
&lt;li&gt;Inspect document relationships&lt;/li&gt;
&lt;li&gt;Validate the structured content model&lt;/li&gt;
&lt;li&gt;Verify retrieval behavior&lt;/li&gt;
&lt;li&gt;Run regression checks against the resulting application&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The MCP connection used the Sanity project:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;q19ey6yx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and dataset:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;production&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A curated public Agent Session can be embedded here after publication through DEV's Agent Sessions interface.&lt;/p&gt;

&lt;p&gt;Before publication, the transcript should be reviewed to ensure that no API keys, tokens, credentials, local paths containing sensitive information, or other private data are exposed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Architecture
&lt;/h2&gt;

&lt;p&gt;At a high level, the system looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                     ┌──────────────────────┐
                     │       User           │
                     │    EN / PT / ES      │
                     └──────────┬───────────┘
                                │
                                ▼
                     ┌──────────────────────┐
                     │   Next.js 15 App     │
                     │    /api/chat         │
                     └──────────┬───────────┘
                                │
                                ▼
                     ┌──────────────────────┐
                     │ Intent Classifier    │
                     │      &amp;amp; Router        │
                     └───────┬──┬──┬───────┘
                             │  │  │
                 ┌───────────┘  │  └────────────┐
                 ▼              ▼               ▼
          ┌────────────┐ ┌────────────┐ ┌──────────────┐
          │ M2         │ │ M4         │ │ M3           │
          │ Structured │ │ Agentic    │ │ Semantic     │
          │ GROQ       │ │ KG         │ │ Embeddings   │
          └─────┬──────┘ └─────┬──────┘ └──────┬───────┘
                │              │               │
                └──────────────┼───────────────┘
                               ▼
                    ┌──────────────────────┐
                    │ Sanity Content Lake  │
                    │ Structured Knowledge │
                    └──────────┬───────────┘
                               │
                               ▼
                    ┌──────────────────────┐
                    │ Grounded Context     │
                    └──────────┬───────────┘
                               │
                               ▼
                    ┌──────────────────────┐
                    │ Gemini 3.6 Flash     │
                    └──────────┬───────────┘
                               │
                               ▼
                    ┌──────────────────────┐
                    │ Factual Answer or    │
                    │ Safe Abstention      │
                    └──────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is also a separate engineering-time MCP path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        AI Engineering Agent (AGY)
                    │
                    ▼
        Sanity MCP Server
        @sanity/mcp-server
                    │
                    ▼
        Sanity Content Lake
        q19ey6yx / production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This separation is intentional.&lt;/p&gt;

&lt;p&gt;The MCP integration gives the engineering agent direct access to the real Sanity environment for schema inspection, querying, and validation.&lt;/p&gt;

&lt;p&gt;The production application independently uses Sanity's APIs and retrieval capabilities to serve end-user questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Knowledge Layer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Sanity Studio v3.78&lt;/li&gt;
&lt;li&gt;Sanity Content Lake&lt;/li&gt;
&lt;li&gt;GROQ&lt;/li&gt;
&lt;li&gt;Sanity Dataset Embeddings&lt;/li&gt;
&lt;li&gt;Structured document references&lt;/li&gt;
&lt;li&gt;Official Sanity MCP server&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Application
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Next.js 15&lt;/li&gt;
&lt;li&gt;React 19&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;Turborepo&lt;/li&gt;
&lt;li&gt;Vercel Serverless&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  AI
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Google GenAI API&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gemini-3.6-flash&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gemini-embedding-2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;768-dimensional embeddings&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Supporting Infrastructure
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Supabase&lt;/li&gt;
&lt;li&gt;Server-side resilience mechanisms&lt;/li&gt;
&lt;li&gt;TypeScript in-memory vector fallback&lt;/li&gt;
&lt;li&gt;GitHub Actions&lt;/li&gt;
&lt;li&gt;AI Engineering Agent (AGY)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Engineering Quality
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;TDD-oriented development&lt;/li&gt;
&lt;li&gt;Intent-routing regression tests&lt;/li&gt;
&lt;li&gt;Jidoka validation pipeline&lt;/li&gt;
&lt;li&gt;Automated integration tests&lt;/li&gt;
&lt;li&gt;End-to-end HTTP regression scenarios&lt;/li&gt;
&lt;li&gt;Architecture Decision Records&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Verification
&lt;/h2&gt;

&lt;p&gt;The final release candidate was validated through multiple independent gates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automated Tests
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;170 / 170 tests passing&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;151 frontend tests&lt;/li&gt;
&lt;li&gt;19 backend tests&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  HTTP Regression
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;17 / 17 end-to-end HTTP scenarios passing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All verified scenarios returned successful HTTP responses.&lt;/p&gt;

&lt;h3&gt;
  
  
  Jidoka Validation
&lt;/h3&gt;

&lt;p&gt;The full Jidoka pipeline completed successfully across the monorepo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TypeScript type checking&lt;/li&gt;
&lt;li&gt;Linting&lt;/li&gt;
&lt;li&gt;Production builds&lt;/li&gt;
&lt;li&gt;Test execution&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Repository Integrity
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;git diff --check&lt;/code&gt; completed with zero errors.&lt;/p&gt;

&lt;p&gt;The release candidate was committed and deployed to Vercel.&lt;/p&gt;

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

&lt;p&gt;The most important lesson was that a structured content model changes what an AI agent can reliably do.&lt;/p&gt;

&lt;p&gt;A conventional RAG pipeline often starts with:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“How do I retrieve the most similar text?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This project led me toward a different question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“What kind of information is the user actually asking for?”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes the answer is a structured query.&lt;/p&gt;

&lt;p&gt;Sometimes it is semantic retrieval.&lt;/p&gt;

&lt;p&gt;Sometimes it is a relationship traversal.&lt;/p&gt;

&lt;p&gt;Trying to force all three problems through a single retrieval mechanism creates unnecessary ambiguity.&lt;/p&gt;

&lt;p&gt;Sanity made it possible to represent the career domain as structured content first, and then build retrieval strategies around that model.&lt;/p&gt;

&lt;p&gt;That changed the role of the CMS.&lt;/p&gt;

&lt;p&gt;It became part of the reasoning architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Ask Richter started as an experiment to make my resume conversational.&lt;/p&gt;

&lt;p&gt;It evolved into a structured knowledge system where an AI agent has to remain accountable to the underlying evidence.&lt;/p&gt;

&lt;p&gt;The goal was not to make an LLM sound confident about my career.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The goal was to make the agent answer from what the knowledge base can actually support.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Retrieve evidence first. Generate second. Abstain when the evidence is not there.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>devchallenge</category>
      <category>sanitychallenge</category>
      <category>sanity</category>
      <category>ai</category>
    </item>
    <item>
      <title>I Built Cat Guardian for My Seven Cats 🐾</title>
      <dc:creator>Luis Fernando Richter</dc:creator>
      <pubDate>Mon, 17 Aug 2026 14:45:48 +0000</pubDate>
      <link>https://dev.to/lfrichter/i-built-cat-guardian-for-my-seven-cats-287</link>
      <guid>https://dev.to/lfrichter/i-built-cat-guardian-for-my-seven-cats-287</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/weekend-2026-08-13"&gt;Weekend Challenge: Dog Days Edition&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🐾 Cat Guardian — Protect. Identify. Find.
&lt;/h2&gt;

&lt;p&gt;I live with seven cats: Kiara, Golia, Meias, Vaquinha, Tigrinha, Peluda, and Gamora. They all have different personalities, different appearances, and different routines.&lt;/p&gt;

&lt;p&gt;And, like many pet owners, there is one thing that has always worried me: &lt;strong&gt;What if one of them gets lost?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That question became the starting point for Cat Guardian.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Cat Guardian&lt;/strong&gt; is a privacy-first digital safety passport for cats.&lt;/p&gt;

&lt;p&gt;The idea is simple: give each cat a digital identity containing the information that could actually help if they ever go missing.&lt;/p&gt;

&lt;p&gt;The platform provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🐈 Digital identity for each cat&lt;/li&gt;
&lt;li&gt;🩺 Health records and vaccination tracking&lt;/li&gt;
&lt;li&gt;🧠 AI-assisted visual identification&lt;/li&gt;
&lt;li&gt;🏷️ Dynamic QR collar tags&lt;/li&gt;
&lt;li&gt;🚨 Lost Mode&lt;/li&gt;
&lt;li&gt;📱 Public rescue passport&lt;/li&gt;
&lt;li&gt;🔐 Privacy-preserving contact between finder and owner&lt;/li&gt;
&lt;li&gt;🌎 English and Brazilian Portuguese localization&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The problem
&lt;/h3&gt;

&lt;p&gt;When a pet goes missing, useful information is often scattered across photos, veterinary records, paper documents, and the owner's memory.&lt;/p&gt;

&lt;p&gt;Traditional collar tags can also expose personal information such as phone numbers or addresses. I wanted a different approach.&lt;/p&gt;

&lt;p&gt;The QR code attached to the collar doesn't expose the owner's contact information. Instead, when someone finds the cat, they can scan the QR code and access a public rescue profile.&lt;/p&gt;

&lt;p&gt;If the owner has activated &lt;strong&gt;Lost Mode&lt;/strong&gt;, the finder can submit a sighting. The owner is then notified through a secure backend relay.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Owner
  │
  ▼
Cat Guardian
  │
  ├── Digital Identity
  ├── Health Records
  ├── AI Profile
  └── QR Collar Tag
          │
          ▼
      Lost Mode
          │
          ▼
     Finder scans QR
          │
          ▼
    Public Rescue Card
          │
          ▼
     Submit Sighting
          │
          ▼
       Owner notified
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal isn't to replace GPS trackers or microchips.&lt;/p&gt;

&lt;p&gt;It is to make the information surrounding a lost pet &lt;strong&gt;available, structured, and safer to share&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why AI?
&lt;/h3&gt;

&lt;p&gt;I didn't want to add AI simply because this was an AI-related challenge.&lt;/p&gt;

&lt;p&gt;I wanted to use it where it could provide practical value.&lt;/p&gt;

&lt;p&gt;Gemini is used to analyze visual characteristics such as coat patterns, eye color, and distinctive markings and generate a structured identification profile.&lt;/p&gt;

&lt;p&gt;The application also provides informational preventive wellness guidance, while explicitly keeping medical diagnosis and treatment outside its scope.&lt;/p&gt;

&lt;p&gt;AI-generated profiles are also localized according to the user's language.&lt;/p&gt;




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

&lt;p&gt;🌐 &lt;strong&gt;&lt;a href="https://cat-guardian-two.vercel.app/" rel="noopener noreferrer"&gt;Open the Live Demo →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The application includes a &lt;strong&gt;Demo Mode&lt;/strong&gt;, so you can explore the main experience without creating an account.&lt;/p&gt;

&lt;p&gt;The demo contains my seven cats:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kiara · Golia · Meias · Vaquinha · Tigrinha · Peluda · Gamora&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Try the Lost &amp;amp; Found flow with the demo data and explore how a finder would interact with a cat's public rescue passport.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key flows
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Register a cat&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create a digital identity and add health information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Generate a QR collar tag&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The QR code points to the cat's public safety passport.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Activate Lost Mode&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The owner can mark the cat as missing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Finder scans the QR code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The finder sees the relevant rescue information without seeing the owner's private contact details.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Submit a sighting&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The finder can send information about where and when the cat was seen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Owner receives the notification&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The backend relays the sighting to the owner through Resend.&lt;/p&gt;




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

&lt;p&gt;💻 &lt;strong&gt;&lt;a href="https://github.com/lfrichter/cat-guardian" rel="noopener noreferrer"&gt;GitHub Repository →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The project is open source and built with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React 19&lt;/li&gt;
&lt;li&gt;Vite 6&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;Supabase PostgreSQL&lt;/li&gt;
&lt;li&gt;Supabase Auth&lt;/li&gt;
&lt;li&gt;Row Level Security&lt;/li&gt;
&lt;li&gt;Gemini&lt;/li&gt;
&lt;li&gt;Ollama&lt;/li&gt;
&lt;li&gt;Mistral 7B&lt;/li&gt;
&lt;li&gt;OpenCoder 8B&lt;/li&gt;
&lt;li&gt;Resend&lt;/li&gt;
&lt;li&gt;i18next / react-i18next&lt;/li&gt;
&lt;li&gt;Vitest&lt;/li&gt;
&lt;li&gt;React Testing Library&lt;/li&gt;
&lt;li&gt;ESLint&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;This project was also an experiment in &lt;strong&gt;AI-assisted software engineering&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I used my own &lt;strong&gt;AI Software Engineering Framework 2.0&lt;/strong&gt; to orchestrate the development process.&lt;/p&gt;

&lt;p&gt;The goal was not simply to ask an LLM to generate the application.&lt;/p&gt;

&lt;p&gt;Instead, I treated AI agents as specialized members of an engineering workflow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Human Supervisor
       │
       ▼
Chief of Staff
       │
       ▼
   Risk Router
    /   |   \
   ▼    ▼    ▼
Mistral OpenCoder Gemini
   \    |    /
    \   |   /
      Jidoka
         │
         ▼
   Human Approval
         │
         ▼
       Merge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Risk-based agent routing
&lt;/h3&gt;

&lt;p&gt;Simple and low-risk tasks were delegated to local models running through Ollama.&lt;/p&gt;

&lt;p&gt;🟢 &lt;strong&gt;Mistral 7B&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Used for tasks such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;documentation&lt;/li&gt;
&lt;li&gt;simple UI changes&lt;/li&gt;
&lt;li&gt;repetitive work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🟡 &lt;strong&gt;OpenCoder 8B&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CRUD&lt;/li&gt;
&lt;li&gt;forms&lt;/li&gt;
&lt;li&gt;implementation tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔴 &lt;strong&gt;Gemini&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Used for higher-risk tasks such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authentication&lt;/li&gt;
&lt;li&gt;Row Level Security&lt;/li&gt;
&lt;li&gt;AI integrations&lt;/li&gt;
&lt;li&gt;architectural decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allowed me to keep the more capable model focused on tasks where it provided the most value.&lt;/p&gt;

&lt;h3&gt;
  
  
  Jidoka Quality Gate
&lt;/h3&gt;

&lt;p&gt;Every implementation had to pass a validation pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Lint
  ↓
Typecheck
  ↓
Tests
  ↓
Build
  ↓
Human Approval
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a validation step failed, the workflow stopped instead of allowing the problem to propagate.&lt;/p&gt;

&lt;p&gt;This follows the &lt;strong&gt;Jidoka / Andon Cord&lt;/strong&gt; principle from my framework:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When an anomaly is detected, stop the process and fix it before continuing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The final release candidate passed:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Gate&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ESLint&lt;/td&gt;
&lt;td&gt;✅ PASS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TypeScript&lt;/td&gt;
&lt;td&gt;✅ PASS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vitest&lt;/td&gt;
&lt;td&gt;✅ 21/21 PASS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production Build&lt;/td&gt;
&lt;td&gt;✅ PASS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Privacy-first architecture
&lt;/h3&gt;

&lt;p&gt;The public rescue passport deliberately does not expose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;owner's email&lt;/li&gt;
&lt;li&gt;phone number&lt;/li&gt;
&lt;li&gt;physical address&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The finder communicates through a backend relay.&lt;/p&gt;

&lt;p&gt;Sightings are persisted in PostgreSQL and the owner is notified through the Resend API.&lt;/p&gt;

&lt;p&gt;This creates a simple separation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Finder
  │
  ▼
Public Rescue Passport
  │
  ▼
Sighting
  │
  ▼
Backend
  ├── PostgreSQL
  └── Resend
          │
          ▼
        Owner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The finder can help without gaining direct access to the owner's private contact information.&lt;/p&gt;




&lt;h3&gt;
  
  
  Internationalization
&lt;/h3&gt;

&lt;p&gt;English is the default language, with Brazilian Portuguese as a secondary locale.&lt;/p&gt;

&lt;p&gt;I also wanted AI-generated information to respect localization.&lt;/p&gt;

&lt;p&gt;The localized AI profiles are stored in PostgreSQL using JSONB:&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;"en"&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;"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;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"personality"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"pt-BR"&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;"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;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"personality"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps the cat's identity data together while allowing the presentation to adapt to the user's language.&lt;/p&gt;




&lt;h3&gt;
  
  
  Design System
&lt;/h3&gt;

&lt;p&gt;The application uses a custom &lt;strong&gt;Midnight Guardian&lt;/strong&gt; design system.&lt;/p&gt;

&lt;p&gt;The visual language combines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Midnight Navy&lt;/li&gt;
&lt;li&gt;Lavender&lt;/li&gt;
&lt;li&gt;Emerald&lt;/li&gt;
&lt;li&gt;Amber&lt;/li&gt;
&lt;li&gt;Coral&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal was to make the application feel like a safety product rather than a generic pet CRUD application.&lt;/p&gt;




&lt;h3&gt;
  
  
  🔐 Privacy &amp;amp; Safety
&lt;/h3&gt;

&lt;p&gt;Privacy was treated as a product requirement rather than an afterthought.&lt;/p&gt;

&lt;p&gt;The public QR page is intentionally limited to information that can help identify and recover the cat.&lt;/p&gt;

&lt;p&gt;Owner PII is not rendered publicly.&lt;/p&gt;

&lt;p&gt;The system also does not attempt to provide veterinary diagnosis.&lt;/p&gt;

&lt;p&gt;Cat Guardian provides informational preventive wellness guidance and does not replace professional veterinary advice.&lt;/p&gt;




&lt;h3&gt;
  
  
  🚧 Current Limitations
&lt;/h3&gt;

&lt;p&gt;Cat Guardian is a hackathon prototype.&lt;/p&gt;

&lt;p&gt;It does &lt;strong&gt;not&lt;/strong&gt; currently provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;real-time GPS tracking;&lt;/li&gt;
&lt;li&gt;GPS collar hardware integration;&lt;/li&gt;
&lt;li&gt;veterinary diagnosis;&lt;/li&gt;
&lt;li&gt;guaranteed pet recovery.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These could be explored in future versions.&lt;/p&gt;

&lt;p&gt;For this challenge, I intentionally focused on the digital identity, QR-based rescue flow, privacy-preserving communication, and AI-assisted identification.&lt;/p&gt;




&lt;h3&gt;
  
  
  🎯 What I Learned
&lt;/h3&gt;

&lt;p&gt;The biggest challenge wasn't building the features.&lt;/p&gt;

&lt;p&gt;It was deciding &lt;strong&gt;what not to build&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It would have been easy to add GPS, maps, mobile applications, IoT devices, blockchain, push notifications, and many other features.&lt;/p&gt;

&lt;p&gt;But the core idea was much simpler:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Give a cat a digital identity that can help protect, identify, and reunite them with their owner.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Everything else had to support that idea.&lt;/p&gt;

&lt;p&gt;And the project became much stronger because of that constraint.&lt;/p&gt;




&lt;h3&gt;
  
  
  🐾 Built for seven cats
&lt;/h3&gt;

&lt;p&gt;Cat Guardian started with a very personal question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What information would I want to have if one of my cats disappeared tomorrow?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I would want their photo.&lt;/p&gt;

&lt;p&gt;Their identifying characteristics.&lt;/p&gt;

&lt;p&gt;Their health information.&lt;/p&gt;

&lt;p&gt;Their vaccination history.&lt;/p&gt;

&lt;p&gt;Their microchip information.&lt;/p&gt;

&lt;p&gt;And, most importantly:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I would want the person who found them to have a safe way to contact me.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's Cat Guardian.&lt;/p&gt;

&lt;p&gt;Built for:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kiara · Golia · Meias · Vaquinha · Tigrinha · Peluda · Gamora&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🐾&lt;/p&gt;




&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;I'm submitting Cat Guardian for:&lt;/p&gt;

&lt;h3&gt;
  
  
  🏆 Best Use of Google AI
&lt;/h3&gt;

&lt;p&gt;Gemini is used meaningfully in the application for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI-assisted visual identification profiles&lt;/li&gt;
&lt;li&gt;feline characteristic analysis&lt;/li&gt;
&lt;li&gt;preventive wellness assistance&lt;/li&gt;
&lt;li&gt;localized AI-generated content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Google AI is also used as the high-risk agent in the AI-assisted engineering workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔗 Links
&lt;/h2&gt;

&lt;p&gt;🌐 &lt;strong&gt;&lt;a href="https://cat-guardian-two.vercel.app/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;💻 &lt;strong&gt;&lt;a href="https://github.com/lfrichter/cat-guardian" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built for the DEV Weekend Challenge: Dog Days Edition.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>googleaichallenge</category>
      <category>ai</category>
    </item>
    <item>
      <title>Building a Robust API with Laravel, Clean Architecture, and SOLID Principles</title>
      <dc:creator>Luis Fernando Richter</dc:creator>
      <pubDate>Fri, 17 Oct 2025 15:42:01 +0000</pubDate>
      <link>https://dev.to/lfrichter/building-a-robust-api-with-laravel-clean-architecture-and-solid-principles-3jb5</link>
      <guid>https://dev.to/lfrichter/building-a-robust-api-with-laravel-clean-architecture-and-solid-principles-3jb5</guid>
      <description>&lt;p&gt;Excited to share a recent back-end project I architected and developed: the &lt;strong&gt;Favorite Products API&lt;/strong&gt;. This isn't just another CRUD API; it's a practical case study on implementing &lt;strong&gt;Clean Architecture&lt;/strong&gt; and &lt;strong&gt;SOLID&lt;/strong&gt; principles with Laravel to build a secure, high-performance, and scalable solution.&lt;/p&gt;

&lt;p&gt;The project is a RESTful API designed to manage user's favorite product lists, integrating with an external e-commerce service.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✨ Key Highlights &amp;amp; Challenges Overcome
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance Optimization (N+1 Problem):&lt;/strong&gt; I refactored the service layer to transform N+1 external API calls into a single, efficient bulk request (&lt;code&gt;findProductsByIds&lt;/code&gt;), dramatically reducing latency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security First (IDOR Vulnerability):&lt;/strong&gt; We patched a critical &lt;em&gt;Insecure Direct Object Reference&lt;/em&gt; vulnerability by implementing strict, ownership-based authorization rules in the Form Requests. This is reinforced with feature tests covering 200, 401, and 403 status codes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decoupled &amp;amp; Testable Architecture:&lt;/strong&gt; By using &lt;em&gt;Dependency Inversion&lt;/em&gt; (Contracts/Interfaces), we fully decoupled our business logic from the external API client. This makes unit testing a breeze (just mock the interface!) and swapping data sources trivial.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resilient Error Handling:&lt;/strong&gt; Instead of letting external service failures fail silently (returning an empty &lt;code&gt;200 OK&lt;/code&gt;), the system now throws custom exceptions, which are caught by a global handler to return a meaningful &lt;code&gt;503 Service Unavailable&lt;/code&gt; response.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The entire stack runs on &lt;strong&gt;PHP 8.3/Laravel 12&lt;/strong&gt;, &lt;strong&gt;PostgreSQL&lt;/strong&gt;, and is containerized with &lt;strong&gt;Docker&lt;/strong&gt;. We also have a comprehensive test suite using &lt;strong&gt;Pest&lt;/strong&gt; and auto-generated, interactive documentation with &lt;strong&gt;OpenAPI (Swagger)&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔗 Open Source
&lt;/h3&gt;

&lt;p&gt;The project is fully open-source. Feel free to explore the code, learn from the architectural decisions, or even contribute!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Check out the full source code on GitHub:&lt;/strong&gt; &lt;a href="https://github.com/lfrichter/favorite-products-api" rel="noopener noreferrer"&gt;lfrichter/favorite-products-api&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope this can be a useful resource for anyone looking to deepen their understanding of modern back-end architecture.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>api</category>
      <category>architecture</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Lightning-Speed Development with Bun and Hono ⚡</title>
      <dc:creator>Luis Fernando Richter</dc:creator>
      <pubDate>Tue, 05 Aug 2025 13:00:00 +0000</pubDate>
      <link>https://dev.to/lfrichter/lightning-speed-development-with-bun-and-hono-ace</link>
      <guid>https://dev.to/lfrichter/lightning-speed-development-with-bun-and-hono-ace</guid>
      <description>&lt;p&gt;Instead of just reading about the performance of &lt;strong&gt;Bun&lt;/strong&gt; and the simplicity of &lt;strong&gt;Hono&lt;/strong&gt;, I decided to put them to the test by building a Task Manager API. The result exceeded all my expectations and unveiled a new way of thinking about backend development.&lt;/p&gt;

&lt;p&gt;![[lightning-speed-development-with-bun-and-hono.jpeg]]&lt;/p&gt;

&lt;p&gt;Here are the highlights of this experience:&lt;/p&gt;




&lt;h3&gt;
  
  
  🏎️ &lt;strong&gt;Bun: The All-in-One Ecosystem That Eliminates Friction&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Bun isn't just a runtime; it's a revolution in developer experience (DX).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Raw Performance:&lt;/strong&gt; The server startup is instantaneous. In simple local benchmarks, my laptop hit peaks of &lt;strong&gt;110,000+ requests/second&lt;/strong&gt;. The memory usage was also incredibly optimized compared to Node.js.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integrated Tooling:&lt;/strong&gt; The best part is what you &lt;em&gt;don't&lt;/em&gt; have to do. Bun comes with:&lt;br&gt;
* ✅ An absurdly fast package manager.&lt;br&gt;
* ✅ A native test runner (&lt;code&gt;bun:test&lt;/code&gt;), allowing me to achieve 100% test coverage without setting up Jest, Vitest, or Mocha.&lt;br&gt;
* ✅ Out-of-the-box support for TypeScript and JSX.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  ✨ &lt;strong&gt;Hono: The Magic of Simplicity for APIs&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If Bun is the engine, Hono is the ultralight and aerodynamic chassis.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Minimalism and Performance:&lt;/strong&gt; The code is clean and direct, with no boilerplate. The final bundle is just a few KBs, making it perfect for &lt;strong&gt;Edge Computing&lt;/strong&gt; and serverless environments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Total Flexibility:&lt;/strong&gt; I wrote the API once, and I can deploy it anywhere: &lt;strong&gt;Bun, Deno, Cloudflare Workers, Vercel...&lt;/strong&gt; Adhering to Web Standards makes all the difference.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;TypeScript-First:&lt;/strong&gt; The TypeScript experience is flawless. Autocomplete for route params, body, and headers is automatic, ensuring type safety across the entire application.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The simplicity of Hono in action:&lt;/span&gt;
&lt;span class="c1"&gt;// A route to fetch all tasks with strong typing.&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// 'c' (context) is fully typed\!&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s1"&gt;* FROM tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tasks&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;h3&gt;
  
  
  🎯 &lt;strong&gt;The Dynamic Duo: Why Bun + Hono?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Together, they form the stack every developer deserves: fast, simple, and powerful.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;True Agile Development:&lt;/strong&gt; I went from "zero" to a fully tested CRUD in minutes, not hours. Less time configuring, more time creating value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fewer Headaches:&lt;/strong&gt; Compared to a traditional stack (like MERN), the number of development dependencies and configurations to manage is drastically lower.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Production-Ready:&lt;/strong&gt; The structure is naturally scalable and easy to test, creating a solid foundation for serious projects from the get-go.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The complete project is on my GitHub, with the full folder structure, tests, and documentation for anyone who wants to explore it.&lt;/p&gt;

&lt;p&gt;👉 [&lt;a href="https://github.com/lfrichter/hono-task-manager" rel="noopener noreferrer"&gt;https://github.com/lfrichter/hono-task-manager&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ready to see for yourself?&lt;/strong&gt; Try this combination and let me know what you think in the comments! 👇&lt;/p&gt;

</description>
      <category>bunjs</category>
      <category>typescript</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I Built an Tool to AI Agent Testing</title>
      <dc:creator>Luis Fernando Richter</dc:creator>
      <pubDate>Fri, 25 Jul 2025 00:06:12 +0000</pubDate>
      <link>https://dev.to/lfrichter/i-built-an-tool-to-ai-agent-testing-3co8</link>
      <guid>https://dev.to/lfrichter/i-built-an-tool-to-ai-agent-testing-3co8</guid>
      <description>&lt;p&gt;Excited to share my latest open-source project: the &lt;strong&gt;AI Agent Tester&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;As AI models become more integrated into our applications, how do we ensure their responses are consistent and reliable? Manually testing prompts is slow and doesn't scale. That's why I created this tool.&lt;/p&gt;

&lt;p&gt;The AI Agent Tester automates the validation process. It reads prompts from a simple CSV file, sends them to an AI (like OpenAI's GPT), and checks the responses for expected keywords.&lt;/p&gt;

&lt;p&gt;Here’s what makes it effective:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Intelligent Validation&lt;/strong&gt;: It uses "stemming" with NLTK to recognize word variations (e.g., 'fly', 'flying', 'flew'), making validation more robust.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Detailed Reports&lt;/strong&gt;: It generates a JSON report with the status (&lt;code&gt;Success&lt;/code&gt;/&lt;code&gt;Fail&lt;/code&gt;) for each prompt, along with the AI's full response.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Easy to Use&lt;/strong&gt;: Built with Python and requires minimal setup. It even has automatic proxy support for corporate environments.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This project is for any developer or QA engineer working with Large Language Models who wants to add a layer of automated testing to their workflow.&lt;/p&gt;

&lt;p&gt;It's open-source, and I would love to get your feedback or contributions!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check out the project on GitHub:&lt;/strong&gt; &lt;a href="https://github.com/lfrichter/ai-agent-test" rel="noopener noreferrer"&gt;https://github.com/lfrichter/ai-agent-test&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>testing</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The Essence of Development: Unravelling the Complexities to Build High-End Applications</title>
      <dc:creator>Luis Fernando Richter</dc:creator>
      <pubDate>Thu, 17 Jul 2025 20:28:44 +0000</pubDate>
      <link>https://dev.to/lfrichter/the-essence-of-development-unravelling-the-complexities-to-build-high-end-applications-19pn</link>
      <guid>https://dev.to/lfrichter/the-essence-of-development-unravelling-the-complexities-to-build-high-end-applications-19pn</guid>
      <description>&lt;p&gt;As developers, we dive daily into a sea of lines of code, features, and challenges. But before any technological choice, there is a fundamental truth that guides the success of any application, especially those built for established businesses: the clear distinction between &lt;strong&gt;business complexity&lt;/strong&gt; and &lt;strong&gt;technical complexity&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Two Faces of Complexity
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Business complexity&lt;/strong&gt; resides in the rules, processes, and nuances of the very domain in which we operate. It would exist even without a single line of code. Think of the intricate tax regulations of an e-commerce site or the credit approval process of a financial institution. This is the essence, the "why" of our work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technical complexity&lt;/strong&gt;, on the other hand, is what we, as developers, introduce with tools, frameworks, architectures, and implementation decisions. While necessary to bring the solution to life, it should serve the business, not the other way around.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Distinction to Powerful Architectures
&lt;/h2&gt;

&lt;p&gt;When we cultivate the ability to clearly perceive and map this difference, something magical happens: we elevate our application to a new level. By focusing on accurately modelling the business, isolating it from purely technical concerns, we open the doors to &lt;strong&gt;Clean Architecture&lt;/strong&gt; and &lt;strong&gt;Hexagonal Architecture&lt;/strong&gt;. These approaches allow us to build systems that are more maintainable, testable, and adaptable to business changes, as the core of the application—the business logic—remains cohesive and independent of external layers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deepening the Solution with Domain-Driven Design
&lt;/h2&gt;

&lt;p&gt;And if the challenge is to build a robust system for a complex, large-scale business, &lt;strong&gt;Domain-Driven Design (DDD)&lt;/strong&gt; becomes a powerful ally. By immersing ourselves in the domain, in the language of business experts, and translating it into a rich, cohesive model, we build software that truly solves business problems in an aligned and evolving manner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Build for the Business First
&lt;/h2&gt;

&lt;p&gt;In short, the journey to building high-level applications begins with a careful look at the nature of the complexity we face. By honouring the distinction between business and technology, we pave the way for solid architectures and, consequently, for the success of the product and the business it serves. Remember: understanding the core business is the first step to building solutions that truly make a difference.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>ddd</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>My end-to-end automated YouTube video factory</title>
      <dc:creator>Luis Fernando Richter</dc:creator>
      <pubDate>Sat, 12 Jul 2025 20:35:16 +0000</pubDate>
      <link>https://dev.to/lfrichter/my-end-to-end-automated-youtube-video-factory-29fn</link>
      <guid>https://dev.to/lfrichter/my-end-to-end-automated-youtube-video-factory-29fn</guid>
      <description>&lt;p&gt;I'm excited to share the MVP of my latest personal project: a fully &lt;strong&gt;end-to-end automated YouTube video factory&lt;/strong&gt;. This system is designed to transform a simple text idea into a complete, published video, supporting both short-form (Shorts) and long-form content.&lt;/p&gt;

&lt;p&gt;It orchestrates a suite of powerful APIs and tools to automate the entire workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scripting:&lt;/strong&gt; OpenAI API (GPT)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Voiceover:&lt;/strong&gt; ElevenLabs API for high-quality TTS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visuals:&lt;/strong&gt; Flexible image generation via Replicate (SDXL) or a cost-effective alternative using the Pixabay API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subtitles:&lt;/strong&gt; Precise, locally-run transcription with OpenAI Whisper&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Music:&lt;/strong&gt; Royalty-free background music sourced from the Jamendo API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assembly:&lt;/strong&gt; A robust, two-step FFmpeg process that ensures smooth, "judder-free" animations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publishing:&lt;/strong&gt; Direct upload to YouTube via the YouTube Data API v3&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Beyond just connecting APIs, the focus was on building a resilient and developer-friendly system. This includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A comprehensive &lt;code&gt;health_check.py&lt;/code&gt; script to validate the environment.&lt;/li&gt;
&lt;li&gt;Automated &lt;code&gt;pytest&lt;/code&gt; tests for key integrations like Pixabay and Jamendo to handle API errors gracefully.&lt;/li&gt;
&lt;li&gt;A full scheduling system for macOS using &lt;code&gt;launchd&lt;/code&gt; to automate future uploads.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This project was a deep dive into system architecture, complex automation pipelines, and solving low-level integration challenges.&lt;/p&gt;

&lt;p&gt;You can see the system's architecture in these diagrams:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application Flowchart:&lt;/strong&gt; &lt;a href="https://bit.ly/4kzoxby" rel="noopener noreferrer"&gt;https://bit.ly/4kzoxby&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sequence Diagram:&lt;/strong&gt; &lt;a href="https://bit.ly/46EHd6h" rel="noopener noreferrer"&gt;https://bit.ly/46EHd6h&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm always open to feedback and connecting with fellow developers!&lt;/p&gt;

</description>
      <category>automation</category>
      <category>softwareengineering</category>
      <category>api</category>
      <category>python</category>
    </item>
    <item>
      <title>Never Leave Your Inbox 📥 A Task Manager Powered by Simple Email Replies</title>
      <dc:creator>Luis Fernando Richter</dc:creator>
      <pubDate>Mon, 09 Jun 2025 02:45:00 +0000</pubDate>
      <link>https://dev.to/lfrichter/my-submission-for-the-postmark-challenge-i-turned-my-inbox-into-a-powerful-task-manager-2odd</link>
      <guid>https://dev.to/lfrichter/my-submission-for-the-postmark-challenge-i-turned-my-inbox-into-a-powerful-task-manager-2odd</guid>
      <description>&lt;p&gt;Hello everyone! This is my submission for the &lt;strong&gt;Postmark Challenge: Inbox Innovators&lt;/strong&gt; on DEV.to. I decided to tackle a common problem for many of us: tasks that originate from emails often force us to switch contexts, copy-pasting content into a separate to-do application.&lt;/p&gt;

&lt;p&gt;My solution? An application that transforms your email client into a fully-fledged, conversational task manager.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Core Idea: Email as an Interface
&lt;/h3&gt;

&lt;p&gt;Instead of just being a place where tasks arrive, what if the inbox could be the interface where you manage their entire lifecycle?&lt;/p&gt;

&lt;p&gt;My project allows a user to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Create a task&lt;/strong&gt; by sending a simple email.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Receive an instant confirmation&lt;/strong&gt; that creates a conversational thread.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Update, comment on, and complete the task&lt;/strong&gt; just by replying to that thread with simple commands.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This creates a seamless workflow, keeping the user right where they are, without ever needing to open another app.&lt;/p&gt;

&lt;h3&gt;
  
  
  How It Works: The Conversational Flow
&lt;/h3&gt;

&lt;p&gt;The magic happens through a combination of Postmark's Inbound and Outbound APIs and a command parser built in Laravel. The entire flow is conversational.&lt;/p&gt;

&lt;p&gt;Here is a sequence diagram illustrating the process:&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%2Fe5ubkmxgl7e2qt68w92b.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%2Fe5ubkmxgl7e2qt68w92b.png" alt="Sequence Diagram" width="800" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's see it in action with a simple story: updating a page on a website.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The First Email (Task Creation)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I send an email to the system's inbound address. The body contains a description of the task and some commands to set the priority and due date right away.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Subject:&lt;/strong&gt; &lt;code&gt;📄 Update 'About Us' page on the company website&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Body:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The 'About Us' page is outdated. Please update the text to reflect our new company values and add the latest team photos. The photo assets are in the shared drive.

#priority medium
&lt;/code&gt;&lt;/pre&gt;

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

&lt;p&gt;My application receives this, creates the task, sets the priority, and cleans the description.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The Reply (Adding a Comment)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After receiving the confirmation email, I can reply to it to add a comment or ask a question.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Subject:&lt;/strong&gt; &lt;code&gt;Re: [TASK-2] 📄 Update 'About Us' page on the company website&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Body:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The content team is ready to start, but they have a question first. 🤔

#comment Should we also update the individual team member bios, or just the main company description for now?
&lt;/code&gt;&lt;/pre&gt;

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

&lt;p&gt;The application receives this reply, finds the original task, and attaches the new comment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The Final Reply (Task Completion)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once the work is done, a final reply with the &lt;code&gt;#complete&lt;/code&gt; command is all that's needed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Subject:&lt;/strong&gt; &lt;code&gt;Re: [TASK-2] 📄 Update 'About Us' page on the company website&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Body:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Just confirmed with the director. For now, only update the main company description.

#comment The content team has confirmed the changes are now live on the site. Everything looks great. ✔️
#complete
&lt;/code&gt;&lt;/pre&gt;

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

&lt;p&gt;The task is now automatically marked as completed in the UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Tech Stack
&lt;/h3&gt;

&lt;p&gt;To bring this idea to life, I used the following technologies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; Laravel 12&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email Processing:&lt;/strong&gt; Postmark API (Inbound and Outbound)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; Livewire with Blade&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI &amp;amp; Icons:&lt;/strong&gt; Tailwind CSS &amp;amp; Blade Heroicons&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing:&lt;/strong&gt; Pest (PHP Testing Framework)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A Glimpse into the Implementation
&lt;/h3&gt;

&lt;p&gt;One of the core components is a &lt;code&gt;CommandParser&lt;/code&gt; service in Laravel. It uses a simple but powerful regex-based approach to find and process commands within the email body. This service is responsible for updating the task's attributes or creating related records, like comments.&lt;/p&gt;

&lt;p&gt;Another key piece was using Laravel's event system. By listening to the &lt;code&gt;MessageSent&lt;/code&gt; event, the application captures the unique &lt;code&gt;Message-ID&lt;/code&gt; of the outgoing confirmation email. This ID could be used in the future to build an even more robust system for threading replies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Live Demo in Action
&lt;/h3&gt;

&lt;p&gt;To demonstrate the application's flow in real-time, I recorded a short video showing the complete lifecycle of a task, from creation to completion, all managed via email.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/NDFgcH2X1ZI" rel="noopener noreferrer"&gt;youtu.be/NDFgcH2X1ZI&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;This project was a fantastic exercise in thinking about email not just as a destination, but as an interactive platform. By leveraging Postmark's powerful APIs, it's possible to build truly innovative and seamless workflows that meet users where they already are: their inbox.&lt;/p&gt;

&lt;p&gt;Thank you for the challenge!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Find the full source code on my GitHub repository:&lt;/strong&gt; &lt;a href="https://github.com/lfrichter/Interactive-email-management" rel="noopener noreferrer"&gt;Interactive-email-management&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>postmarkchallenge</category>
      <category>webdev</category>
      <category>api</category>
    </item>
  </channel>
</rss>
